Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion source-code/chapter-5/exercise-2/newsbot/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def handle_incoming_messages(last_updated):
summarized_news = get_latest_news(sub_reddits)
post_message(person_id, summarized_news)
except peewee.DoesNotExist:
post_message(person_id, 'Could not find a saved subreddit, please try setting sources with /source')
post_message(person_id, ERR_NO_SOURCE)

last_updated = req['update_id']
with open('last_updated.txt', 'w') as f:
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

9 changes: 9 additions & 0 deletions source-code/chapter-6/exercise-1/newsbot/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM python:3-alpine

RUN apk add gcc musl-dev python3-dev libffi-dev openssl-dev cargo
WORKDIR /apps/subredditfetcher/
COPY . .

RUN pip install --upgrade pip && pip install -r requirements.txt
VOLUME ["/data"]
CMD ["python", "newsbot.py"]
15 changes: 15 additions & 0 deletions source-code/chapter-6/exercise-1/newsbot/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
__author__ = 'Sathyajith'

from os import environ
from sys import exit
ERR_NO_SOURCE = 'No sources defined! Set a source using /source list, of, sub, reddits'
skip_list = []
sources_dict = {}
UPDATE_PERIOD = 1
FALSE_RESPONSE = {"ok": False}

BOT_KEY = environ.get('NBT_ACCESS_TOKEN')
if not BOT_KEY:
print("Telegram access token not set, exiting.")
exit(1)
API_BASE = f'https://api.telegram.org/bot{BOT_KEY}'
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from peewee import *
# db = SqliteDatabase('newsbot.db')
from peewee import Model, PrimaryKeyField, IntegerField, CharField, DateTimeField, MySQLDatabase


db = MySQLDatabase(host="mysql", port=3306, user="root", password="dontusethisinprod", database="newsbot")

class BaseModel(Model):
class Meta:
database = db
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
from telegram import handle_incoming_messages
from models import *
from time import sleep

import sys
from peewee import OperationalError
import pymysql


Expand All @@ -28,14 +27,12 @@ def get_last_updated():
log.info('Checking on dbs')
try:
db.connect()
except OperationalError as o:
print("Could not connect to db, please check db parameters")
sys.exit(-1)
except InternalError as e:
# 1049 is MySQL error code for db doesn't exist - so we create it.
db_connection = pymysql.connect(host='mysql', user= 'root', password='dontusethisinprod')
db_connection.cursor().execute('CREATE DATABASE newsbot')
db_connection.close()
except OperationalError as e:
error_code, message = e.args[0], e.args[1]
if error_code == 1049:
db_connection = pymysql.connect(host='mysql', user= 'root', password='dontusethisinprod')
db_connection.cursor().execute('CREATE DATABASE newsbot')
db_connection.close()
db.create_tables([Source, Request, Message], True)

try:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,30 @@
__author__ = 'Sathyajith'


def summarize(url):
log.info('Not yet implemented!')
return url


def get_latest_news(sub_reddits):
log.debug('Fetching news from reddit')
r = praw.Reddit(user_agent='SubReddit Newsfetcher Bot',
r = praw.Reddit(user_agent='NewsBot',
client_id='ralalsYuEJXKDg',
client_secret="16DD-6O7VVaYVMlkUPZWLhdluhU")
r.read_only = True

# Can change the subreddit or add more.
sub_reddits = clean_up_subreddits(sub_reddits)
log.info('Fetching subreddits: {0}'.format(sub_reddits))
log.info('Fetching subreddits: {sub_reddits}')
submissions = r.subreddit(sub_reddits).hot(limit=5)
submission_content = ''
try:
for post in submissions:
submission_content += summarize(post.title + ' - ' + post.url) + '\n\n'
submission_content += post.title + ' - ' + post.url + '\n\n'
except praw.errors.Forbidden:
log.debug('subreddit {0} is private'.format(sub_reddits))
log.debug(f'subreddit {sub_reddits} is private')
submission_content = "Sorry couldn't fetch; subreddit is private"
except praw.errors.InvalidSubreddit:
log.debug('Subreddit {} is invalid or doesn''t exist.'.format(sub_reddits))
log.debug(f'Subreddit {sub_reddits} is invalid or doesn''t exist')
submission_content = "Sorry couldn't fetch; subreddit doesn't seem to exist"
return submission_content


def clean_up_subreddits(sub_reddits):
log.debug('Got subreddits to clean: {0}'.format(sub_reddits))
log.debug(f'Got subreddits to clean: {sub_reddits}')
return sub_reddits.strip().replace(" ", "").replace(',', '+')
4 changes: 4 additions & 0 deletions source-code/chapter-6/exercise-1/newsbot/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
peewee==2.10.2
praw==7.4.0
PyMySQL
cryptography
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
from constants import *
from reddit import get_latest_news
from models import *
import peewee

__author__ = 'Sathyajith'

db = MySQLDatabase(host="mysql", port=3306, user="root", password="dontusethisinprod", database="newsbot")

def get_updates(last_updated):
log.debug('Checking for requests, last updated passed is: {}'.format(last_updated))
log.debug('Checking for requests, last updated passed is: {last_updated}')
sleep(UPDATE_PERIOD)
response = requests.get(API_BASE + BOT_KEY + '/getUpdates', params={'offset': last_updated+1})
response = requests.get(f"{API_BASE}/getUpdates", params={'offset': last_updated+1})
json_response = FALSE_RESPONSE
if response.status_code != 200:
# wait for a bit, try again
Expand All @@ -25,79 +26,83 @@ def get_updates(last_updated):
except ValueError:
sleep(UPDATE_PERIOD*20)
get_updates(last_updated)
log.info('received response: {}'.format(json_response))
log.info(f"received response: {json_response}")
return json_response


def post_message(chat_id, text):
log.info('posting {} to {}'.format(text, chat_id))
log.debug(f"posting {text} to {chat_id}")
payload = {'chat_id': chat_id, 'text': text}
requests.post(API_BASE + BOT_KEY + '/sendMessage', data=payload)
requests.post(f"{API_BASE}/sendMessage", data=payload)


def handle_incoming_messages(last_updated):
r = get_updates(last_updated)
split_chat_text = []
if r['ok']:
for req in r['result']:
chat_sender_id = req['message']['chat']['id']
if 'message' in req:
chat_sender_id = req['message']['chat']['id']
else:
chat_sender_id = req['edited_message']['chat']['id']
try:
chat_text = req['message']['text']
split_chat_text = chat_text.split()
except KeyError:
chat_text = ''
split_chat_text.append(chat_text)
log.debug('Looks like no chat text was detected... moving on')
try:

if 'message' in req:
person_id = req['message']['from']['id']
except KeyError:
pass
else:
person_id = req['edited_message']['from']['id']

log.info('Chat text received: {0}'.format(chat_text))
log.info(f"Chat text received: {chat_text}")
r = re.search('(source+)(.*)', chat_text)

if (r is not None and r.group(1) == 'source'):
if r.group(2):
sources_dict[person_id] = r.group(2)
log.info('Sources set for {0} to {1}'.format(person_id, sources_dict[person_id]))
try:
sources = Source.create(person_id = person_id, fetch_from = sources_dict[person_id])
except IntegrityError:
sources = Source.get(person_id = person_id)
sources.fetch_from = sources_dict[person_id]
sources.save()
log.info(sources.person_id)
log.info(f'Sources set for {person_id} to {sources_dict[person_id]}')
with db.atomic() as txn:
try:
sources = Source.create(person_id=person_id, fetch_from=sources_dict[person_id])
log.debug(f'Inserted row id: {sources.person_id}')
except peewee.IntegrityError:
sources = Source.update(fetch_from=sources_dict[person_id]).where(person_id == person_id)
rows_updated = sources.execute()
log.info(f'Updated {rows_updated} rows')
txn.commit()
post_message(person_id, 'Sources set as {0}!'.format(r.group(2)))
else:
post_message(person_id, 'We need a comma separated list of subreddits! No subreddit, no news :-(')
if chat_text == '/stop':
log.debug('Added {0} to skip list'.format(chat_sender_id))
log.debug(f'Added {chat_sender_id} to skip list')
skip_list.append(chat_sender_id)
post_message(chat_sender_id, "Ok, we won't send you any more messages.")

if chat_text in ('/start', '/help'):
helptext = '''
Hi! This is a News Bot which fetches news from subreddits. Use "/source" to select a subreddit source.
Example "/source programming,games" fetches news from r/programming, r/games.
Use "/fetch for the bot to go ahead and fetch the news. At the moment, bot will fetch total of 5 posts from all sub reddits
I will have this configurable soon.
Use "/fetch for the bot to go ahead and fetch the news. At the moment, bot will fetch total of 5 posts from the selected subreddit.
'''
post_message(chat_sender_id, helptext)

if split_chat_text[0] == '/fetch' and (person_id not in skip_list):
post_message(person_id, 'Hang on, fetching your news..')

try:
sub_reddits = Source.get(person_id = person_id).fetch_from.strip()
summarized_news = get_latest_news(sub_reddits)
post_message(person_id, summarized_news)
except:
except peewee.DoesNotExist:
post_message(person_id, ERR_NO_SOURCE)

last_updated = req['update_id']
with open('last_updated.txt', 'w') as f:
f.write(str(last_updated))
States.last_updated = last_updated
log.debug(
'Updated last_updated to {0}'.format(last_updated))
f'Updated last_updated to {last_updated}')
f.close()
13 changes: 0 additions & 13 deletions source-code/chapter-7/exercise-1/docker-compose-adminer/Dockerfile

This file was deleted.

This file was deleted.

Loading