Mass dump for remote work
This commit is contained in:
Thomas Hodnemyr 2023-08-03 14:50:04 +02:00
parent 9798cee411
commit c7310ca58c
4690 changed files with 368768 additions and 13726 deletions

7
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
"cSpell.words": [
"autocomp",
"disnake",
"sqlalchemy"
]
}

21
Neat Normal file
View File

@ -0,0 +1,21 @@
URL = 'https://www.google.com/'
IMAGE_1 = 'https://cdn.discordapp.com/embed/avatars/1.png'
IMAGE_2 = 'https://cdn.discordapp.com/embed/avatars/2.png'
# embeds must have the same url
# works with more up to 4(?) embeds on desktop, might not work at all on mobile
embed1 = discord.Embed(
title='TITLE 1',
description='DESCRIPTION 1',
url=URL # <<< same url as other embeds
)
embed1.set_image(url=IMAGE_1)
embed2 = discord.Embed(
title='TITLE 2',
description='DESCRIPTION 2',
url=URL # <<< same url as other embeds
)
embed2.set_image(url=IMAGE_2)
await channel.send(embeds=[embed1, embed2])

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,75 @@
from disnake.ext import commands
import disnake
from main import StronkBot
from loguru import logger
import httpx
from thefuzz import process
from datetime import datetime
class Relationship_Manager(commands.Cog):
def __init__(self,bot:StronkBot):
self.bot = bot
self.houses = ["House 1 - The Heavenly Ones","House 2 - High Castle","House 3 - The Dragons","House 4 - The Farmers","House 5 - The Navigators","House 6 - The Free Folk","House 7 - The Royals","House 8 - The Roses","House 9 - The Rams","House 10 - Fighters","House 11 - Heroes","House 12 - Stags","House 13 - Oak","House 14 - Beasts","House 15 - The Pure","House 16 - Lionheart","House 17 - The Insane","House 18 - Sinners","House 19 - The Double-Eagles","House 20 - Maidens",]
@commands.slash_command()
async def set_relationship(self,inter:disnake.ApplicationCommandInteraction,
target_type:str = commands.Param(choices=["House", "Player"]),
relation:str = commands.Param(choices=["Faction", "Allied", "Neutral", "Peace", "Enemy", "Rogue"]),
world:str = commands.Param(description="What world does this relation apply? Leave blank to affect all worlds", default = None),
target:str = commands.Param(description="Type the name of the target of this relation change"),
comment:str = commands.Param(default="",description="If you want you can add some info about this relationship for clarity. Might not be used anywhere")):
#Validate target name
if target_type == "Player":
async with httpx.AsyncClient() as client:
response = await client.get(f'http://login.strongholdkingdoms.com/ajaxphp/username_search.php?term={target}')
if target not in response.json(): return await inter.send(ephemeral=True, content=f"You submitted {target} this name does not seem valid. Make sure the name has the right capitalization. Or the player is banned")
await self.bot.database.players.update_one({"in_game_name": target},{"$set": {"in_game_name": target}},upsert=True)
if target_type == "House":
if target not in self.houses: return await inter.send(ephemeral=True,content=f"You submitted {target} this name does not seem valid. Make sure to pick from the list")
target = target.partition(" - ")[0]
document = {
"guild_id": inter.guild_id,
"world": world,
"target": target,
"type": target_type,
"state": relation,
"comment": comment,
"author": {
"discord_id" : inter.author.id,
"discord_name" : inter.author.display_name,
"date": datetime.now()
}
}
#Upsert the correct document to the relationship collection
await self.bot.database.relationships.update_one({"guild_id": inter.guild_id, "type": target_type, "target": target}, {"$set": document},upsert=True)
await inter.send(ephemeral=True,content=f"Done! Set {target} as {relation}!\nNote that this does not update adverts, any changes will be updated during their scheduled updates.")
@set_relationship.autocomplete("target")
async def autocomp_input(self, inter:disnake.ApplicationCommandInteraction,user_input:str):
if len(user_input) == 0: return []
target_type = inter.filled_options.get("target_type")
if target_type is None: return ["Please set a target type first"]
if target_type == "Player":
async with httpx.AsyncClient() as client:
response = await client.get(f'http://login.strongholdkingdoms.com/ajaxphp/username_search.php?term={user_input}')
return response.json()
if target_type == "House":
return [option[0] for option in process.extract(user_input,self.houses,limit=4)]
@set_relationship.autocomplete("world")
async def autocomp_world(self, inter:disnake.ApplicationCommandInteraction,user_input:str):
server_document = await self.bot.database.servers.find_one({"_id":inter.guild_id})
return server_document["worlds"].keys()
def setup(bot):
logger.info(f"{__name__} Loaded")
bot.add_cog(Relationship_Manager(bot))

View File

@ -1,13 +1,66 @@
from disnake.ext import commands
from PIL import Image
import disnake
from main import StronkBot
from loguru import logger
class Setup(commands.Cog):
typelist = ["liegelord","vm_tracker","diplomacy"]
def __init__(self,bot) -> None:
def __init__(self,bot:StronkBot):
self.bot = bot
self.worlds = []
self.advert_types = []
@commands.slash_command(description='Define an advert channel',default_member_permissions=disnake.Permissions(manage_guild=True))
async def create_advert(self,
@commands.slash_command(description="Assign a world to this server",default_member_permissions=disnake.Permissions(manage_guild=True))
async def set_server_world(self,
inter:disnake.ApplicationCommandInteraction,
advert_type:str = commands.Param(description='What type=',choices=typelist),
target: disnake.abc.GuildChannel = commands.Param(description='Channel override, optional')):
world:str,
api_key:str = None):
if not world in self.worlds:
await inter.response.send_message(content="Not found, use suggestions please",ephemeral=True)
return
world_document = await self.bot.database.worlds.find_one({"world_name": world})
if not world_document:
return await inter.response.send_message(ephemeral=True,content="Can't find the world, contact Strix please")
server_document = await self.bot.database.servers.find_one({"_id": inter.guild_id})
if not server_document:
new_document = {"_id": inter.guild_id,"server_name": inter.guild.name,"worlds":{world_document["world_name"]:api_key}}
result = await self.bot.database.servers.insert_one(new_document)
return await inter.response.send_message(ephemeral=True, content=f'Great! Server registered and added {world_document["world_name"]} to your server')
world_list = server_document.get("worlds")
if world_list and world_document["_id"] in world_list:
return await inter.response.send_message(ephemeral=True, content="This world is already registered on this world!")
await self.bot.database.servers.find_one_and_update({"_id": inter.guild_id},{"$set":{"worlds.{}".format(world_document["world_name"]):api_key}},upsert=True)
await inter.response.send_message(f"Done, added {world_document['world_name']}")
@set_server_world.autocomplete("world")
async def autocomp_worlds(self, inter:disnake.ApplicationCommandInteraction, user_input:str):
if len(self.worlds) == 0:
cursor = self.bot.database.worlds.find()
world_docs = await cursor.to_list(length=None)
self.worlds = [world["world_name"] for world in world_docs if not world["ended"]]
return [world for world in self.worlds if user_input.lower() in world.lower()][:25]
@commands.slash_command(description="Define one of your channels as an advert channel")
async def set_advert_channel(self, inter:disnake.ApplicationCommandInteraction, ad_type:str, channel:disnake.TextChannel):
if not ad_type in self.advert_types:
await inter.response.send_message(content="Not found, use suggestions please",ephemeral=True)
return
result = await self.bot.database.adverts.update_one({"guild_id": inter.guild_id}, {"$set":{"advert_type": ad_type, "channel_id": channel.id}}, upsert=True)
await inter.send(content=f"Ok, registered {channel.name} as a {ad_type}. The advert should appear shortly.")
#TODO: Trigger individual refresh of this advert.
@set_advert_channel.autocomplete("ad_type")
async def autocomp_worlds(self, inter:disnake.ApplicationCommandInteraction, user_input:str):
if len(self.advert_types) == 0:
results = await self.bot.database.config.find_one({"name":"advert_types"})
self.advert_types = results.get("advert_types")
return [ad_type for ad_type in self.advert_types if user_input.lower() in ad_type.lower()][:25]
def setup(bot):
logger.info(f"{__name__} Loaded")
bot.add_cog(Setup(bot))

65
cogs/shk_info_tasks.py Normal file
View File

@ -0,0 +1,65 @@
import aiohttp
import disnake
from disnake.ext import commands, tasks
from loguru import logger
import httpx
from datetime import datetime
class Shk_tasks(commands.Cog):
def __init__(self,bot):
self.bot = bot
self.getHouseData.start()
def cog_unload(self):
logger.info(f"{__name__} Unloaded")
self.getHouseData.cancel()
@tasks.loop(hours=2)
async def getHouseData(self) -> None:
#Collect all worlds we have access too.
await self.bot.wait_until_ready()
logger.info("Starting House Data Update")
filter_query = {"worlds": {"$exists": True}}
documents = await self.bot.database.servers.find(filter_query).to_list(None)
# Combine dictionaries into a collated list of worlds
collated_worlds = {}
for doc in documents:
worlds = doc.get("worlds")
collated_worlds.update(worlds)
upsert_operations = []
world:str
try:
async with aiohttp.ClientSession() as session:
for world,key in collated_worlds.items():
if key is None: continue
logger.info(f"Updating house info for {world}")
for house in range(1,21):
try:
async with session.get(f'https://shk.azure-api.net/shkinfo/v1/HouseActivity?world={world}&house={house}&Key={key}&subscription-key=ff2e578e119348ea8b48a2acd2f5a48d',timeout=20) as houseActivity:
for user in await houseActivity.json():
filter_query = {
"in_game_name": user["Username"],
"world": world,
"house": house
}
update_query = {
"$set": {
"timestamp": datetime.now()
}
}
await self.bot.database.players.update_one({"in_game_name": user["Username"]},{"$set": {"in_game_name": user["Username"]}},upsert=True)
await self.bot.database.house_history.update_one(filter_query, update_query, upsert=True)
except aiohttp.ServerTimeoutError:
logger.exception(f"Timeout when trying to fetch data for World {world} and house {house}")
logger.info(f"Finished {world} update")
except Exception as e:
logger.exception("Scan failed due to exception")
logger.info("Finished House Data update")
def setup(bot):
logger.info(f"{__name__} Loaded")
bot.add_cog(Shk_tasks(bot))

175
cogs/vm_tracker.py Normal file
View File

@ -0,0 +1,175 @@
from disnake.ext import commands, tasks
import disnake
from main import StronkBot
from loguru import logger
from datetime import datetime, timedelta
from embed_factory import vm_advert
import httpx
from thefuzz import process
class Vm_tracker(commands.Cog):
def __init__(self,bot:StronkBot):
self.bot = bot
self.update_vm_embeds.start()
def cog_unload(self):
self.update_vm_embeds.cancel()
@commands.slash_command(description="Report someone going in VM")
async def report_vm(self,inter:disnake.ApplicationCommandInteraction, in_game_name:str):
logger.info(f"{inter.application_command.name} used by {inter.author} using {inter.filled_options}")
inter.response.defer(ephemeral=True)
async with httpx.AsyncClient() as client:
response = await client.get(f'http://login.strongholdkingdoms.com/ajaxphp/username_search.php?term={in_game_name}')
if in_game_name not in response.json(): return await inter.send(content=f"You submitted {in_game_name} this name does not seem valid. Make sure the name has the right capitalization. Or the player is banned")
#See if this is a duplicate
check = await self.bot.database.vm_entries.find_one({"in_game_name": in_game_name,"guild_id": inter.guild_id, "finished": {"$exists" : False}})
if check is not None:
return await inter.send(content="Good news, this is already reported! :D")
await self.bot.database.vm_entries.insert_one(
{"guild_id": inter.guild_id, "in_game_name": in_game_name, "added": datetime.now()}
)
advert = await self.bot.database.adverts.find_one({"advert_type":"vm_tracker", "guild_id": inter.guild_id})
if advert is not None:
await self.update_adverts([advert])
await inter.send(content=f"Thank you! {in_game_name} has been registered")
@commands.slash_command(description="Edit a VM entry on this server")
async def edit_vm(self,inter:disnake.ApplicationCommandInteraction, in_game_name:str, action:str = commands.Param(choices=["Remove", "Adjust Start Time"], description="If you choose adjust time add the optional 'Value' argument"), value:int = commands.Param(default= 0 ,description="In hours how much do you want to adjust the start time. Negative numbers go forward in time")):
logger.info(f"{inter.application_command.name} used by {inter.author} using {inter.filled_options}")
# Get the list of players this server is allowed to edit.
filter = {
"added": {
"$gte": datetime(datetime.now().year - 1, 12, 15),
"$lte": datetime(datetime.now().year + 1, 1, 15)
},
"guild_id": inter.guild_id,
"finished": {"$exists" : False}
}
vm_entries = await self.bot.database.vm_entries.find(filter, {"_id": 0, "in_game_name": 1} ).to_list(length=None)
eligible_names = [entry["in_game_name"] for entry in vm_entries]
filter.update({"in_game_name": in_game_name})
if in_game_name not in eligible_names: return await inter.send(ephemeral=True, content=f"You submitted {in_game_name} this name does not seem valid. You can only edit entries submitted by your server")
if action == "Remove":
await self.bot.database.vm_entries.update_one(filter, {"$set": {"finished": datetime.now()}})
elif action == "Adjust Start Time":
await self.bot.database.vm_entries.update_one(filter, [{"$set": {"added": { "$add": ["$added", -value*3600000]}}}])
advert = await self.bot.database.adverts.find_one({"advert_type":"vm_tracker", "guild_id": inter.guild_id})
if advert is not None:
await self.update_adverts([advert])
await inter.response.send_message(ephemeral=True,content=f"Thank you! {in_game_name} has been edited")
@edit_vm.autocomplete("in_game_name")
async def autocomp_input(self, inter:disnake.ApplicationCommandInteraction,user_input:str):
if len(user_input) == 0: return []
filter = {
"added": {
"$gte": datetime(datetime.now().year - 1, 12, 15),
"$lte": datetime(datetime.now().year + 1, 1, 15)
},
"guild_id": inter.guild_id,
"finished": {"$exists" : False}
}
vm_entries = await self.bot.database.vm_entries.find(filter, {"_id": 0, "in_game_name": 1} ).to_list(length=None)
eligible_names = [entry["in_game_name"] for entry in vm_entries]
return [option[0] for option in process.extract(user_input,set(eligible_names),limit=4)]
@tasks.loop(hours=1)
async def update_vm_embeds(self) -> None:
await self.bot.wait_until_ready()
logger.info(f"---> Updating VM adverts")
#Check if any entries have expired
result = await self.bot.database.vm_entries.update_many({"added": {"$lt": datetime.now()-timedelta(days=15)}, "finished" : { "$exists" : False }},{"$set":{"finished": datetime.now()}})
adverts = await self.bot.database.adverts.find({"advert_type": "vm_tracker"}).to_list(length=None)
#TODO Enable some way to switch what world house colors should be pulled from. As servers might have more than one world listed.
await self.update_adverts(adverts)
async def update_adverts(self,adverts:list):
for advert in adverts:
#Make sure the guild is still present
target_guild = self.bot.get_guild(advert["guild_id"])
if not target_guild:
logger.error(f"Tried updating VM advert in {advert['guild_id']} but its not present in the bot")
continue
#TODO Note infraction for later cleanup if this repeats.
target_channel = target_guild.get_channel(advert["channel_id"])
if not target_channel:
logger.error(f"Tried updating VM advert in {target_guild.name} but the channel is not present in the guild")
continue
#TODO Note infraction, warn the server owner. Repeated failures will result in advert removal
#Collect what world(s) the guild is looking at
current_server_document = await self.bot.database.servers.find_one({"_id": advert["guild_id"]})
world_list:dict = current_server_document.get("worlds", None)
vm_entries = await self.collect_server_vms(guild_id=advert["guild_id"],all=True)
vm_entries = sorted(vm_entries, key=lambda x: x["added"])
#Get the relevant house affiliations if applicable
house_data = None
house_relations = None
if len(world_list) > 0:
house_data = await self.bot.database.house_history.find({"timestamp":{"$gte":datetime.now()- timedelta(hours=2)}, "in_game_name": {"$in":[entry["in_game_name"] for entry in vm_entries]}, "world":next(iter(world_list))}).to_list(length=None)
house_data = {doc["in_game_name"]: doc for doc in house_data}
house_relations = await self.bot.database.relationships.find({"guild_id": advert["guild_id"], "type": "House", "world": {"$in": [next(iter(world_list)),None]}}).to_list(length=None)
relations = {doc["target"]: doc["state"] for doc in house_relations}
player_relations = await self.bot.database.relationships.find({"guild_id": advert["guild_id"], "type": "Player", "world": {"$in": [next(iter(world_list)),None]}}).to_list(length=None)
relations.update({doc["target"]: doc["state"] for doc in player_relations})
embed = vm_advert.generate_embed(bot = self.bot, guild_id = advert["guild_id"],vm_entries=vm_entries,house_data=house_data,relations=relations)
target_message_id = advert.get("message_id", None)
if target_message_id is None:
sent_message = await target_channel.send(embed=embed)
#Add new message to advert for future updates
await self.bot.database.adverts.update_one({"guild_id":advert["guild_id"],"channel_id":advert["channel_id"]},{"$set": {"message_id":sent_message.id}})
continue
else:
target_message = await target_channel.fetch_message(target_message_id)
await target_message.edit(embed=embed,components=None)
async def collect_server_vms(self,guild_id:int, all=False):
from_date = datetime(datetime.now().year - 1, 12, 15)
to_date = datetime(datetime.now().year + 1, 1, 15)
# Build the filter for the query
filter_query = {
"added": {
"$gte": from_date,
"$lte": to_date
},
"guild_id": guild_id,
}
if not all:
filter_query.update({"finished": {"$exists" : False}})
return await self.bot.database.vm_entries.find(filter_query).to_list(length=None)
@commands.Cog.listener()
async def on_button_click(self, inter:disnake.MessageInteraction):
if "vm_tracker" not in inter.component.custom_id: return
logger.info(f"{inter.component.custom_id} used by {inter.author}")
await inter.response.defer(with_message=False)
await self.bot.database.vm
await self.bot.database.adverts.update_one({"advert_type":"vm_tracker", "guild_id": inter.guild_id}, [ { "$set": {"private": {"$not": "$private" } } } ] )
advert = await self.bot.database.adverts.find_one({"advert_type":"vm_tracker", "guild_id": inter.guild_id})
if advert is not None:
await self.update_adverts([advert])
def setup(bot):
logger.info(f"{__name__} Loaded")
bot.add_cog(Vm_tracker(bot))

89
cogs_dev/check_player.py Normal file
View File

@ -0,0 +1,89 @@
from disnake.ext import commands, tasks
import disnake
import db
import httpx
from datetime import datetime
from sqlalchemy import func
from loguru import logger
import sb_utils
import embed_factory.check_player
from main import StronkBot
class Check_Player(commands.Cog):
def __init__(self,bot):
self.bot:StronkBot = bot
@commands.slash_command(description="Look up information about a player")
async def check_player(self, inter:disnake.ApplicationCommandInteraction,player:str):
logger.info(f"{inter.application_command.name} used by {inter.author} using {inter.filled_options}")
#Get server specific shit
server_document = await self.bot.database.servers.find_one({"_id" : inter.guild_id})
server_worlds = list(server_document.get("worlds", {}).keys())
await inter.response.defer()
async with httpx.AsyncClient() as client:
#
#Check if player is banned
ban_response = await client.get(f'http://login.strongholdkingdoms.com/ajaxphp/username_search.php?term={player}')
#
#Collect world activity data
activity_response = await client.get(f'https://shk.azure-api.net/shkinfo/v1/UserActivity?world={server_worlds[0]}&username={player}&Key={server_document["worlds"][server_worlds[0]]}&subscription-key=ff2e578e119348ea8b48a2acd2f5a48d')
if activity_response.text == '01/Jan/0001 00:00:00':
activity_date = None
else:
activity_date = datetime.datetime.strptime(activity_response.text,'%d/%b/%Y %H:%M:%S')
shk_banned_data = ban_response.json()
if server_document is None: return await inter.send(ephemeral=True,content="Missing server setup, have you done the setup process?")
#Collect info about the player
if len(server_worlds) > 0:
#
#Collect house history
house_data = await self.bot.database.house_history.find({"in_game_name": player, "world": server_worlds[0]}).to_list(length=None)
#
#Collect Relationships with the server
target_list = [f"House {entry['house']}" for entry in house_data]
target_list.append(player)
relationships = await self.bot.database.relationships.find({ "$and" : [ { "$or" : [ { "world" : server_worlds[0] }, { "world" : { "$not" : { "$exists" : True } } }, { "world" : None } ] }, { "guild_id" : inter.guild_id }, { "target" : { "$in" : target_list } } ] }).to_list(length=None)
#
#Collect Intel data
intel = await self.bot.database.intel_screenshots.find({"in_game_name": player, "added_by.discord_guild_id": inter.guild_id}).to_list(length=None)
##
##Collect VM data
from_date = datetime(datetime.now().year - 1, 12, 15)
to_date = datetime(datetime.now().year + 1, 1, 15)
filter_query = {
"added": {
"$gte": from_date,
"$lte": to_date
},
"guild_id": inter.guild_id,
"in_game_name" : player
}
vm_entries = await self.bot.database.vm_entries.find(filter_query).to_list(length=None)
@check_player.autocomplete("player")
async def autocomp_input(self, inter:disnake.ApplicationCommandInteraction,user_input:str):
if len(user_input) == 0: return []
async with httpx.AsyncClient() as client:
response = await client.get(f'http://login.strongholdkingdoms.com/ajaxphp/username_search.php?term={user_input}')
return response.json()
@commands.Cog.listener()
async def on_message_interaction(self,inter:disnake.MessageInteraction):
pass
# States:
# 0 - Overview
# 1 - Castle Designs
# 2 - House History
# 3 - Bot Usage Stats
def generate_overview_embed_and_components(id:int):
pass
def setup(bot):
logger.info(f"{__name__} Loaded")
bot.add_cog(Check_Player(bot))

18
cogs_dev/template_cog.py Normal file
View File

@ -0,0 +1,18 @@
from disnake.ext import commands
import disnake
from main import StronkBot
from loguru import logger
class Vm_tracker(commands.Cog):
def __init__(self,bot:StronkBot):
self.bot = bot
def cog_unload(self):
logger.info(f"{__name__} Unloaded")
self.getHouseData.cancel()
def setup(bot):
logger.info(f"{__name__} Loaded")
bot.add_cog(Vm_tracker(bot))

11
cogs_dev/user_manager.py Normal file
View File

@ -0,0 +1,11 @@
from disnake.ext import commands
import disnake
import db
class User_Manager(commands.Cog):
@commands.Cog.listener() #Welcome Screen Listener
async def on_message_interaction(self,inter:disnake.MessageInteraction):
if not inter.component.custom_id.startswith("advert_welcome_"):
return
if inter.component.custom_id.partition("advert_welcome_")[2] == "social":
pass

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

22
cogs_old/ban_checker.py Normal file
View File

@ -0,0 +1,22 @@
from disnake.ext import commands
import disnake
import db
import httpx
from datetime import datetime
from loguru import logger
import sb_utils
import sb_emojis
class PTest(commands.Cog):
def __init__(self,bot):
self.bot = bot
@commands.slash_command()
async def test(self,inter: disnake.ApplicationCommandInteraction):
user = await inter.bot.fetch_user(inter.author.id)
await inter.send(user.banner)
def setup(bot):
logger.info(f"{__name__} Loaded")
bot.add_cog(PTest(bot))

195
cogs_old/calculate_time.py Normal file
View File

@ -0,0 +1,195 @@
from ast import match_case
from urllib import response
from disnake.ext import commands
import disnake
import db
import requests
import re
from datetime import datetime, timedelta
from loguru import logger
class Calculate_Time(commands.Cog):
def __init__(self,bot):
self.bot = bot
@commands.slash_command(description="Calculate your times like a pro")
async def calculate_time(self,inter:disnake.ApplicationCommandInteraction):
db.log_interaction(inter,f"Issued calculate_time")
logger.info(f"{inter.author.display_name} Issued calculate time command")
await inter.response.send_modal(timesModal())
@commands.Cog.listener()
async def on_message_interaction(self,inter:disnake.MessageInteraction):
if 'calc_time' in inter.component.custom_id:
db.log_interaction(inter,f"Interracted with {inter.component.custom_id} on {inter.message.id}")
match(inter.component.custom_id):
case 'calc_time_delete':
await inter.response.defer()
await inter.message.delete()
case 'calc_time_add':
await inter.response.send_modal(timesModal(inter=inter))
case 'calc_time_new':
await inter.response.send_modal(timesModal())
case 'calc_time_show_all':
await inter.response.defer()
await update_message(inter=inter,display_all_multipliers=True)
case 'calc_time_multi':
await inter.response.defer()
with db.get_session()() as session:
time_data_list = session.query(db.Time_Data).filter(db.Time_Data.message_id == inter.message.id).all()
print(len(time_data_list))
for t in time_data_list:
t.multiplier = int(inter.values[0][1])
session.commit()
await update_message(inter=inter,time_data_list=time_data_list)
def calc_times_from_modal(time_string,multi:int):
#Split times
timeList = re.split(',| ',time_string)
times = []
try:
for num,time_ in enumerate(timeList):
if time_ == '':
continue
#Try and idiotproof some edge cases
if time_.startswith((':',';','.')):
temp_time = time_[1:]
else:
temp_time = time_
modifier = 0
if '|' in time_:
temp = time_.split('|')
name = temp[0]
if name.startswith('>') or name.lower() == 'breaker':
#Breaker
if name.startswith('>'): name = name[1:]
modifier = 10
temp_time = temp[1]
else:
name = f'{num+1}'
time_components = [int(s) for s in re.split('\:|\;|\.',temp_time)]
time_components.reverse()
seconds = 0
for n,t in enumerate(time_components):
seconds += t*60**n
times.append({'name': name, 'seconds': seconds, 'multiplier': multi, 'modifier': modifier})
return times
except:
return []
class timesModal(disnake.ui.Modal):
def __init__(self,multi=4,inter=None):
self.inter = inter
self.id = None
if inter != None:
self.id = inter.message.id
components = [
disnake.ui.TextInput(
label="name|hh:mm:ss or hh:mm:ss can add multiple",
placeholder="Times to convert",
custom_id="times",
required=True,
),
disnake.ui.TextInput(
label="Time multiplier",
placeholder="4",
custom_id="multi_value",
style= disnake.TextInputStyle.short,
max_length=1,
value = multi,
),
]
super().__init__(
title="Calculate attack times",
custom_id="submit_calc",
components=components
)
async def callback(self, interaction: disnake.ModalInteraction):
if self.id:
await interaction.response.defer(ephemeral=True)
else:
await interaction.response.defer()
times = interaction.text_values['times']
multi = int(interaction.text_values['multi_value'])
#do tests on times:
times_list = calc_times_from_modal(times,multi)
if times_list:
#Store relevant info
time_data_list = []
if not self.id:
message:disnake.Message = await interaction.followup.send("If you see this for long something went wrong")
message_id = self.id or message.id
with db.get_session()() as session:
user:db.User = session.query(db.User).filter(db.User.discord_id == interaction.author.id).first()
for t in times_list:
time_data_list.append(db.Time_Data(message_id=message_id, user_id = user.id, **t))
session.add_all(time_data_list)
session.commit()
if self.id != None:
await update_message(inter=interaction,override_inter=self.inter)
else:
await update_message(inter=interaction,time_data_list=time_data_list)
else:
await interaction.followup.send("Something went wrong.")
return
return
async def update_message(inter:disnake.ApplicationCommandInteraction,time_data_list=None,display_all_multipliers=False,override_inter=None):
if not time_data_list:
with db.get_session()() as session:
time_data_list = session.query(db.Time_Data).filter(db.Time_Data.message_id == inter.message.id).all()
if not time_data_list:
await inter.followup.edit("No time data found")
return
time_data_list.sort(key=lambda y: y.seconds)
time_data_list.reverse()
#Components
components = [[],[]]
components[0].append(disnake.ui.Select(placeholder="Change multiplier",options=["x2","x3","x4","x5","x6"],custom_id="calc_time_multi"))
if len(time_data_list) == 1:
components[1].append(disnake.ui.Button(label="Show All Multipliers", custom_id="calc_time_show_all"))
components[1].append( disnake.ui.Button(label="Add time",custom_id="calc_time_add",style=disnake.ButtonStyle.green))
components[1].append( disnake.ui.Button(label="Create New",custom_id="calc_time_new",style=disnake.ButtonStyle.green))
components[1].append( disnake.ui.Button(label="Delete Message",custom_id="calc_time_delete",style=disnake.ButtonStyle.danger))
#Embed
embed = disnake.Embed()
embed.title = "Time Converter"
embed.set_author(name='Storm Brigade',icon_url='https://i.imgur.com/Opk3fCq.png')
embed.description = "Modifies any times to the desired card level\n Useful for prepping times from monk speeds"
before_string = ""
after_string = ""
data: db.Time_Data
if not display_all_multipliers:
for data in time_data_list:
emoji = '<:Captain:947543163608924181>'
if data.modifier > 0:
emoji = '<:Breaker:947543175025819709>'
before_string += f"{emoji}**{data.name}**:{timedelta(seconds=data.seconds)} -**x{data.multiplier}**->\n"
after_string += f"{timedelta(seconds=int(data.seconds/data.multiplier))}\n"
else:
for m in range(2,7):
emoji = '<:Captain:947543163608924181>'
before_string += f"{emoji}**{time_data_list[0].name}**:{timedelta(seconds=time_data_list[0].seconds)} -**x{m}**->\n"
after_string += f"{timedelta(seconds=int(time_data_list[0].seconds/m))}\n"
embed.add_field(name="Original",value=before_string)
embed.add_field(name="Modified",value=after_string)
if override_inter != None:
await inter.followup.send("Added to the list, this message is required for now, sorry. Just dismiss it :)")
await override_inter.edit_original_message(content="",embed=embed,components=components)
else:
await inter.edit_original_message(content="",embed=embed,components=components)
def setup(bot):
bot.add_cog(Calculate_Time(bot))

68
cogs_old/check_house.py Normal file
View File

@ -0,0 +1,68 @@
from disnake.ext import commands
import disnake
import db
import httpx
from datetime import datetime
from loguru import logger
import sb_utils
import sb_emojis
class Check_House(commands.Cog):
def __init__(self,bot):
self.bot = bot
@commands.slash_command(description="Look up Activity about a house")
async def check_house(self, inter:disnake.ApplicationCommandInteraction,house=commands.Param(description="Which house?",choices=[str(x) for x in range(1,21)]),ban_check=commands.Param(description="Also check for bans? This will take a while, slowed down to avoid FF banning the bot",choices=["Yes","No"],default="No"),world:str = ""):
logger.info(f"{inter.application_command.name} used by {inter.author} using {inter.filled_options}")
await inter.response.defer(with_message=True,ephemeral=True)
async with httpx.AsyncClient() as client:
result = await client.get(f"https://shk.azure-api.net/shkinfo/v1/HouseActivity?world=World%202&house={house}&Key=5E78CFC8-1FFA-4036-8427-D94ED6E1A45B&subscription-key=ff2e578e119348ea8b48a2acd2f5a48d")
house_players_activity = {}
for player in result.json():
banned = None
vm = None
if ban_check == "Yes":
banned_result = await sb_utils.check_banned_player(session,client,player["Username"])
banned = banned_result["banned"]
house_players_activity[player["Username"]] = (max(datetime.strptime(player["MaxPersonTime"],"%Y-%m-%dT%H:%M:%S"),datetime.strptime(player["MaxTraderTime"],"%Y-%m-%dT%H:%M:%S")),(banned,vm))
#Done with Httpx session
house_result = session.query(db.House).filter(db.House.id == house).one_or_none()
#Done with db session
sorted_players = sorted(house_players_activity.items(), key=lambda x: x[1][0]) # Sort by least active
embed = disnake.Embed(title=f"{house_result.emoji} House {house} Activity Report {house_result.emoji}")
embed.description = f"Generated at: {disnake.utils.format_dt(disnake.utils.utcnow(),'D')}\nOnly tracks map activity, so if they're online and not scouting/trading etc this won't reflect that"
embed.set_thumbnail(file=disnake.File(f"resources\house_sprites\{house}.png"))
player_entries = [(f"**{player}** - {data[0].strftime('%d/%b/%Y %H:%M:%S')}\n",data[1]) for player,data in sorted_players]
temp_value = ""
for player_tuple in player_entries:
if player_tuple[1][0] != None: #Banned has been set
if player_tuple[1][0]:
banned_emoji = sb_emojis.embed_fillers["banned"]
else:
banned_emoji = sb_emojis.embed_fillers["banned_before"]
else:
banned_emoji = sb_emojis.embed_fillers["no_data"]
if player_tuple[1][1] != None: #VM has been set
if player_tuple[1][1]:
vm_emoji = sb_emojis.embed_fillers["vm_active"]
else:
vm_emoji = sb_emojis.embed_fillers["vm_logged"]
else:
vm_emoji = sb_emojis.embed_fillers["no_data"]
temp = f"{vm_emoji}{banned_emoji} {player_tuple[0]}"
if "01/Jan/0001 00:00:00" in player_tuple[0]:
temp = temp.replace("01/Jan/0001 00:00:00","**INACTIVE/RESET**")
if len(temp_value)+len(temp) > 1024:
if len(embed)+len(temp_value) > 6000:
break
embed.add_field(name='\u200b',value=temp_value,inline=False)
temp_value = ''
temp_value += temp
embed.add_field(name='\u200b',value=temp_value,inline=False)
embed.colour = disnake.Color(int(house_result.color,0))
await inter.send("Here you go, blame discord for this dumb message...",delete_after=1)
await inter.channel.send(embed=embed)
def setup(bot):
bot.add_cog(Check_House(bot))

24
cogs_old/parish_intel.py Normal file
View File

@ -0,0 +1,24 @@
from disnake.ext import commands
import disnake
import db
import httpx
from datetime import datetime
from loguru import logger
import sb_utils
import sb_emojis
import csv
from io import StringIO
class Parish_Intel(commands.Cog):
def __init__(self,bot):
self.bot = bot
@commands.slash_command()
async def moon(self,inter):
asd = disnake.Embed(title="KEK0")
asd.set_image(file=disnake.File("0.png"))
def setup(bot):
logger.info(f"{__name__} Loaded")
bot.add_cog(Parish_Intel(bot))

66
cogs_old/player_intel.py Normal file
View File

@ -0,0 +1,66 @@
from disnake.ext import commands
import disnake
import db
import httpx
from datetime import datetime
from loguru import logger
import sb_utils
import sb_emojis
import csv
from io import StringIO
from uuid import uuid4
from embed_factory import castle_design_confirmation
from os import makedirs
class Player_Intel(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.slash_command()
async def upload_castle(self, inter:disnake.ApplicationCommandInteraction,player: str, design: disnake.Attachment):
if not design.content_type.startswith('image'):
return await inter.send("You can only use this with pictures",ephemeral=True)
async with httpx.AsyncClient() as client:
response = await client.get(
f"http://login.strongholdkingdoms.com/ajaxphp/username_search.php?term={player}"
)
response = response.json()
if len(response) != 1:
return await inter.send(f"Sorry, {player} could not be found or theres too many results, check spelling")
await inter.response.defer(ephemeral=True)
with db.get_session()() as session:
player:db.Player = db.get_or_create(session,db.Player,player_name = player)[0]
server:db.Server = db.get_or_create(session,db.Server,server_name = inter.guild.name,discord_guild_id = inter.guild.id)[0]
file_name, ext = design.filename.split('.')
path = f"castle_designs//{player.id}"
makedirs(path)
await design.save(f"{path}//{uuid4()}.{ext}")
castle_design = db.Player_Castle_Designs(path=f"{path}//{uuid4()}.{ext}", player_id=player.id, server_id=server.id)
session.add(castle_design)
session.commit()
target_advert = session.query(db.Advert).filter(db.Advert.server_id == server.id).filter(db.Advert.advert_type_id == 6).first()
if not target_advert:
await inter.send("There's not a castle_design channel for this server, so posting confirmation in this channel")
await inter.channel.send(embed=castle_design_confirmation.generate_embed(design,player.player_name,inter.author.display_name),components=castle_design_confirmation.generate_buttons(inter.author.id))
@upload_castle.autocomplete("player")
async def autocomp_input(
self, inter: disnake.ApplicationCommandInteraction, user_input: str
):
if len(user_input) == 0:
return []
async with httpx.AsyncClient() as client:
response = await client.get(
f"http://login.strongholdkingdoms.com/ajaxphp/username_search.php?term={user_input}"
)
return response.json()
def setup(bot):
logger.info(f"{__name__} Loaded")
bot.add_cog(Player_Intel(bot))

368
db.py
View File

@ -1,145 +1,197 @@
#! .\sbsheriff\scripts\python.exe
import sqlalchemy as sqla
import json
from time import time
import disnake
from requests import session
from sqlalchemy import Integer, create_engine, String, Column, ForeignKey,Table,Boolean,BigInteger,SmallInteger,DateTime,func
from sqlalchemy.orm import declarative_base, relationship, scoped_session, sessionmaker
import sqlite3
from dotenv import load_dotenv
from os import getenv
engine = sqla.create_engine('postgresql://strix:unnipus1213@192.168.1.2:5432/sbdb')
load_dotenv(".env", override=True)
engine = create_engine(getenv("DB_CON"),pool_pre_ping=True)
Base = declarative_base()
Session = sessionmaker(engine)
class World(Base):
__tablename__ = 'world'
id = sqla.Column(sqla.Integer, primary_key=True)
short_name = sqla.Column(sqla.String(50))
world_name = sqla.Column(sqla.String(50))
shk_id = sqla.Column(sqla.Integer)
age = sqla.Column(sqla.Integer)
ended = sqla.Column(sqla.Boolean)
hoh_scraped = sqla.Column(sqla.Boolean)
id = Column(Integer, primary_key=True)
short_name = Column(String(50))
world_name = Column(String(50))
shk_id = Column(Integer)
age = Column(Integer)
ended = Column(Boolean)
hoh_scraped = Column(Boolean)
servers = relationship('Server',back_populates='worlds') #Checked
hoh_entries = relationship('Hall_Of_Heroes',back_populates='world') #Checked
house_histories = relationship('House_History',back_populates='world') #Checked
parishes = relationship("Parish_Data",back_populates='world') #Checked
class Player(Base):
__tablename__ = 'player'
id = sqla.Column(sqla.Integer, primary_key=True)
player_name = sqla.Column(sqla.String(100))
user_id = sqla.Column(sqla.Integer,sqla.ForeignKey('user.id'))
id = Column(Integer, primary_key=True)
player_name = Column(String(100))
user_id = Column(Integer,ForeignKey('user.id'))
user = relationship('User',back_populates='player') #Checked
vm_entries = relationship('Vm_Entry',back_populates='player') #Checked
hoh_entries = relationship("Hall_Of_Heroes",back_populates="player") #Checked
house_history = relationship("House_History",back_populates="player") #Checked
castle_designs = relationship("Player_Castle_Designs",back_populates="player") #Checked
checks = relationship('Check_Player_Data',back_populates='player')
world_data = relationship("WorldPlayerData",back_populates="player")#C
server_user = sqla.Table(
class PlayerBan(Base):
__tablename__ = "player_ban"
id = Column(Integer,primary_key=True)
player_id = Column(Integer,ForeignKey("player.id"))
date_added = Column(DateTime,server_default=func.now())
last_check = Column(DateTime,server_default=func.now())
unbanned = Column(Boolean,default=False)
permanent = Column(Boolean,default=False)
class BanTrackedHouse(Base):
__tablename__ = "ban_tracked_house"
id = Column(Integer,primary_key=True)
house_id = Column(Integer,ForeignKey("house.id"))
tracked_by_server_id = Column(Integer,ForeignKey("server.id"))
class BanTrackedPlayer(Base):
__tablename__ = "ban_tracked_player"
id = Column(Integer,primary_key=True)
player_id = Column(Integer,ForeignKey("player.id"))
tracked_by_server_id = Column(Integer,ForeignKey("server.id"))
server_user = Table(
"association",
Base.metadata,
sqla.Column("server_id",sqla.ForeignKey("server.id")),
sqla.Column("user_id",sqla.ForeignKey("user.id")),
Column("server_id",ForeignKey("server.id")),
Column("user_id",ForeignKey("user.id")),
)
class WorldPlayerData(Base):
__tablename__ = 'world_player_data'
id = Column(Integer,primary_key=True)
player_id = Column(Integer,ForeignKey("player.id"))
world_id = Column(Integer,ForeignKey("world.id"))
cp_rank = Column(Integer)
player = relationship("Player",back_populates="world_data")#C
class Server(Base):
__tablename__ = 'server'
id = sqla.Column(sqla.Integer, primary_key=True)
server_name = sqla.Column(sqla.Integer)
discord_guild_id = sqla.Column(sqla.BigInteger,unique=True)
world_id = sqla.Column(sqla.Integer,sqla.ForeignKey('world.id'))
id = Column(Integer, primary_key=True)
server_name = Column(String)
discord_guild_id = Column(BigInteger,unique=True)
world_id = Column(Integer,ForeignKey('world.id'))
api_key = Column(String)
worlds = relationship("World",back_populates="servers") #Checked
users = relationship("User",secondary=server_user,back_populates='servers') #Checked
roles = relationship("Server_Roles", back_populates="server")
adverts = relationship("Advert",back_populates="server")
class User(Base):
__tablename__ = 'user'
id = sqla.Column(sqla.Integer, primary_key=True)
discord_id = sqla.Column(sqla.BigInteger,unique=True)
display_name = sqla.Column(sqla.String(50))
id = Column(Integer, primary_key=True)
discord_id = Column(BigInteger,unique=True)
display_name = Column(String(50))
servers = relationship("Server",secondary=server_user,back_populates='users') #Checked
#Parent in user prefferences relationship
user_prefference = relationship("User_Prefference",back_populates="user",uselist=False) #Checked
#Parent in user preferences relationship
user_preference = relationship("User_Preference",back_populates="user",uselist=False) #Checked
#Parent in user player relationship
player = relationship('Player',back_populates='user',uselist=False) #Checked
class User_Prefference(Base):
__tablename__ = 'user_prefference'
id = sqla.Column(sqla.Integer,primary_key=True)
preffered_pikes = sqla.Column(sqla.Integer)
preffered_archers = sqla.Column(sqla.Integer)
user_id = sqla.Column(sqla.Integer,sqla.ForeignKey('user.id'))
user = relationship('User',back_populates='user_prefference') #Checked
parish_actions = relationship("Parish_Action",back_populates='user')
time_data = relationship("Time_Data",back_populates='user')
class User_Preference(Base):
__tablename__ = 'user_preference'
id = Column(Integer,primary_key=True)
preferred_pikes = Column(Integer)
preferred_archers = Column(Integer)
user_id = Column(Integer,ForeignKey('user.id'))
user = relationship('User',back_populates='user_preference') #Checked
class Advert_Type(Base):
__tablename__ = 'advert_type'
id = sqla.Column(sqla.Integer, primary_key=True)
advert_name = sqla.Column(sqla.String(50))
id = Column(Integer, primary_key=True)
advert_name = Column(String(50))
adverts = relationship("Advert",back_populates="advert_type") #Checked
class Advert(Base):
__tablename__ = 'advert'
advert_id = sqla.Column(sqla.Integer, primary_key=True)
advert_type_id = sqla.Column(sqla.SmallInteger, sqla.ForeignKey("advert_type.id"))
channel_id = sqla.Column(sqla.BigInteger)
message_id = sqla.Column(sqla.BigInteger)
advert_id = Column(Integer, primary_key=True)
advert_type_id = Column(SmallInteger, ForeignKey("advert_type.id"))
server_id = Column(Integer,ForeignKey('server.id'))
channel_id = Column(BigInteger)
message_id = Column(BigInteger)
advert_type = relationship("Advert_Type",back_populates="adverts") #Checked
server = relationship("Server",back_populates="adverts")
class Vm_Entry(Base):
__tablename__ = 'vm_entry'
id = sqla.Column(sqla.Integer, primary_key=True)
added_by_user_id = sqla.Column(sqla.Integer, sqla.ForeignKey("user.id"))
player_id = sqla.Column(sqla.Integer, sqla.ForeignKey("player.id"))
server_id = sqla.Column(sqla.Integer, sqla.ForeignKey("server.id"))
time_added = sqla.Column(sqla.Time)
time_ended = sqla.Column(sqla.Time,nullable=True)
id = Column(Integer, primary_key=True)
added_by_user_id = Column(Integer, ForeignKey("user.id"))
player_id = Column(Integer, ForeignKey("player.id"))
server_id = Column(Integer, ForeignKey("server.id"))
time_added = Column(DateTime,server_default=func.now())
time_ended = Column(DateTime,nullable=True)
player = relationship("Player",back_populates="vm_entries") #Checked
class House(Base):
__tablename__ = 'house'
id = sqla.Column(sqla.Integer, primary_key=True)
color = sqla.Column(sqla.String)
emoji = sqla.Column(sqla.String)
id = Column(Integer, primary_key=True)
name = Column(String)
color = Column(String)
emoji = Column(String)
relationships = relationship("House_Relationship",back_populates="house")
class Relationship_State(Base):
__tablename__ = 'relationship_state'
id = sqla.Column(sqla.Integer, primary_key=True)
relationship_name = sqla.Column(sqla.String(50))
alignment = sqla.Column(sqla.Integer)
id = Column(Integer, primary_key=True)
relationship_name = Column(String(50))
alignment = Column(Integer)
emoji = Column(String)
house_relations = relationship('House_Relationship',back_populates='relationship_state') #Checked
player_relations = relationship('Player_Relationship',back_populates='relationship_state')#Checked
class House_Relationship(Base):
__tablename__ = 'house_relationship'
id = sqla.Column(sqla.Integer, primary_key=True)
id = Column(Integer, primary_key=True)
server_id = sqla.Column(sqla.Integer, sqla.ForeignKey("server.id"))
house_id = sqla.Column(sqla.Integer, sqla.ForeignKey("house.id"))
server_id = Column(Integer, ForeignKey("server.id"))
house_id = Column(Integer, ForeignKey("house.id"))
house = relationship("House",back_populates="relationships") #Checked
relationship_state_id = sqla.Column(sqla.Integer, sqla.ForeignKey("relationship_state.id"))
relationship_state_id = Column(Integer, ForeignKey("relationship_state.id"))
relationship_state = relationship("Relationship_State",back_populates="house_relations") #Checked
class Player_Relationship(Base):
__tablename__ = 'player_relationship'
id = sqla.Column(sqla.Integer, primary_key=True)
note = sqla.Column(sqla.String(100),nullable=True)
id = Column(Integer, primary_key=True)
note = Column(String(100),nullable=True)
server_id = sqla.Column(sqla.Integer, sqla.ForeignKey("server.id"))
player_id = sqla.Column(sqla.Integer, sqla.ForeignKey("player.id"))
relationship_state_id = sqla.Column(sqla.Integer, sqla.ForeignKey("relationship_state.id"))
server_id = Column(Integer, ForeignKey("server.id"))
player_id = Column(Integer, ForeignKey("player.id"))
relationship_state_id = Column(Integer, ForeignKey("relationship_state.id"))
relationship_state = relationship('Relationship_State',back_populates='player_relations')#Checked
class Hoh_Rank(Base):
__tablename__ = 'hoh_rank'
id = sqla.Column(sqla.Integer, primary_key=True)
rank_name = sqla.Column(sqla.String(50))
id = Column(Integer, primary_key=True)
rank_name = Column(String(50))
hoh_entries = relationship("Hall_Of_Heroes",back_populates="rank") #Checked
class Hall_Of_Heroes(Base):
__tablename__ = 'hall_of_heroes'
id = sqla.Column(sqla.Integer,primary_key=True)
player_id = sqla.Column(sqla.Integer,sqla.ForeignKey('player.id'))
hoh_rank_id = sqla.Column(sqla.Integer,sqla.ForeignKey('hoh_rank.id'))
world_id = sqla.Column(sqla.Integer,sqla.ForeignKey('world.id'))
id = Column(Integer,primary_key=True)
player_id = Column(Integer,ForeignKey('player.id'))
hoh_rank_id = Column(Integer,ForeignKey('hoh_rank.id'))
world_id = Column(Integer,ForeignKey('world.id'))
#Parent in player hoh relationship
player = relationship('Player',back_populates='hoh_entries') #Checked
@ -148,39 +200,191 @@ class Hall_Of_Heroes(Base):
class Player_Castle_Designs(Base):
__tablename__ = "player_castle_designs"
id = sqla.Column(sqla.Integer,primary_key=True)
path = sqla.Column(sqla.String)
player_id = sqla.Column(sqla.Integer,sqla.ForeignKey("player.id"))
server_id = sqla.Column(sqla.Integer,sqla.ForeignKey("server.id"))
id = Column(Integer,primary_key=True)
path = Column(String)
player_id = Column(Integer,ForeignKey("player.id"))
server_id = Column(Integer,ForeignKey("server.id"))
validated = Column(Boolean,default=False)
player = relationship("Player", back_populates="castle_designs") #Checked
server = relationship("Server") #Checked
class House_History(Base):
__tablename__ = 'house_history'
id = sqla.Column(sqla.Integer,primary_key=True)
date = sqla.Column(sqla.Date)
id = Column(Integer,primary_key=True)
date = Column(DateTime)
player_id = sqla.Column(sqla.Integer,sqla.ForeignKey("player.id"))
world_id = sqla.Column(sqla.Integer,sqla.ForeignKey("world.id"))
house_id = sqla.Column(sqla.Integer,sqla.ForeignKey("house.id"))
player_id = Column(Integer,ForeignKey("player.id"))
world_id = Column(Integer,ForeignKey("world.id"))
house_id = Column(Integer,ForeignKey("house.id"))
player = relationship("Player",back_populates='house_history') #Checked
world = relationship("World",back_populates='house_histories') #Checked
house = relationship("House") #Checked
class Liegelord_Requests(Base):
__tablename__ = 'liegelord_requests'
id = sqla.Column(sqla.Integer,primary_key=True)
village_id = sqla.Column(sqla.SmallInteger)
confirm_message_id = sqla.Column(sqla.BigInteger)
id = Column(Integer,primary_key=True)
village_id = Column(SmallInteger)
confirm_message_id = Column(BigInteger)
server_id = sqla.Column(sqla.Integer,sqla.ForeignKey("server.id"))
request_user_id = sqla.Column(sqla.Integer,sqla.ForeignKey('user.id'))
fulfilled_user_id = sqla.Column(sqla.Integer,sqla.ForeignKey('user.id'))
server_id = Column(Integer,ForeignKey("server.id"))
request_user_id = Column(Integer,ForeignKey('user.id'))
fulfilled_user_id = Column(Integer,ForeignKey('user.id'))
server = relationship("Server") #Checked
request_user = relationship("User",foreign_keys=[request_user_id])
fulfilled_user= relationship("User",foreign_keys=[fulfilled_user_id])
def create_session():
session = scoped_session(sessionmaker(bind=engine))
return session
class Parish_Data(Base):
__tablename__ = 'parish_data'
id = Column(Integer,primary_key=True)
parish_id = Column(Integer)
parish_name = Column(String)
world_id = Column(Integer,ForeignKey('world.id'))
world = relationship("World",back_populates='parishes') #Checked
actions = relationship("Parish_Action",back_populates='parish') #Checked
class Parish_Action(Base):
__tablename__ = 'parish_action'
id = Column(Integer,primary_key=True)
parish_id = Column(Integer,ForeignKey('parish_data.id'))
performed_by_user_id = Column(Integer,ForeignKey('user.id'))
performed_at = Column(DateTime,server_default=func.now())
building_id = Column(Integer,ForeignKey('parish_building.id'))
parish = relationship("Parish_Data",back_populates = 'actions') #Checked
building = relationship("Parish_Building",back_populates='actions') #Checked
user = relationship("User",back_populates='parish_actions') #Checked
class Parish_Building(Base):
__tablename__ = 'parish_building'
id = Column(Integer,primary_key=True)
name = Column(String)
actions = relationship("Parish_Action",back_populates='building') #checked
class User_Interaction(Base):
__tablename__ = "user_interaction"
id = Column(Integer,primary_key=True)
date = Column(DateTime,server_default=func.now())
action = Column(String)
user_id = Column(Integer,ForeignKey("user.id"))
server_id = Column(Integer,ForeignKey("server.id"))
class Time_Data(Base):
__tablename__ = 'time_data'
id = Column(Integer,primary_key = True)
message_id = Column(BigInteger)
name = Column(String)
seconds = Column(Integer)
multiplier = Column(Integer)
modifier = Column(Integer)
user_id = Column(Integer,ForeignKey('user.id'))
user = relationship("User",back_populates='time_data')
class Check_Player_Data(Base):
__tablename__ = 'check_player_data'
id = Column(Integer,primary_key = True)
player_id = Column(Integer,ForeignKey('player.id'))
player = relationship('Player',back_populates='checks')
class AI(Base):
__tablename__ = 'ai'
id = Column(Integer, primary_key=True)
name = Column(String)
class AI_Castle(Base):
__tablename__ = 'ai_castle'
id = Column(Integer, primary_key=True)
ai_id = Column(Integer, ForeignKey('ai.id'))
ai_level = Column(Integer)
archers = Column(Integer)
pikemen = Column(Integer)
catapults = Column(Integer)
swordmen = Column(Integer)
captains = Column(Integer)
parish_compatible = Column(Boolean)
img_path = Column(String)
class Role_Type(Base):
__tablename__ = 'role_type'
id = Column(Integer, primary_key=True)
name = Column(String)
class Server_Roles(Base):
__tablename__ = 'server_roles'
id = Column(Integer, primary_key=True)
server_id = Column(Integer, ForeignKey('server.id'))
role_type_id = Column(Integer, ForeignKey('role_type.id'))
discord_role_id = Column(BigInteger)
server = relationship("Server",back_populates="roles")
def get_session():
return Session
def log_interaction(inter:disnake.ApplicationCommandInteraction,action:str):
with Session() as session:
#Get or Create User
user = session.query(User).filter(User.discord_id==inter.author.id).first()
server = session.query(Server).filter(Server.discord_guild_id==inter.guild_id).first()
if user == None:
#Create user object and assosiate with server
print(f"adding new user to database -> {inter.author.display_name}")
user = User(display_name=inter.author.display_name,discord_id=inter.author.id)
session.add(user)
session.commit()
if not server in user.servers:
print(f"associating new user to server -> {inter.author.display_name} -> {inter.guild.name}")
user.servers.append(server)
interaction = User_Interaction(user_id=user.id,server_id=server.id,action=action)
session.add(interaction)
session.commit()
def add_players_from_search(json:dict):
with Session() as session:
for entry in json:
player = session.query(Player).filter(Player.player_name==entry).first()
if player == None:
player = Player(player_name=entry)
session.add(player)
session.commit()
def get_or_create(session, model, defaults=None, **kwargs):
instance = session.query(model).filter_by(**kwargs).one_or_none()
if instance:
return instance, False
else:
kwargs |= defaults or {}
instance = model(**kwargs)
try:
session.add(instance)
session.commit()
except Exception:
session.rollback()
instance = session.query(model).filter_by(**kwargs).one()
return instance, False
else:
return instance, True
def get_adverts():
with Session() as session:
return session.query(Advert_Type).all()
def get_advert_type_by_name(name: str):
with Session() as session:
advert_id = session.query(Advert_Type).filter_by(advert_name=name).one_or_none()
if advert_id:
return advert_id.id
else:
return None
def get_ai_castles(ai_id: int):
with Session() as session:
return session.query(AI_Castle).filter(AI_Castle.ai_id == ai_id).all()
#Base.metadata.create_all(bind=engine)

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,13 @@
import disnake
from embed_factory import embeds
def generate_embed(attachment:disnake.Attachment,player_name,author_name):
embed = embeds.base_embed()
embed.set_image(attachment.to_file())
embed.description = f"{author_name} submits this design for {player_name}"
return embed
def generate_buttons(author_id):
confirm = disnake.ui.Button(label="Confirm Submission",emoji="",style=disnake.ButtonStyle.green,custom_id=f"cdc-confirm-{author_id}")
delete = disnake.ui.Button(label="Delete",emoji="",style=disnake.ButtonStyle.red,custom_id="cdc-delete")
return [confirm,delete]

View File

@ -0,0 +1,6 @@
import disnake
import sqlalchemy.orm
class Overview(disnake.Embed):
def __init__(self, session:sqlalchemy.orm.session, target_player_id:int):
super().__init__(title=f"{2+2}")

19
embed_factory/embeds.py Normal file
View File

@ -0,0 +1,19 @@
import disnake
import httpx
class base_embed(disnake.Embed):
def __init__(self):
super().__init__()
self.set_footer(text="Provided by Storm Brigade",icon_url='https://i.imgur.com/Opk3fCq.png')
#self.set_author(name='Storm Brigade',icon_url='https://i.imgur.com/Opk3fCq.png')
self.set_thumbnail(file=disnake.File("resources\StormBrigade_White.png"))
async def add_player_shield(self,in_game_name:str):
async with httpx.AsyncClient() as client:
response = await client.get(f"https://login.strongholdkingdoms.com/ajaxphp/get_shield_url.php?username={in_game_name}&transparent=1")
response_json = response.json()
if response_json.get("url", None) is not None:
self.set_thumbnail(url=response_json.get("url"))
return self

View File

@ -0,0 +1,87 @@
import disnake
from embed_factory import embeds
import sb_emojis
from datetime import datetime, timedelta
from main import StronkBot
def generate_embed(bot:StronkBot, guild_id:int, vm_entries:dict,house_data:dict,relations:dict):
embed = embeds.base_embed()
embed.title = f"VM tracker"
embed.description = f"Players currently on VM\n Use </report_vm:{bot.get_global_command_named('report_vm').id}> to add more"
vm_names = [entry["in_game_name"] for entry in vm_entries]
if len(vm_entries) == 0: return embed
entry_list = []
for entry in vm_entries:
if entry.get("finished"): continue
vm_num = '<:SecondVm:1020804212399018157>' if vm_names.count(entry["in_game_name"]) > 1 else '<:no_data:1020809240648101978>'
house_emoji = '<:no_data:1020809240648101978>' if house_data.get(entry["in_game_name"]) is None else sb_emojis.houseEmojis.get(house_data.get(entry["in_game_name"]).get("house"))
#Check relationships
relation_state = None
if house_data.get(entry["in_game_name"]) is not None:
relation_state = relations.get(f"House {house_data.get(entry['in_game_name']).get('house')}")
if relation_state is None: relation_state = relations.get(entry["in_game_name"])
relationship_emoji = '<:no_data:1020809240648101978>' if relation_state is None else sb_emojis.relationshipEmojis.get(relation_state) or '<:no_data:1020809240648101978>'
entry_list.append( f"{relationship_emoji}{house_emoji}{vm_num}{entry['in_game_name']}:{disnake.utils.format_dt(entry.get('added')+ timedelta(days=15), style='R')}\n")
temp_value = ''
for vm_entry in entry_list:
if len(temp_value)+len(vm_entry) > 1024:
if len(embed)+len(temp_value) > 6000:
print("embed is going to be too large lol")
break
embed.add_field(name='\u200b',value=temp_value,inline=False)
temp_value = ''
temp_value += vm_entry
embed.add_field(name='\u200b',value=temp_value,inline=False)
return embed
def generate_components():
return [disnake.ui.Button(label="Remove VM", emoji="", custom_id="vm_tracker.spawn_remove")]
def vm_advert(gID = None):
embed = disnake.Embed(title="VM tracker",description = "Players currently on VM")
embed.set_author(name='Storm Brigade',icon_url='https://i.imgur.com/Opk3fCq.png')
if gID == None:
return embed
#Cleanup expired vm's
exired_vms = helpers.sql_get('SELECT name,added FROM vm_entries WHERE gID = {gID} AND added < unixepoch("now","-15 days") AND finished IS NULL'.format(gID=gID))
vm_length = 1296000
if len(exired_vms) > 0:
for vm in exired_vms:
helpers.sql_set("UPDATE vm_entries SET finished = ? WHERE gID = ? AND name = ? AND added = ?",(vm[1]+vm_length,gID,vm[0],vm[1]))
#print(exired_vms)
from_date = int(datetime.datetime.fromisoformat("{YYYY}-12-15".format(YYYY=datetime.date.today().year-1)).timestamp())
to_date = int(datetime.datetime.fromisoformat("{YYYY}-01-15".format(YYYY=datetime.date.today().year+1)).timestamp())
#print("SELECT vm_entries.name,vm_entries.added,house.house FROM vm_entries INNER JOIN house ON LOWER(vm_entries.name) = LOWER(house.username) WHERE vm_entries.added BETWEEN {start} AND {end} AND vm_entries.finished IS NULL".format(start=from_date,end=to_date))
query_result = helpers.sql_get("SELECT vm_entries.name,vm_entries.added,house.house FROM vm_entries LEFT JOIN house ON LOWER(vm_entries.name) = LOWER(house.username) AND house.date > unixepoch('now','-6 hours') WHERE vm_entries.added BETWEEN {start} AND {end} AND vm_entries.finished IS NULL ORDER BY added ASC".format(start=from_date,end=to_date),True)
house_json = json.loads(helpers.sql_get("SELECT relationships FROM guild WHERE gID = {gID}".format(gID = gID))[0][0])
if len(query_result) > 0:
vm_entries = []
for entry in query_result:
vm_num = '<:no_data:1020809240648101978>'
vm_info = helpers.sql_get(f"SELECT added FROM vm_entries WHERE LOWER(name) = LOWER('{entry['name']}') AND added BETWEEN {from_date} AND {to_date}")
if len(vm_info) > 1:
vm_num = '<:SecondVm:1020804212399018157>'
house_emoji = '<:no_data:1020809240648101978>'
relationship_emoji = '<:no_data:1020809240648101978>'
if str(entry['house']) in house_json.keys():
relationship_emoji = botOptions.relationshipEmojis[house_json[str(entry['house'])]]
if entry['house'] != None:
house_emoji = botOptions.houseEmojis[entry['house']]
vm_entries.append( "{relationship}{house}{num}{name}:<t:{time_remaining}:R>\n".format(relationship= relationship_emoji,num=vm_num,house=house_emoji,name=entry['name'],time_remaining=entry['added']+vm_length))
temp_value = ''
for vm_entry in vm_entries:
if len(temp_value)+len(vm_entry) > 1024:
if len(embed)+len(temp_value) > 6000:
print("embed is going to be too large lol")
break
embed.add_field(name='\u200b',value=temp_value,inline=False)
temp_value = ''
temp_value += vm_entry
embed.add_field(name='\u200b',value=temp_value,inline=False)
#print(len(embed))
return embed

87
house_history_migrate.py Normal file
View File

@ -0,0 +1,87 @@
from pymongo import MongoClient
import sqlite3
import json
from datetime import datetime
import requests
# Connect to SQLite
sqlite_conn = sqlite3.connect('sbsheriff.sqlite')
sqlite_conn.row_factory = sqlite3.Row
sqlite_cursor = sqlite_conn.cursor()
# Connect to MongoDB
mongo_client = MongoClient('mongodb://sheriff:unnipus1213@192.168.1.109:27017/?retryWrites=true&serverSelectionTimeoutMS=5000&connectTimeoutMS=10000&authSource=stormbrigade&authMechanism=SCRAM-SHA-256')
mongo_db = mongo_client['stormbrigade']
mongo_collection = mongo_db['intel_screenshots']
# Fetch data from SQLite table
sqlite_cursor.execute("SELECT gID, name, castle_designs, attack_designs FROM players")
rows = sqlite_cursor.fetchall()
# Iterate over the rows and migrate data to MongoDB
for row in rows:
username = row['name']
guild_id = row['gID']
castle_design_json = row['castle_designs']
attack_design_json = row['attack_designs']
# Convert house_history JSON to Python dictionary
castle_dict = json.loads(castle_design_json)
attack_dict = json.loads(attack_design_json)
#print(castle_dict)
# Iterate over house_history elements and upsert to MongoDB
player_doc = mongo_db.players.find_one(filter={"in_game_name": {"$regex": f"^{username}$", "$options": "i"}})
if player_doc is None:
player_doc = {}
r = requests.get(f'http://login.strongholdkingdoms.com/ajaxphp/username_search.php?term={username}').json()
if len(r) > 0:
player_doc["in_game_name"] = r[0]
else:
print(username, len(castle_dict))
continue
#print(player_doc)
for filename in castle_dict.keys():
filter_query = {
"in_game_name": player_doc["in_game_name"],
"added_by" : {
"added_by_discord_id": 0,
"added_by_discord_name": "Old Submission",
"added_by_discord_server_id": 947398173805133834,
},
"type": "castle",
"filename": filename
}
update_query = {
"$set": {
"filename": filename
}
}
mongo_collection.update_one(filter_query, update_query, upsert=True)
for filename in attack_dict.keys():
filter_query = {
"in_game_name": player_doc["in_game_name"],
"added_by" : {
"added_by_discord_id": 0,
"added_by_discord_name": "Old Submission",
"added_by_discord_server_id": 947398173805133834,
},
"type": "attack",
"filename": filename
}
update_query = {
"$set": {
"filename": filename
}
}
mongo_collection.update_one(filter_query, update_query, upsert=True)
# Perform the upsert operation
# Close connections
sqlite_cursor.close()
sqlite_conn.close()
mongo_client.close()

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Some files were not shown because too many files have changed in this diff Show More