diff --git a/database.sql b/database.sql new file mode 100644 index 0000000..e69de29 diff --git a/discordsFunctionalities/runBot.py b/discordsFunctionalities/runBot.py new file mode 100644 index 0000000..c3eba6f --- /dev/null +++ b/discordsFunctionalities/runBot.py @@ -0,0 +1,62 @@ +from .sendMessages import * +import discord +import os +import re + + +Token = os.getenv('MY_TOKEN') +intents = discord.Intents.default() +intents.members = True +client = discord.Client(intents = intents) + + +def run_discord_bot(): + """ + Function to run the Discord bot. Registers the event handlers. + """ + # Event handler for when the bot ready: + @client.event + async def initiation(): + await on_ready() + # Event handler for when a message is received + @client.event + async def on_message(message): + # Ignore messages ent by the bot itself: + if message.author == client.user: + return + # Extract the username, user message, and channel from the message. + username = str(message.author) + user_message = str(message.content) + channel = str(message.channel) + print(f'{username} said: {user_message} {channel}.') + # Define regular expressions to match the message: + asin_pattern = r"""^[A-Z0-9]{10}$""" + regex_pattern = """^hi|hello|hey|yo""" + amazon_pattern = '(https?://)?(www\.)?amazon\.(com|in|co\.uk)/.+' + + # If the message is a greeting and is sent in a direct message: + if message.guild is None and re.match(regex_pattern, message.content, re.IGNORECASE): + await message.author.send(f"Hey {username}. Type '!general' or '!help' to know the overview of bot.") + # If the message is !general and is sent in a direct message: + elif message.content == '!commands': + await menu(message.content, message.author) + elif message.content == '!general' or message.content == '!help': + await menu(message.content, message.author) + elif message.content == '!about': + await menu(message.content, message.author) + elif message.content == '!ping': + await menu(message.content, message.author, client) + elif message.content == '!status': + await menu(message.content, message.author) + # If the message is an Amazon product link and is sent in a direct message: + elif message.guild is None and re.search(amazon_pattern, user_message): + await asin_isbn(message.author, user_message) + # IF the message is an ASIN/ISBN and is sent in a direct message: + elif message.guild is None and (re.match(asin_pattern, message.content)): + await message.author.send(f"Please wait. Fetching data from Amazon.") + await getdataByasin(user_message, message.author) + else: + await message.author.send(f"Invalid command. Type '!general | !help' or '!commands' to know the purpose of the bot.") + # Run the client with the TOKEN: + client.run(Token) + diff --git a/discordsFunctionalities/sendMessages.py b/discordsFunctionalities/sendMessages.py new file mode 100644 index 0000000..1b6e71d --- /dev/null +++ b/discordsFunctionalities/sendMessages.py @@ -0,0 +1,143 @@ +from tools.tool import Response +import datetime +import discord +import sys +import os + + +sys.path.append(os.getcwd()) +from scrapers.scraper import Amazon + + +async def menu(message, user, bot = None): + """ + Handles different commands based on the user's input message and sends corresponding information to the user via private message. + + Args: + - message (str): The user's input message, indicating the command to be executed. + - user (discord.User): User object representing the user who initiated the command. + - bot (discord.Client, optional): Discord bot object. Defaults to None. + + Returns: + - None: This function does not return any value directly. It sends relevant information to the user via private message based on the input command. + """ + if message == '!general' or message == '!help': + embed = discord.Embed(title = "General", description = "General overview of bot.", color = 0xff9900) + embed.add_field(name = '!commands', value = "List of available commands and their explanation.", inline = False) + embed.add_field(name = '!about', value = "Provides the information about the bot and its purpose.", inline = False) + embed.add_field(name = "!ping", value = "Check the bot's response time to the server.") + embed.add_field(name = "!status", value = "Check the status of the Amazon's server.", inline = False) + embed.set_footer(text = 'Powered by Python', icon_url = 'https://logos-download.com/wp-content/uploads/2016/10/Python_logo_icon.png') + embed.set_author(name = "Sushil", url = "https://www.github.com/sushil-rgb", icon_url = "https://avatars.githubusercontent.com/u/107347115?s=400&u=7a5fbfe85d59d828d52b407c999474c8938325c7&v=4") + embed.timestamp = datetime.datetime.now() + + await user.send(embed = embed) + + if message == '!commands': + embed = discord.Embed(title ='Bot menu', description = "List of available commands and their explanation.", color = 0xff9900) + embed.add_field(name = "ASIN `[B0CK3ZWT7X]`", value = "Extracts ASIN from the provided product link.", inline = False) + embed.add_field(name = "Paste product link `https://www.amazon.com/PlayStation-5-Console-CFI-1215A01X/dp/B0BCNKKZ91`", value = "Extracts ASIN from the provided product link.", inline = False) + embed.set_footer(text = 'Powered by Python', icon_url = 'https://logos-download.com/wp-content/uploads/2016/10/Python_logo_icon.png') + embed.set_author(name = "Sushil", url = "https://www.github.com/sushil-rgb", icon_url = "https://avatars.githubusercontent.com/u/107347115?s=400&u=7a5fbfe85d59d828d52b407c999474c8938325c7&v=4") + embed.timestamp = datetime.datetime.now() + + await user.send(embed = embed) + + if message == '!about': + embed = discord.Embed(title = "About", description = "Provides the information about the bot and its purpose.", color = 0xff9900) + embed.add_field(name = "Purpose", value = "The purpose of this bot is to extract product ASIN by product link and retrieve product information by pasting ASIN.", inline = False) + embed.add_field(name = "Example Usage:", + value = "`[product link]` - Extracts ASIN from the provided product link. \n" + "`[B0CK3ZWT7X]` - Retrieves detailed product information using the provided ASIN.", + inline = False + ) + embed.set_footer(text = 'Powered by Python', icon_url = 'https://logos-download.com/wp-content/uploads/2016/10/Python_logo_icon.png') + embed.set_author(name = "Sushil", url = "https://www.github.com/sushil-rgb", icon_url = "https://avatars.githubusercontent.com/u/107347115?s=400&u=7a5fbfe85d59d828d52b407c999474c8938325c7&v=4") + embed.timestamp = datetime.datetime.now() + + await user.send(embed = embed) + + if message == '!ping': + latency = bot.latency + embed = discord.Embed(title = "Ping", + description = f"Pong! Bot latency is {latency * 1000:.2f}ms.", + color = 0x008000, + ) + embed.set_footer(text = 'Powered by Python', icon_url = 'https://logos-download.com/wp-content/uploads/2016/10/Python_logo_icon.png') + embed.set_author(name = "Sushil", url = "https://www.github.com/sushil-rgb", icon_url = "https://avatars.githubusercontent.com/u/107347115?s=400&u=7a5fbfe85d59d828d52b407c999474c8938325c7&v=4") + embed.timestamp = datetime.datetime.now() + + await user.send(embed = embed) + + + if message == '!status': + repsonse = await Response('https://www.amazon.com').response() + if repsonse == 200: + embed = discord.Embed(title = "Status", description = f'Status code: 200', color = 0x008000) + embed.set_footer(text = 'Powered by Python', icon_url = 'https://logos-download.com/wp-content/uploads/2016/10/Python_logo_icon.png') + embed.set_author(name = "Sushil", url = "https://www.github.com/sushil-rgb", icon_url = "https://avatars.githubusercontent.com/u/107347115?s=400&u=7a5fbfe85d59d828d52b407c999474c8938325c7&v=4") + embed.timestamp = datetime.datetime.now() + + await user.send(embed = embed) + else: + embed = discord.Embed(title = "Status", description = repsonse, color = 0xFF0000) + embed.set_footer(text = 'Powered by Python', icon_url = 'https://logos-download.com/wp-content/uploads/2016/10/Python_logo_icon.png') + embed.set_author(name = "Sushil", url = "https://www.github.com/sushil-rgb", icon_url = "https://avatars.githubusercontent.com/u/107347115?s=400&u=7a5fbfe85d59d828d52b407c999474c8938325c7&v=4") + embed.timestamp = datetime.datetime.now() + + await user.send(embed = embed) + + +async def on_ready(): + """ + This function prints a message when the bot is ready to use. + """ + print(f"Buddy is now running.") + + +async def asin_isbn(user, userInput): + """ + This function takes a user object and a user input as parameters, calls the Amazon class to get ASIN and ISBN numbers, + and sends the results to the user. + + Args: + -user (discord.User): User object. + -userInput (str): User input. + + Returns: + -None + """ + datas = await Amazon(userInput, None).getASIN(userInput) + await user.send(datas) + + +async def getdataByasin(userInput, user): + """ + This function takes a user input and a suer object as parameters, call the Amazon class to get product data using ASIN, + creates a discord embed with the product data, and send the embed to the user. + + Args: + -userInput (str): User input. + -user (discord.User): User object. + + Returns: + -None + """ + try: + datas = await Amazon(userInput, None).dataByAsin(userInput) + name = datas['Name'] + hyperlink = datas['Hyperlink'] + embed = discord.Embed(title = name, url = hyperlink, color = 0xff9900) + embed.add_field(name = 'Price', value = datas['Price'], inline = False) + embed.add_field(name = 'Availability', value = datas['Availability'], inline = False) + embed.add_field(name = "Store", value = f"[{datas['Store']}]({datas['Store link']})", inline = False) + embed.add_field(name = 'Rating', value = datas['Rating'], inline = False) + embed.add_field(name = 'Review count', value = datas['Rating count'], inline = False) + embed.set_thumbnail(url = datas['Image']) + embed.timestamp = datetime.datetime.now() + embed.set_footer(text = 'Powered by Python', icon_url = 'https://logos-download.com/wp-content/uploads/2016/10/Python_logo_icon.png') + await user.send(embed = embed) + except Exception as e: + await user.send('Content loading error. Please try again in few minutes.') + + diff --git a/mongo_database/mongo.py b/mongo_database/mongo.py new file mode 100644 index 0000000..ff837df --- /dev/null +++ b/mongo_database/mongo.py @@ -0,0 +1,36 @@ +from tools.tool import flat, export_sheet +from scrapers.scraper import Amazon +import pymongo as mong + + +async def export_to_mong(url, proxy): + amazon = Amazon(url, proxy) + client = mong.MongoClient("mongodb://localhost:27017/") + db = client['amazon'] + collection_name = await amazon.category_name() + print(f"Collecting {collection_name} to Mongo database.") + collection = db[collection_name] + datas = await amazon.concurrent_scraping() + result = collection.insert_many(flat(datas)) + client.close() + return result + + +async def mongo_to_sheet(coll_name): + client = mong.MongoClient('mongodb://localhost:27017') + db = client['amazon'] + collection_category = db[coll_name] + datas = list(collection_category.find({})) + await export_sheet(datas, coll_name) + client.close() + + +async def data_by_asin(asin): + client = mong.MongoClient("mongodb://localhost:27017/") + db = client['amazon'] + collection = db['playstation_5_accessories'] + query = {"ASIN": asin} + filtered_doc = [doc for doc in collection.find(query)] + client.close() + return filtered_doc + diff --git a/mySQLfunctionalities/base_model.py b/mySQLfunctionalities/base_model.py new file mode 100644 index 0000000..0d9f5a3 --- /dev/null +++ b/mySQLfunctionalities/base_model.py @@ -0,0 +1,40 @@ +from pydantic import BaseModel, Field + + +class AamazonRecord(BaseModel): + """ + A Pydantic BaseModel to represent Amazon product's records. + + Attributes: + ----------- + ASIN : str + -The unique Amazon Standard Identification Number of the product. + Name: str + -The name of the product. + Price: str + -The price of the product. + Rating: str + -The rating of the product. + Rating_count: str + -The number of rating the product has. + Availability : str + -The availability status of the product. + Hyperlink: str + -The hyperlink of the product on Amazon. + Store: str + -The name of the store selling the product. + Store_link : str + -The URL of the store selling the product. + + """ + ASIN: str = Field(..., alias = "ASIN") + Name: str = Field(..., alias = "Name") + Price: str = Field(..., alias = "Price") + Rating: str = Field(..., alias = "Rating") + Rating_count: str = Field(..., alias = "Rating count") + Availability: str = Field(..., alias = "Availability") + Hyperlink: str = Field(..., alias = "Hyperlink") + Image: str = Field(..., alias = "Image") + Store: str = Field(..., alias = "Store") + Store_link: str = Field(..., alias = "Store link") + diff --git a/mySQLfunctionalities/db.py b/mySQLfunctionalities/db.py new file mode 100644 index 0000000..65e6da1 --- /dev/null +++ b/mySQLfunctionalities/db.py @@ -0,0 +1,85 @@ +from scrapers.scraper import Amazon +from dotenv import load_dotenv +import mysql.connector +import os + + +load_dotenv(f"{os.getcwd()}//environmentVariables//.env") + + +async def mysql_connections(): + """ + Establishes a connection to the MySQL database using environment variables. + + Returns: + -cnx: MySQL connection object. + """ + cnx = mysql.connector.connect( + host = os.getenv('DB_HOST'), + port = os.getenv('PORT'), + user = os.getenv('DB_USERNAME'), + password = os.getenv('DB_PASSWORD'), + database = os.getenv('DATABASE'), + ) + return cnx + + +async def verifyASIN(amazon_asin): + """ + Checks if the given Amazon ASIN exists in the database. + + Args: + -amazon_asin: Amazon ASIN of the product to check. + + Returns: + -True if ASIN already exists in the database, else None. + """ + cnx = await mysql_connections() + cursor = cnx.cursor() + sql_check_query = """SELECT * FROM asin_collections WHERE ASIN = %s""" + params = (amazon_asin,) + cursor.execute(sql_check_query, params) + if cursor.fetchone(): + cnx.close() + return True + else: + cnx.close() + return + + +async def export_to_db(amazon_asin, user = None): + """ + Exports data for a given Amazon ASIN/ISBN to the databse. + + Args: + -amazon_asin: Amazon ASIN of the product to export. + + Returns: + -Dictionary containing the data for the product if it's already existed in the database, + else None if the data was successfully exported to the databse. + """ + cnx = await mysql_connections() + select_query = f"""SELECT * FROM asin_collections WHERE ASIN = '{amazon_asin}'""" + cursor = cnx.cursor() + if await verifyASIN(amazon_asin): + cursor.execute(select_query) + row = cursor.fetchone() + columns = [col[0] for col in cursor.description] + result_dict = dict(zip(columns, row)) + print(f"{amazon_asin} already exists.") + cnx.close() + return result_dict + else: + amazon_datas = await Amazon().dataByAsin(amazon_asin) + insert_query = f"""INSERT INTO `asin_collections` (`ASIN`, `Name`, `Price`, `Rating`, `Rating count`, `Availability`, `Hyperlink`, `Image`, `Store`, `Store link`) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""" + values = (amazon_asin, amazon_datas['Name'], amazon_datas['Price'], amazon_datas['Rating'], amazon_datas['Rating count'], amazon_datas['Availability'], amazon_datas['Hyperlink'], amazon_datas['Image'], amazon_datas['Store'], amazon_datas['Store link']) + cursor.execute(insert_query, values) + cnx.commit() + cursor.execute(select_query) + row = cursor.fetchone() + columns = [col[0] for col in cursor.description] + result_dict = dict(zip(columns, row)) + print(f"{amazon_asin} added to database.") + cnx.close() + return result_dict +