Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test #10

Merged
merged 21 commits into from
Jan 27, 2024
Merged

Test #10

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e3fe9c9
feat: add getnews command
GianmarcoBasile Dec 11, 2023
adb95f1
chore: add syntax error for getnews command
GianmarcoBasile Dec 11, 2023
f5d8cb6
chore: start of db swap
GianmarcoBasile Dec 12, 2023
d2c0df6
fix: fix of addgame and deletegame command
GianmarcoBasile Dec 12, 2023
7f9af7a
feat:mongodb compatibility
AndreaSeminara Dec 12, 2023
7ec7fee
feat: add parsing of news and add return of news message
AndreaSeminara Dec 15, 2023
c4dbbc4
Merge pull request #3 from GianmarcoBasile/mongo_compatibility
GianmarcoBasile Dec 15, 2023
bcb113e
chore: change news message
GianmarcoBasile Dec 15, 2023
794ab62
feat: add news command automatation
GianmarcoBasile Dec 18, 2023
f8d23e0
refactor: 10/10 pylint
GianmarcoBasile Dec 18, 2023
9411391
Merge branch 'dev' into parsing
GianmarcoBasile Dec 18, 2023
84c589b
Merge pull request #5 from GianmarcoBasile/parsing
GianmarcoBasile Dec 18, 2023
41b3717
fix: json adjustment
GianmarcoBasile Dec 18, 2023
89411d1
chore: remove debug files
GianmarcoBasile Dec 18, 2023
de40e85
feat: add checksales command and add auto message for game sales
AndreaSeminara Dec 20, 2023
fd61d66
Merge pull request #6 from GianmarcoBasile/sales_message
GianmarcoBasile Dec 20, 2023
c555c7d
feat: add possible suggestions when the addgame parameter is not in t…
AndreaSeminara Dec 20, 2023
184bf8a
chore: optimize suggestions
AndreaSeminara Dec 20, 2023
9092c2e
Merge pull request #7 from GianmarcoBasile/suggestions
GianmarcoBasile Dec 20, 2023
88d6eb7
test: implement test for commands
GianmarcoBasile Jan 27, 2024
2fb727b
refactor: code refactor
GianmarcoBasile Jan 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .coverage
Binary file not shown.
5 changes: 5 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[run]
omit =
src/main.py
src/bot.py
src/database.py
File renamed without changes.
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
python-telegram-bot
python-telegram-bot[job-queue]
python-dotenv
redis
pymongo==3.12.3
requests
json_stream
1 change: 1 addition & 0 deletions requirements_dev.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pytest
pytest-mock
pytest-cov
pytest-asyncio
pylint
273 changes: 205 additions & 68 deletions src/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,93 +2,230 @@
"""Module providing commands for the bot"""

import json
import requests
from database import initialize_db as db
from utils import get_game_list
from utils import (
get_game_list,
get_game_id_by_name,
check_similarities,
get_games_record,
update_games_record,
)
from news_parser import parser
from telegram.constants import ParseMode

redis_instance = db('localhost', 6379)
mongo_instance = db("mongodb://localhost", 27017)
app_list = get_game_list()
required_argument = 'This command requires one argument: '
syntax_error = "The correct syntax for this command is: "


async def start(update, context):
redis_instance.set(update.message.from_user['username'], json.dumps({'games': {}}))
await update.message.reply_text('Welcome to Steam News Bot!')
sender = update.message.from_user["username"]
if not mongo_instance["USERS"]["users"].find_one(
{"chat_id": update.message.chat_id}
):
mongo_instance["USERS"]["users"].insert_one(
{"chat_id": update.message.chat_id, "user": sender, "games": {}}
)
await update.message.reply_text("Welcome to Steam News Bot!")


async def addGame(update, context):
games_record = {}
try:
if context.args:
game_name = ' '.join(context.args).lower()
game_name = " ".join(context.args).lower()
if game_name in app_list.values():
games_list = json.loads(redis_instance.get(update.message.from_user['username']))['games']
if not games_list:
games_json = {'games': {0: game_name}}
redis_instance.set(update.message.from_user['username'], json.dumps(games_json))
await update.message.reply_text('Games set to ' + game_name)
else:
games = []
games_json = json.loads(redis_instance.get(update.message.from_user['username']))
if game_name not in games_json['games'].values():
games_json['games'].update({len(games_json['games']): game_name})
games = list(games_json['games'].values())
redis_instance.set(update.message.from_user['username'], json.dumps(games_json))
await update.message.reply_text('Games set to ' + str(games).replace('[', '').replace(']', '').replace("'", ''))
try:
games_record = get_games_record(
update.message.from_user["username"]
)
except Exception as e:
print(e)
if game_name not in games_record["games"].values():
if games_record["games"] == {}:
games_record["games"] = {"0": game_name}
else:
await update.message.reply_text('Game already in your favorites')
games_record["games"].update(
{str(int(max(games_record["games"])) + 1): game_name}
)
update_games_record(
update.message.from_user["username"], games_record
)
await update.message.reply_text(
"Game " + str(game_name) + " added to the list"
)
else:
await update.message.reply_text("The game is already in the list")
else:
await update.message.reply_text('Game not found')
suggestions = check_similarities(game_name)
if len(suggestions) > 0:
await update.message.reply_text(
"Game not found. Maybe you meant: " + suggestions
)
else:
await update.message.reply_text("The game is not a steam game")
else:
await update.message.reply_text(required_argument + '/addgame <game_name>')
await update.message.reply_text(syntax_error + "/addgame <game_name>")
except Exception as e:
print(e)

async def deleteGame(update, context):

async def deleteGame(update, context):
if context.args:
game_name = ' '.join(context.args).lower()
games_list = json.loads(redis_instance.get(update.message.from_user['username']))['games']
if not games_list:
await update.message.reply_text('The favourite game list is empty')
game_name = " ".join(context.args).lower()
try:
games_record = get_games_record(update.message.from_user["username"])
except Exception as e:
print(e)
if game_name in games_record["games"].values():
games_record["games"].pop(
str(list(games_record["games"].values()).index(game_name))
)
update_games_record(update.message.from_user["username"], games_record)
await update.message.reply_text(
"Game " + str(game_name) + " deleted from the list"
)
else:
games_json = json.loads(redis_instance.get(update.message.from_user['username']))
if game_name in games_json['games'].values():
for key, value in games_json['games'].items():
if value == game_name:
games_json['games'].pop(key)
break
new_games_json = {'games':{}}
for key, value in games_json['games'].items():
new_games_json['games'].update({len(new_games_json['games']): value})
redis_instance.set(update.message.from_user['username'], json.dumps(new_games_json))
await update.message.reply_text('Game ' + str(game_name)+ ' removed from the list')
else:
await update.message.reply_text('The game is not in the list')
await update.message.reply_text("The game is not in the list")
else:
await update.message.reply_text(required_argument + '/deletegame <game_name>')
await update.message.reply_text(syntax_error + "/deletegame <game_name>")


async def clearGamesList(update, context):
redis_instance.set(update.message.from_user['username'], json.dumps({'games': {}}))
await update.message.reply_text('Game list cleared')

# async def getNews(update, context):
# global game_id
# if context.args:
# r = requests.get('http://api.steampowered.com/ISteamNews/GetNewsForApp/v0002/?appid=' + getGameIdByName(context.args[0]) + '&count=3&maxlength=300&format=json')
# print(r.json())
# await update.message.reply_text('News for game ' + context.args[0])
# elif not context.args and game_id != '':
# r = requests.get('http://api.steampowered.com/ISteamNews/GetNewsForApp/v0002/?appid=' + game_id + '&count=3&maxlength=300&format=json')
# print(r.json())
# await update.message.reply_text('News for game ' + game_id)
# else:
# await update.message.reply_text('La sintassi del comando prevede che tu abbia prima settato un gioco oppure che tu inserisca un argomento: /getnews <game_id>')

# async def getNews(context):
# global game_id
# print('gameid:', game_id)
# r = requests.get('http://api.steampowered.com/ISteamNews/GetNewsForApp/v0002/?appid=' + game_id + '&count=3&maxlength=300&format=json')
# print(r.json())
# return r.json()
if not context.args:
try:
games_record = get_games_record(update.message.from_user["username"])
except Exception as e:
print(e)
games_record["games"] = {}
update_games_record(update.message.from_user["username"], games_record)
await update.message.reply_text("Games list cleared")
else:
await update.message.reply_text(syntax_error + "/cleargameslist")


async def getNews(update, context):
if not context.args:
try:
games = get_games_record(update.message.from_user["username"])
for game in games["games"].values():
r = requests.get(
"http://api.steampowered.com/ISteamNews/GetNewsForApp/v0002/?appid="
+ str(get_game_id_by_name(game))
+ "&count=5&maxlength=50000&format=json"
)
news_list = r.json()["appnews"]["newsitems"]
# added_news = []
for news in news_list:
news_message = parser(news)
await update.message.reply_text(
news_message, parse_mode=ParseMode.HTML
)
except Exception as e:
print(e)
else:
await update.message.reply_text(syntax_error + "/getnews")


async def getNewsAuto(context): # pragma: no cover
users = mongo_instance["USERS"]["users"].find()
for user in users:
for game in user["games"].values():
r = requests.get(
"http://api.steampowered.com/ISteamNews/GetNewsForApp/v0002/?appid="
+ str(get_game_id_by_name(game))
+ "&count=1&maxlength=50000&format=json"
)
news_list = r.json()["appnews"]["newsitems"]
for news in news_list:
news_message = parser(news)
await context.bot.send_message(
user["chat_id"], news_message, parse_mode=ParseMode.HTML
)


async def getFavoriteGames(update, context):
games = list(json.loads(redis_instance.get(update.message.from_user['username']))['games'].values())
print(games)
await update.message.reply_text('Favorite Games: ' + str(games).replace('[', '').replace(']', '').replace("'", ''))
if not context.args:
try:
games_record = get_games_record(update.message.from_user["username"])
except Exception as e:
print(e)
games = list(games_record["games"].values())
await update.message.reply_text(
"Favorite Games: "
+ str(games).replace("[", "").replace("]", "").replace("'", "")
)
else:
await update.message.reply_text(syntax_error + "/favoritegames")


async def saleOnGames(update, context): # pragma: no cover
if not context.args:
games_record = mongo_instance["USERS"]["users"].find_one(
{"user": update.message.from_user["username"]}
)
for game in games_record["games"].values():
game_id = str(get_game_id_by_name(game))
r = requests.get(
"https://store.steampowered.com/api/appdetails/?appids="
+ game_id
+ "&currency=EUR"
)
req = r.json()[game_id]
if req["success"]:
curr_game = req["data"]
if curr_game["is_free"]:
await update.message.reply_text("The game " + game + " is free")
elif (
curr_game["price_overview"]["initial"]
== curr_game["price_overview"]["final"]
):
await update.message.reply_text(
"The game "
+ game
+ " is not on sale. It costs "
+ curr_game["price_overview"]["final_formatted"]
)
else:
await update.message.reply_text(
"The game "
+ game
+ " is on sale for "
+ curr_game["price_overview"]["final_formatted"]
+ " instead of "
+ curr_game["price_overview"]["initial_formatted"]
)
else:
await update.message.reply_text(syntax_error + "/checksales")


async def saleOnGamesAuto(context): # pragma: no cover
users = mongo_instance["USERS"]["users"].find()
for user in users:
for game in user["games"].values():
game_id = str(get_game_id_by_name(game))
r = requests.get(
"https://store.steampowered.com/api/appdetails/?appids="
+ game_id
+ "&currency=EUR"
)
req = r.json()[game_id]
if req["success"]:
curr_game = req["data"]
if curr_game["is_free"]:
continue
elif (
curr_game["price_overview"]["initial"]
== curr_game["price_overview"]["final"]
):
await context.bot.send_message(
user["chat_id"], game + " is not on sale"
)
else:
await context.bot.send_message(
user["chat_id"],
game
+ " is on sale for "
+ curr_game["price_overview"]["final_formatted"],
)
11 changes: 8 additions & 3 deletions src/database.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
"""Module providing Database API."""
import pymongo


import redis
def initialize_db(host, port):
"""Initialize Database."""
db = redis.Redis(host=host, port=port, decode_responses=True)
return db
try:
mongo = pymongo.MongoClient(host + ":" + str(port) + "/", connectTimeoutMS=5000)
except pymongo.errors.ServerSelectionTimeoutError as e:
print("Error connecting to the database: " + str(e))
return None
return mongo
47 changes: 36 additions & 11 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,52 @@
from dotenv import load_dotenv
from telegram.ext import CommandHandler
from bot import Bot
from commands import start, addGame, getFavoriteGames, deleteGame,clearGamesList
from commands import (
start,
addGame,
getFavoriteGames,
deleteGame,
clearGamesList,
getNews,
getNewsAuto,
saleOnGames,
saleOnGamesAuto,
)

load_dotenv()
API_KEY = os.environ['API_KEY']
API_KEY = os.environ["API_KEY"]
bot_instance = Bot(API_KEY)

# http://api.steampowered.com/ISteamNews/GetNewsForApp/v0002/?appid=440&count=3&maxlength=300&format=json


def main():
"""Main function which runs the bot and adds the handlers"""
# Commands
bot_instance.application.add_handler(CommandHandler('start', start))
# application.add_handler(CommandHandler('getnews', getNews))
bot_instance.application.add_handler(CommandHandler('addgame', addGame))
bot_instance.application.add_handler(CommandHandler('favoritegames', getFavoriteGames))
#il nome del comando nel bot è favoritegame, da modificare in favoritegames
bot_instance.application.add_handler(CommandHandler('deletegame', deleteGame))
bot_instance.application.add_handler(CommandHandler('cleargameslist', clearGamesList))
# application.job_queue.run_repeating(getNews, interval=10, first=0)
bot_instance.application.add_handler(CommandHandler("start", start))
bot_instance.application.add_handler(CommandHandler("getnews", getNews))
bot_instance.application.add_handler(CommandHandler("checksales", saleOnGames))
bot_instance.application.add_handler(CommandHandler("addgame", addGame))
bot_instance.application.add_handler(
CommandHandler("favoritegames", getFavoriteGames)
)
bot_instance.application.add_handler(CommandHandler("deletegame", deleteGame))
bot_instance.application.add_handler(
CommandHandler("cleargameslist", clearGamesList)
)
# Jobs: get news every 24 hours
bot_instance.application.job_queue.run_once(getNewsAuto, 0)
bot_instance.application.job_queue.run_repeating(
getNewsAuto, interval=86400, first=0
)
# Jobs: check for sales every 24 hours
bot_instance.application.job_queue.run_once(saleOnGamesAuto, 5)
bot_instance.application.job_queue.run_repeating(
saleOnGamesAuto, interval=86400, first=0
)
# Run bot
bot_instance.application.run_polling(1.0)

if __name__ == '__main__':

if __name__ == "__main__":
main()
Loading
Loading