mirror of
https://github.com/NovaOSS/nova-cord.git
synced 2024-11-25 18:43:57 +01:00
Simple user management
This commit is contained in:
parent
cce6cc5152
commit
e8bc01fbf5
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
||||||
|
*.log
|
||||||
|
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
|
|
47
cord/accounts.py
Normal file
47
cord/accounts.py
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
"""Account system functionality."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
|
||||||
|
import embedder
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
async def request_user_by_discord_id(discord_id):
|
||||||
|
return requests.get(
|
||||||
|
url=f'https://api.nova-oss.com/users?discord_id={discord_id}',
|
||||||
|
timeout=3,
|
||||||
|
headers={
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': os.getenv('CORE_API_KEY')
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
async def get_account(interaction):
|
||||||
|
try:
|
||||||
|
get_response = await request_user_by_discord_id(interaction.user.id)
|
||||||
|
|
||||||
|
except Exception as exc:
|
||||||
|
await embedder.error(interaction, """Sorry,
|
||||||
|
there was an error while checking if you have an account.
|
||||||
|
Please report this issue to the staff!""", ephemeral=True)
|
||||||
|
raise exc
|
||||||
|
|
||||||
|
if get_response.status_code == 404:
|
||||||
|
return await embedder.error(interaction, """You
|
||||||
|
don't have an account yet!""", ephemeral=True)
|
||||||
|
|
||||||
|
await embedder.info(interaction, f"""**Your account**
|
||||||
|
This is all we have stored about your API account in our database.
|
||||||
|
Feel free to request a removal of your account by contacting the staff.
|
||||||
|
|
||||||
|
||```json
|
||||||
|
{json.dumps(get_response.json(), indent=4)}
|
||||||
|
```||
|
||||||
|
(Click to reveal)
|
||||||
|
|
||||||
|
Learn more about how to use our API at **https://nova-oss.com**.
|
||||||
|
""", ephemeral=True)
|
|
@ -1,18 +1,31 @@
|
||||||
import random
|
|
||||||
import embedder
|
import embedder
|
||||||
|
from nextcord import DMChannel
|
||||||
|
|
||||||
async def process(message):
|
async def process(message):
|
||||||
if message.content == '/key':
|
text = message.content
|
||||||
responses = [
|
|
||||||
'https://media.tenor.com/t9f91LQWsM4AAAAS/breaking-bad-funny.gif',
|
|
||||||
'NPC detected, command rejected.',
|
|
||||||
'https://images-ext-1.discordapp.net/external/DXc3r4PyRR3m_4AzevpxWhfFtavdcMeDpZqFj3Ig4hc/https/media.tenor.com/b7swbvaVKhUAAAPo/seriously-laugh.mp4',
|
|
||||||
'there👏is👏no👏/key👏command👏',
|
|
||||||
'https://i.imgflip.com/7tuhc6.jpg'
|
|
||||||
]
|
|
||||||
|
|
||||||
await message.reply(random.choice(responses))
|
# IGNORE BOTS
|
||||||
await message.channel.send('Jokes aside - the project is still under development. There\'s no **`/key`** command.')
|
if message.author.bot:
|
||||||
|
return
|
||||||
|
|
||||||
if message.content.startswith('/') and ('commands' not in message.channel.name) and (not message.author.guild_permissions.manage_messages):
|
# IGNORE DM CHANNELS
|
||||||
await embedder.warn(message, 'Please only run commands in `/commands`.')
|
if isinstance(message.channel, DMChannel):
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'N0V4x0SS' in text or 'T3BlbkFJ' in text:
|
||||||
|
await embedder.warn(message, f'{message.author.mention}, I think you sent an *OpenAI* or *NovaAI* key in here, which could lead to other users accessing your API account without your knowledge. Be very careful with API credentials!', delete_after=15)
|
||||||
|
await message.delete()
|
||||||
|
|
||||||
|
# COMMANDS: WRONG CHANNEL
|
||||||
|
commands_allowed = ('commands' in message.channel.name) or (message.author.guild_permissions.manage_messages)
|
||||||
|
|
||||||
|
if text.startswith('/') and not commands_allowed:
|
||||||
|
await embedder.error(message, f'{message.author.mention}, plesae __only__ run commands in <#1133103276871667722>.', delete_after=10)
|
||||||
|
await message.delete()
|
||||||
|
return
|
||||||
|
|
||||||
|
# COMMANDS: NOT RAN CORRECTLY
|
||||||
|
if text.startswith('/') and len(text) > 2:
|
||||||
|
await embedder.warn(message, """Need help running commands? Check out
|
||||||
|
**https://nova-oss.com/novacord**!""", delete_after=10)
|
||||||
|
return
|
||||||
|
|
32
cord/bot.py
32
cord/bot.py
|
@ -1,13 +1,14 @@
|
||||||
# This example requires the 'members' and 'message_content' privileged intents to function.
|
"""Bot base."""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import nextcord
|
import nextcord
|
||||||
|
|
||||||
import system
|
|
||||||
import chatbot
|
import chatbot
|
||||||
import embedder
|
import embedder
|
||||||
import autochat
|
import autochat
|
||||||
|
import accounts
|
||||||
import community
|
import community
|
||||||
|
import credential_manager
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from nextcord.ext import commands
|
from nextcord.ext import commands
|
||||||
|
@ -15,9 +16,11 @@ from nextcord import SlashOption
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
|
guild_ids = [int(guild_id) for guild_id in os.getenv('DISCORD_GUILD_IDS').split()]
|
||||||
|
|
||||||
bot = commands.Bot(
|
bot = commands.Bot(
|
||||||
intents=nextcord.Intents.all(),
|
intents=nextcord.Intents.all(),
|
||||||
default_guild_ids=[int(guild_id) for guild_id in os.getenv('DISCORD_GUILD_IDS').split()] # so slash commands work
|
default_guild_ids=guild_ids # so slash commands work
|
||||||
)
|
)
|
||||||
|
|
||||||
@bot.event
|
@bot.event
|
||||||
|
@ -33,29 +36,34 @@ async def on_message(message):
|
||||||
await autochat.process(message)
|
await autochat.process(message)
|
||||||
await bot.process_commands(message)
|
await bot.process_commands(message)
|
||||||
|
|
||||||
@bot.slash_command(description='Chat with AI')
|
# @bot.slash_command(description='Chat with AI')
|
||||||
async def chat(interaction: nextcord.Interaction,
|
# async def chat(interaction: nextcord.Interaction,
|
||||||
prompt: str = SlashOption(description='AI Prompt', required=True)
|
# prompt: str = SlashOption(description='AI Prompt', required=True)
|
||||||
):
|
# ):
|
||||||
await chatbot.respond(interaction, prompt)
|
# await chatbot.respond(interaction, prompt)
|
||||||
|
|
||||||
@bot.slash_command(description='Sets your DMs up, so you can write the bot.')
|
@bot.slash_command(description='Sets your DMs up, so you can write the bot.')
|
||||||
async def dm(interaction: nextcord.Interaction):
|
async def dm_setup(interaction: nextcord.Interaction):
|
||||||
try:
|
try:
|
||||||
await interaction.user.create_dm()
|
await interaction.user.create_dm()
|
||||||
await embedder.info(interaction.user.dm_channel, 'Hello!')
|
await embedder.info(interaction.user.dm_channel, 'Hello!')
|
||||||
except nextcord.Forbidden:
|
except nextcord.Forbidden:
|
||||||
await embedder.error(interaction, text="""Please open this server\'s options,
|
await embedder.error(interaction, text="""Please open this server\'s options,
|
||||||
go to `Privacy Settings` and enable `Direct Messages` as well as `Message Requests`.""")
|
go to `Privacy Settings` and enable `Direct Messages` as well as `Message Requests`.""")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
await embedder.ok(interaction, 'Great, DMs are set up successfully!')
|
await embedder.ok(interaction, 'Great, DMs are set up successfully!')
|
||||||
|
|
||||||
@bot.slash_command(description='Get your secret NovaAI API credentials.')
|
@bot.slash_command(description='Create your account and get your API key.')
|
||||||
async def credentials(interaction: nextcord.Interaction):
|
async def credentials(interaction: nextcord.Interaction):
|
||||||
return await system.get_credentials(interaction)
|
return await credential_manager.get_credentials(interaction)
|
||||||
|
|
||||||
@bot.slash_command(description='Leaderboard.')
|
@bot.slash_command(description='Leaderboard.')
|
||||||
async def leaderboard(interaction: nextcord.Interaction):
|
async def leaderboard(interaction: nextcord.Interaction):
|
||||||
await community.leaderboard(interaction)
|
return await community.leaderboard(interaction)
|
||||||
|
|
||||||
|
@bot.slash_command(description='Get info and stats about your NovaAI API account.')
|
||||||
|
async def account(interaction: nextcord.Interaction):
|
||||||
|
return await accounts.get_account(interaction)
|
||||||
|
|
||||||
bot.run(os.getenv('DISCORD_TOKEN'))
|
bot.run(os.getenv('DISCORD_TOKEN'))
|
||||||
|
|
73
cord/credential_manager.py
Normal file
73
cord/credential_manager.py
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
"""Account system functionality."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
|
||||||
|
import embedder
|
||||||
|
import accounts
|
||||||
|
import tos_verification
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
|
||||||
|
async def get_credentials(interaction):
|
||||||
|
for _ in range(2):
|
||||||
|
try:
|
||||||
|
get_response = await accounts.request_user_by_discord_id(interaction.user.id)
|
||||||
|
except Exception as exc:
|
||||||
|
await embedder.error(interaction, """Sorry,
|
||||||
|
there was an issue while checking if you already have an account.
|
||||||
|
Please report this issue to the staff!""", ephemeral=True)
|
||||||
|
raise exc
|
||||||
|
|
||||||
|
if get_response.status_code == 200: # user exists
|
||||||
|
break
|
||||||
|
|
||||||
|
# NEW USER
|
||||||
|
read_tos = await tos_verification.verify(interaction)
|
||||||
|
|
||||||
|
if not read_tos:
|
||||||
|
await interaction.delete_original_message()
|
||||||
|
return
|
||||||
|
|
||||||
|
# CREATE USER
|
||||||
|
get_response = requests.post(
|
||||||
|
url='https://api.nova-oss.com/users',
|
||||||
|
timeout=3,
|
||||||
|
headers={
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': os.getenv('CORE_API_KEY')
|
||||||
|
},
|
||||||
|
json={
|
||||||
|
'discord_id': interaction.user.id
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
get_response.raise_for_status()
|
||||||
|
|
||||||
|
except Exception as exc:
|
||||||
|
await embedder.error(interaction, """Sorry,
|
||||||
|
your account could not be created. Please report this issue to the staff!""", ephemeral=True)
|
||||||
|
|
||||||
|
raise exc
|
||||||
|
|
||||||
|
else:
|
||||||
|
await embedder.ok(interaction, f"""Welcome to NovaAI, {interaction.user.mention}!
|
||||||
|
Your account was created successfully.""", ephemeral=True)
|
||||||
|
|
||||||
|
api_key = get_response.json()['api_key']
|
||||||
|
|
||||||
|
await embedder.info(interaction, f"""This is your **secret** API key.
|
||||||
|
Don't paste it on untrusted websites, apps or programs.
|
||||||
|
Store it securely using a `.env` file in the environment variables
|
||||||
|
or use a secure password manager like *KeePass*, *ProtonPass* or *Bitwarden*.
|
||||||
|
We reserve the right to __disable your API key at any time__ if you violate our terms of service.
|
||||||
|
If you accept the terms of service and privacy policy, feel free to use the following API key:
|
||||||
|
|
||||||
|
## ||`{api_key}`||
|
||||||
|
|
||||||
|
Learn more about how to use our API at **https://nova-oss.com**.
|
||||||
|
""", ephemeral=True)
|
|
@ -9,7 +9,8 @@ async def send(
|
||||||
text: str,
|
text: str,
|
||||||
content: str = '',
|
content: str = '',
|
||||||
ephemeral: bool = False,
|
ephemeral: bool = False,
|
||||||
color: nextcord.Color = nextcord.Color.blue()
|
color: nextcord.Color = nextcord.Color.blue(),
|
||||||
|
**kwargs
|
||||||
):
|
):
|
||||||
edit = False
|
edit = False
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ async def send(
|
||||||
|
|
||||||
end = ''
|
end = ''
|
||||||
|
|
||||||
if milliseconds > 10000: # https://youtu.be/-5wpm-gesOY
|
if milliseconds > 5000: # https://youtu.be/-5wpm-gesOY
|
||||||
end = f' in {milliseconds}ms'
|
end = f' in {milliseconds}ms'
|
||||||
|
|
||||||
embed.set_footer(text=f'Powered by NovaAI{end}', icon_url='https://i.ibb.co/LDyFcSh/fav-blurple.png')
|
embed.set_footer(text=f'Powered by NovaAI{end}', icon_url='https://i.ibb.co/LDyFcSh/fav-blurple.png')
|
||||||
|
@ -36,19 +37,19 @@ async def send(
|
||||||
|
|
||||||
interaction_type = Union[nextcord.Interaction, nextcord.InteractionResponse]
|
interaction_type = Union[nextcord.Interaction, nextcord.InteractionResponse]
|
||||||
|
|
||||||
# these checks are done so this function is easy as fuck to use
|
# these checks are done so this function is easy to use
|
||||||
|
|
||||||
if edit:
|
if edit:
|
||||||
return await ctx.edit(embed=embed, content=content)
|
return await ctx.edit(embed=embed, content=content, **kwargs)
|
||||||
|
|
||||||
if isinstance(ctx, nextcord.Message):
|
if isinstance(ctx, nextcord.Message):
|
||||||
response = await ctx.reply(embed=embed, content=content)
|
response = await ctx.reply(embed=embed, content=content, **kwargs)
|
||||||
|
|
||||||
elif isinstance(ctx, interaction_type):
|
elif isinstance(ctx, interaction_type):
|
||||||
response = await ctx.send(embed=embed, ephemeral=ephemeral, content=content)
|
response = await ctx.send(embed=embed, ephemeral=ephemeral, content=content, **kwargs)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
response = await ctx.send(embed=embed, content=content)
|
response = await ctx.send(embed=embed, content=content, **kwargs)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
import secrets
|
|
||||||
|
|
||||||
async def create(user):
|
|
||||||
return 'nv-' + secrets.token_urlsafe(32)
|
|
|
@ -1,65 +0,0 @@
|
||||||
import os
|
|
||||||
import asyncio
|
|
||||||
import requests
|
|
||||||
|
|
||||||
import keys
|
|
||||||
import embedder
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv()
|
|
||||||
|
|
||||||
async def get_credentials(interaction):
|
|
||||||
try:
|
|
||||||
resp = requests.post(
|
|
||||||
url='https://nova-oss.com/api/tos-verification',
|
|
||||||
timeout=5,
|
|
||||||
headers={'Content-Type': 'application/json', 'Authorization': os.getenv('TOS_VERIFICATION_KEY')}
|
|
||||||
).json()
|
|
||||||
except Exception as exc:
|
|
||||||
await embedder.error(interaction, """Sorry, the API server for the verification system is not functioning,
|
|
||||||
which means you can\'t create a new key right now. Please report this issue to the staff!""")
|
|
||||||
raise exc
|
|
||||||
|
|
||||||
tos_code = resp['code']
|
|
||||||
tos_emoji = resp['emoji']
|
|
||||||
|
|
||||||
tos_message = await embedder.warn(interaction, f"""# THIS IS JUST A DEMO/EXAMPLE!
|
|
||||||
# THE KEY WON'T WORK!
|
|
||||||
# THE SYSTEM ISN'T READY YET.
|
|
||||||
# DON'T SAVE THE KEY!!!
|
|
||||||
You have to read the privacy policy and terms of service first.
|
|
||||||
In the latter, there is a hidden emoji which you'll have to send (NOT react!) in here.
|
|
||||||
|
|
||||||
https://nova-oss.com/legal/privacy
|
|
||||||
https://nova-oss.com/legal/terms?verify={tos_code}
|
|
||||||
|
|
||||||
I know it's annoying, but it really helps combat spam bots and abuse.
|
|
||||||
|
|
||||||
This message will be deleted and your code will run out **after about 10 minutes**
|
|
||||||
if you don't pass the verification, but **feel free to run this command again** at any time.
|
|
||||||
""", ephemeral=True)
|
|
||||||
|
|
||||||
def check(message): return interaction.user.id == message.author.id and message.content == tos_emoji
|
|
||||||
|
|
||||||
try:
|
|
||||||
answer = await interaction.client.wait_for('message', timeout=666, check=check)
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
await tos_message.delete()
|
|
||||||
requests.delete(
|
|
||||||
url=f'https://nova-oss.com/api/tos-verification/{tos_code}',
|
|
||||||
timeout=5,
|
|
||||||
headers={'Content-Type': 'application/json', 'Authorization': os.getenv('TOS_VERIFICATION_KEY')}
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
|
||||||
await answer.delete()
|
|
||||||
api_key = await keys.create(interaction.user)
|
|
||||||
await embedder.ok(interaction, f"""This is your **secret** API key. Don't paste it on untrusted websites, apps or programs.
|
|
||||||
Store it securely using a `.env` file in the environment variables or use a secure password manager like *KeePass*, *ProtonPass* or *Bitwarden*.
|
|
||||||
We reserve the right to __disable your API key at any time__ if you violate our terms of service.
|
|
||||||
If you accept the terms of service and privacy policy, feel free to use the following API key:
|
|
||||||
|
|
||||||
## ||`{api_key}`||
|
|
||||||
|
|
||||||
""", ephemeral=True)
|
|
75
cord/tos_verification.py
Normal file
75
cord/tos_verification.py
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
"""The module for the Terms of Service verification system."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import asyncio
|
||||||
|
import requests
|
||||||
|
|
||||||
|
import embedder
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
async def verify(interaction) -> bool:
|
||||||
|
try:
|
||||||
|
resp = requests.post(
|
||||||
|
url='https://nova-oss.com/api/tos-verification',
|
||||||
|
timeout=5,
|
||||||
|
headers={
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': os.getenv('TOS_VERIFICATION_KEY')
|
||||||
|
}
|
||||||
|
).json()
|
||||||
|
except Exception as exc:
|
||||||
|
await embedder.error(interaction, """Sorry,
|
||||||
|
the API server for the verification system is not functioning,
|
||||||
|
which means you can\'t create a new key right now. Please report this issue to the staff!""")
|
||||||
|
raise exc
|
||||||
|
|
||||||
|
success = False
|
||||||
|
tos_code = resp['code']
|
||||||
|
tos_emoji = resp['emoji']
|
||||||
|
|
||||||
|
tos_message = await embedder.warn(interaction, f"""
|
||||||
|
You have to read the privacy policy and terms of service first.
|
||||||
|
In the latter, there is a hidden emoji which you'll have to __send__ (NOT react!) in here.
|
||||||
|
|
||||||
|
https://nova-oss.com/legal/privacy
|
||||||
|
https://nova-oss.com/legal/terms?verify={tos_code}
|
||||||
|
|
||||||
|
I know it's annoying, but it really helps combat spam bots and abuse.
|
||||||
|
|
||||||
|
This message will be deleted and your code will run out **after 10 minutes**
|
||||||
|
if you don't pass the verification, but **feel free to run this command again** at any time.
|
||||||
|
""", ephemeral=True)
|
||||||
|
|
||||||
|
def check(message):
|
||||||
|
correct_user = interaction.user.id == message.author.id
|
||||||
|
return correct_user and message.content == tos_emoji
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
received_answer = await interaction.client.wait_for('message', timeout=600, check=check)
|
||||||
|
await received_answer.delete()
|
||||||
|
|
||||||
|
if received_answer.content == tos_emoji:
|
||||||
|
break
|
||||||
|
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
await tos_message.delete()
|
||||||
|
|
||||||
|
else:
|
||||||
|
success = True
|
||||||
|
|
||||||
|
finally:
|
||||||
|
await tos_message.delete()
|
||||||
|
requests.delete(
|
||||||
|
url=f'https://nova-oss.com/api/tos-verification/{tos_code}',
|
||||||
|
timeout=5,
|
||||||
|
headers={
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': os.getenv('TOS_VERIFICATION_KEY')
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return success
|
Loading…
Reference in a new issue