I just deploy a python app in a free Heroku server. This python app provides a telegram bot to me. I want the bot to modify the userconfig.json which is in the same directory with main.py. When I test my bot in my local machine, it works well, the userconfig.json can be modified, but when app deploys on Heroku, it can't modify the file. After sending the modify order, there is no change on my userconfig.json. How can I solve this problem?
Below is the member method which modifies the json file
def modify_token(self, new_token):
self.tokenArray[0] = new_token
token_update = [{'token': self.tokenArray[0]}]
try:
with open("./userconfig.json", 'w') as config:
json.dump(token_update, config)
except Exception as e:
return False
return True
And I use these codes to ask telegram bot to modify the file
def modify(update: Update, context: CallbackContext):
# print(context)
print(context.args)
try:
user_cake.modify_token(context.args[0])
except Exception as e:
err_res = str(e)
context.bot.send_message(chat_id=update.effective_chat.id, text="An error occurred:" + err_res)
else:
context.bot.send_message(chat_id=update.effective_chat.id, text="Your new token is: " + user_cake.tokenArray[0])
Related
so I have just started getting interested in creating discord bots for my own server and mostly for fun, so I'm a a bit of a beginner in that, and this time I'm trying to create a discord bot that logs movies I have watched with my friends and also let's me search through the list of movies, delete a movie or if i just want to list the movies, and I'm trying to use davinci-003 model from the openai API to extract the movie detail that I have added, in case i give it an incomplete movie name so it would complete it for me, or so it would add the movie year and extra details about the movie I'm trying to add, at least that was my intention.
however first of all the very first issue is my bot doesn't show any status when i run it (i.e say watching a movie in the status of the bot), and also none of the / commands work on discord, they all return "The application did not respond" on discord and I get this error in the terminal where the code is running:
when I use /add moviename
Task exception was never retrieved
future: <Task finished name='Task-19' coro=<add() done, defined at /usr/local/lib/python3.10/dist-packages/interactions/client/models/command.py:930> exception=TypeError("add() missing 1 required positional argument: 'movie_details'")>
Traceback (most recent call last):
File "/usr/local/lib/python3.10/dist-packages/interactions/client/models/command.py", line 970, in wrapper
raise e
File "/usr/local/lib/python3.10/dist-packages/interactions/client/models/command.py", line 939, in wrapper
return await coro(ctx, *args, **kwargs)
TypeError: add() missing 1 required positional argument: 'movie_details'
and same error for /delete moviename and /search moviename with their own functions though (i.e delete() or search() which is missing 1 required positional argument: 'query'), for /list however, on discord I still get "The application did not respond" even though it's just supposed to return my empty movie list.
and here is my code:
import openai
import discord
import os
import interactions
from dotenv import load_dotenv
# Load environment variables from .env file
try:
load_dotenv()
except FileNotFoundError:
print("Could not find .env file")
openai.api_key = os.getenv("API_KEY")
if openai.api_key is None:
print("API key not set. Set the API key using openai.api_key = 'YOUR_API_KEY'")
else:
print("Connected to OpenAI API key...")
# Create a bot object using the interactions library
bot = interactions.Client(
token=os.getenv("DISCORD_BOT_TOKEN"),
activity=discord.Activity(type=discord.ActivityType.watching, name="a Movie")
)
# This function is used to get the list of movies from the logger (by reading from the movie-log.txt file)
def get_movie_list():
movie_list = []
try:
with open("movie-log.txt", "r") as movie_log_file:
for line in movie_log_file:
movie_list.append(line.strip())
except FileNotFoundError:
return "movie-log.txt file not found"
else:
return "\n".join(movie_list)
# This function is used to search for movies in the logger (by searching the movie-log.txt file)
def search_movies(query):
search_results = []
try:
with open("movie-log.txt", "r") as movie_log_file:
for line in movie_log_file:
if query.lower() in line.lower():
search_results.append(line.strip())
except FileNotFoundError:
return "movie-log.txt file not found"
else:
if not search_results:
return "No results found"
return "\n".join(search_results)
# This function is used to add a movie to the logger (by appending to the movie-log.txt file)
def add_movie(movie_details):
if not movie_details:
return
# Check if the movie already exists in the logger
if movie_details in search_movies(movie_details):
return
try:
with open("movie-log.txt", "a") as movie_log_file:
movie_log_file.write(f"{movie_details}\n")
except FileNotFoundError:
return "movie-log.txt file not found"
# This function is used to delete a movie from the logger (by overwriting the movie-log.txt file)
def delete_movie(movie_details):
movie_list = get_movie_list()
if movie_details not in movie_list:
return "Movie not found"
try:
with open("movie-log.txt", "w") as movie_log_file:
for movie in movie_list:
if movie != movie_details:
movie_log_file.write(f"{movie}\n")
except FileNotFoundError:
return "movie-log.txt file not found"
# This function is used to handle errors
def handle_error(error):
try:
return f"Error of type {type(error)} occurred: {error}"
except Exception as e:
return "Unable to create error message"
# Debug intents
debug_guild = int(os.getenv("DEBUG_GUILD"))
debug_channel = int(os.getenv("DEBUG_CHANNEL"))
# Define the on_ready event handler
#bot.event
async def on_ready():
print("Bot is up and running...")
print("Bot is ready to use!")
# Define the /add command using the command decorator
#bot.command(
name="add",
description="Adds a movie to the movie log",
scope=debug_guild,
)
async def add(ctx: interactions.CommandContext, movie_details: str):
try:
response = openai.Completion.create(
engine="davinci-003",
prompt=f"/add {movie_details}",
max_tokens=1024,
temperature=0.5,
)
except Exception as e:
# Handle any errors that occurred
await ctx.send(handle_error(e))
else:
# Add the movie to the logger
result = add_movie(response.text.strip())
if result:
await ctx.send(result)
# Define the /delete command using the command decorator
#bot.command(
name="delete",
description="Deletes a movie from the movie log",
scope=debug_guild,
)
async def delete(ctx: interactions.CommandContext, movie_details: str):
try:
response = openai.Completion.create(
engine="davinci-003",
prompt=f"/delete {movie_details}",
max_tokens=1024,
temperature=0.5,
)
except Exception as e:
# Handle any errors that occurred
await ctx.send(handle_error(e))
else:
# Delete the movie from the logger
result = delete_movie(response.text.strip())
if result:
await ctx.send(result)
# Define the /search command using the command decorator
#bot.command(
name="search",
description="Searches for movies in the movie log",
scope=debug_guild,
)
async def search(ctx: interactions.CommandContext, query: str):
# Search for movies in the logger
result = search_movies(query)
if result:
await ctx.send(result)
# Define the /list command using the command decorator
#bot.command(
name="list",
description="Lists all movies in the movie log",
scope=debug_guild,
)
async def list(ctx: interactions.CommandContext):
# Get the list of movies from the logger
result = get_movie_list()
if result:
await ctx.send(result)
# Handle command errors using the on_command_error event
#bot.event
async def command_error(ctx, error):
# Send an error message if a CommandNotFound error occurred
if isinstance(error, interactions.CommandNotFound):
await ctx.send("Command not found")
# Run the bot
bot.start()
Please let me know if anything is unclear or if I don't make sense ;-; Thank you!
What I've tried:
Well, at first I was using commands from discord.ext library but then none of my / commands were even showing up on discord, and I searched the web and found out that it's outdated and that I should switch to using interactions library, I used the docs from https://discord-py-slash-command.readthedocs.io/ to switch to interactions, my / commands started showing up when tried to call on discord however I don't know if I coded them correctly.
So i made a code for warns system, in server it works without issue but the warns are being transferred over to each of the server the bot is in, Plz advise how to make warns distinct for each server
#commands.has_permissions(manage_roles=True, ban_members=True)
async def warn(ctx,user:discord.User,*reason:str):
if reason==None:
reason="Defying a Supreme Power"
else:
reason = ' '.join(reason)
for current_user in Warnlog['user']:
if current_user['name'] == user.name:
current_user['reasons'].append(reason)
break
else:
Warnlog['user'].append({
'name':user.name,
'reasons': [reasons,]
})
with open('Warnlog.json','w+') as f:
json.dump(Warnlog,f)
a=discord.Embed(title="Warned",color=0x800000)
a.add_field(name=f"{user.name} has been warned",value=f" **Reason:-** {reason}")
await ctx.channel.send(embed=a)
#Client.command(manage_channels = True)
async def infractions(ctx,user:discord.User):
for current_user in Warnlog['user']:
if user.name == current_user['name']:
Op=discord.Embed(title=f"**Warn list for {user.name}**",inline=True)
Op.add_field(name="No. Of Warns Recived", value=f"{len(current_user['reasons'])}",inline=True)
Op.add_field(name='Warns', value=f"{','.join(current_user['reasons'])}\n",inline=False)
Op.set_thumbnail(url=f'{user.avatar_url}')
await ctx.send(embed=Op)
break
else:
Io=discord.Embed(title="**Warns**",description=f"{user.name} hasn't commited a Warnable action(YET)")
await ctx.send(embed=Io) ```
You have to change the structure of your json from Warnlog[user] to Warnlog[ctx.guild.id][user]. You can just change this in your code everywhere you are using Warnlog[user], but you have to reset the json database.
I'm using MIP file sample command line interface to apply labelling.
When trying to apply a label that has protection set, i got "Label requires ad-hoc protection, but protection has not yet been set" error.
Therefore, I tried protecting the file using "--protect" option and got the following error message:
"Something bad happened: The service didn't accept the auth token. Challenge:['Bearer resource="https://aadrm.com", realm="", authorization="https://login.windows.net/common/oauth2/authorize"'], CorrelationId=ce732e4a-249a-47ec-a7c2-04f4d68357da, CorrelationId.Description=ProtectionEngine, CorrelationId=6ff992dc-91b3-4610-a24d-d57e13902114, CorrelationId.Description=FileHandler"
This is my auth.py file:
def main(argv):
client_id = str(argv[0])
tenant_id = str(argv[1])
secret = str(argv[2])
authority = "https://login.microsoftonline.com/{}".format(tenant_id)
app = msal.ConfidentialClientApplication(client_id, authority=authority, client_credential=secret)
result = None
scope = ["https://psor.o365syncservice.com/.default"]
result = app.acquire_token_silent(scope, account=None)
if not result:
logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
result = app.acquire_token_for_client(scopes=scope)
if "access_token" in result:
sys.stdout.write(result['access_token'])
else:
print(result.get("error"))
print(result.get("error_description"))
print(result.get("correlation_id")) # You may need this when reporting a bug
if __name__ == '__main__':
main(sys.argv[1:])
I tried to change the scope to ["https://aadrm.com/.default"] and then I was able to protect the file, but when I try getting the file status or try applying label on it I get the same error message with bad auth token.
These are the permissions as configured in azure portal:
Thank you
I think that scope you have is incorrect: https://psor.o365syncservice.com/.default
It should be https://syncservice.o365syncservice.com/.default.
A good way to handle this is to just append .default to whatever resource the AcquireToken() call gets in the resource param. Something like this.
I understand why the error check is printed, but I don't understand why despite the fact that the user calling does not have the mod label, it runs the function anyway, maybe I don't really understand decorators (user also has a token role but I commented that part out for this test)
# token check
#bot.command(name='wallet', help='display if a token is available for user')
#commands.has_role('mod') # remove later
# #commands.has_any_role('PBToken 3', 'PBToken 6')
async def token_check(ctx):
name = ctx.author.name
response = name + ', You have a token available!'
await ctx.send(response)
# error message if user has no token currently
#bot.event
async def on_command_error(ctx, error):
if isinstance(error, commands.errors.MissingRole):
name = ctx.author.name
# await ctx.send(name + ', you currently do not have a token, keep leveling up!')
await ctx.send('error check')
Here is the output:
Intead of using the mod role, why don't you run it using the check for whether the user has server administrator. To do that, all you do would be to replace:
#commands.has_role('mod')
with:
#commands.has_guild_permissions(administrator=True)
This would make the command only run if the specified user has server admin.
Please feel free to reply if you need any more help! :)
Here is my situation: the same Telethon code is used on my local machine and on the server. Requesting authorization code from local machine works fine. Requesting the code from the server does not produce any error, and code is not sent. Sometimes it works even from the server without any changes in code.
I suppose there might be some ip blocks or something related to the ip, cause that is the only thing which might differ on the server side: Heroku assign ip addresses dynamically, so, there might by some subnets which are blocked by Telegram API for some reason. But there is no error and that is really strange. There are too many ip addresses to disprove the hypothesis. I need to catch at least one ip address which gives me opposite results: one time code it recieved and another time does not. So I am stuck with this situation and have no ideas how it could be fixed or clarified.
global t
t = None
async def ssssendCode(phone):
global t
try:
if os.path.isfile(phone+'.session'):
logger.debug('client file exists')
else:
logger.debug('client file does not exist')
if t is None:
t = TelegramClient(phone, settings['telegramClientAPIId'], settings['telegramClientAPIHash'])
t.phone = phone
#t.phone_code_hash = None
await t.connect()
#response = await t.send_code_request(phone=phone,force_sms=True)
s3_session.resource('s3').Bucket('telethon').upload_file(str(phone)+".session", str(phone)+".session")
logger.debug(str(requests.get('https://httpbin.org/ip').text))
response = await t.send_code_request(phone=phone)
logger.debug(str(t.is_connected()))
except Exception as e:
response = str(e)
return str(response)
example of response to the local machine request
SentCode(type=SentCodeTypeSms(length=5), phone_code_hash='b5b069a2a4122040f1', next_type=CodeTypeCall(), timeout=120)
example of reponse to the server-side request
SentCode(type=SentCodeTypeSms(length=5), phone_code_hash='0e89db0324c1af0149', next_type=CodeTypeCall(), timeout=120)
send_code_request is the from the Telethon without modifications
async def send_code_request(
self: 'TelegramClient',
phone: str,
*,
force_sms: bool = False) -> 'types.auth.SentCode':
"""
Sends the Telegram code needed to login to the given phone number.
Arguments
phone (`str` | `int`):
The phone to which the code will be sent.
force_sms (`bool`, optional):
Whether to force sending as SMS.
Returns
An instance of :tl:`SentCode`.
Example
.. code-block:: python
phone = '+34 123 123 123'
sent = await client.send_code_request(phone)
print(sent)
"""
result = None
phone = utils.parse_phone(phone) or self._phone
phone_hash = self._phone_code_hash.get(phone)
if not phone_hash:
try:
result = await self(functions.auth.SendCodeRequest(
phone, self.api_id, self.api_hash, types.CodeSettings()))
except errors.AuthRestartError:
return await self.send_code_request(phone, force_sms=force_sms)
# If we already sent a SMS, do not resend the code (hash may be empty)
if isinstance(result.type, types.auth.SentCodeTypeSms):
force_sms = False
# phone_code_hash may be empty, if it is, do not save it (#1283)
if result.phone_code_hash:
self._phone_code_hash[phone] = phone_hash = result.phone_code_hash
else:
force_sms = True
self._phone = phone
if force_sms:
result = await self(
functions.auth.ResendCodeRequest(phone, phone_hash))
self._phone_code_hash[phone] = result.phone_code_hash
return result
Just in case: I have much more than 2 minutes between attempts to get a code from the local machine and server, so it is absolutely not the timeout issue. And moreover: even when requesting the code from the local right after half a minute from the failed server-side attemp: code is coming almost immediately.