def save_creds(self): """ Store working instagram credentials (username and password) """ creds = secrets.get_var('instacreds:{}'.format(self.user_id)) if os.environ.get('PORT') in (None, ""): # Localhost if not creds: creds = dict() creds[self.username] = self.password secrets.set_var('instacreds:{}'.format(self.user_id), creds) else: connector = redis.from_url(os.environ.get('REDIS_URL')) creds: dict = connector.hgetall('instacreds:{}'.format( self.user_id)) if not creds: creds = dict() try: connector.delete('instacreds:{}'.format(self.user_id)) except: pass creds[self.username] = self.password connector.hmset('instacreds:{}'.format(self.user_id), creds) connector.close()
def get_all_creds(self): if os.environ.get('PORT') in (None, ""): creds = secrets.get_var('instacreds:{}'.format(self.user_id)) if not creds: return None hascreds = False for cred in creds: if creds.get(cred): hascreds = True break if not hascreds: return None return creds else: connector = redis.from_url(os.environ.get('REDIS_URL')) creds: dict = connector.hgetall('instacreds:{}'.format( self.user_id)) decoded = {} for key in creds: decoded[key.decode('utf-8')] = creds.get(key).decode('utf-8') hascreds = False for cred in decoded: if decoded.get(cred): hascreds = True break if not hascreds: return None return decoded
def error(update, context): """Log the error and send a telegram message to notify the developer.""" # Log the error before we do anything else, so we can see it even if something breaks. logger.error(msg="Exception while handling an update:", exc_info=context.error) # traceback.format_exception returns the usual python message about an exception, but as a # list of strings rather than a single string, so we have to join them together. tb_list = traceback.format_exception(None, context.error, context.error.__traceback__) tb = ''.join(tb_list) # Build the message with some markup and additional information about what happened. # You might need to add some logic to deal with messages longer than the 4096 character limit. message = ('<b>An exception was raised while handling an update</b>\n' '<pre>{}</pre>').format(html.escape(tb)) # Finally, send the message string = str(secrets.get_var('DEVS')).replace('[', '') string = string.replace(']', '') string = string.replace(' ', '') devs = list(string.split(',')) for dev in devs: context.bot.send_message(chat_id=dev, text=message, parse_mode=ParseMode.HTML)
def delete_creds(self): session = self.get_session() self.username = None self.password = None if os.environ.get('PORT') in (None, ""): creds = secrets.get_var(f'instacreds:{self.user_id}') try: del creds[session] except: pass secrets.set_var('instacreds:{}'.format(self.user_id), creds) newsession = None for key in list(creds.keys()): if key != session: newsession = key self.set_session(key) self.set_username(key) break applogger.debug(f'Set session: {newsession}') if not newsession: self.set_session(None) else: connector = redis.from_url(os.environ.get('REDIS_URL')) creds: dict = connector.hgetall('instacreds:{}'.format( self.user_id)) try: del creds[bytes(session, encoding='utf8')] except: pass try: connector.delete('instacreds:{}'.format(self.user_id)) except: pass connector.hmset('instacreds:{}'.format(self.user_id), creds) connector.close() newsession = None for key in list(creds.keys()): key = key.decode('utf-8') if key != session: newsession = key self.set_session(key) self.set_username(key) break if not newsession: self.set_session(None)
def get_session(self): if os.environ.get('PORT') in (None, ""): # Localhost session: str = secrets.get_var(f'instasession:{self.user_id}') else: connector = redis.from_url(os.environ.get('REDIS_URL')) session: str = connector.get(f'instasession:{self.user_id}') if session: session = session.decode('utf-8') connector.close() if not session: return None self.username = str(session) return str(session)
def set_message(user_id, message_id): if os.environ.get('PORT') not in (None, ""): spreadsheet = auth() sheet:Worksheet = spreadsheet.get_worksheet(3) row = find_by_username(user_id, sheet) if row: sheet.delete_row(row) sheet.append_row([user_id, message_id]) else: messages = secrets.get_var('MESSAGES') if not messages: secrets.set_var('MESSAGES', {str(user_id): message_id}) else: messages[str(user_id)] = message_id secrets.set_var('MESSAGES', messages)
def auth(): creds_string = secrets.get_var('GSPREAD_CREDS') if creds_string == None: # use creds to create a client to interact with the Google Drive API scope = [ 'https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/drive.file', 'https://www.googleapis.com/auth/drive'] # CREDENTIALS HAVE NOT BEEN INITIALIZED BEFORE client_secret = os.environ.get('GCLIENT_SECRET') if os.environ.get('PORT') in (None, ""): # CODE RUNNING LOCALLY applogger.debug('DATABASE: Resorted to local JSON file') with open('ffinstabot/config/client_secret.json') as json_file: client_secret_dict = json.load(json_file) else: # CODE RUNNING ON SERVER client_secret_dict = json.loads(client_secret) creds = ServiceAccountCredentials.from_json_keyfile_dict( client_secret_dict, scope) creds_string = jsonpickle.encode(creds) if os.environ.get('PORT') in (None, ""): secrets.set_var('GSPREAD_CREDS', creds_string) creds = jsonpickle.decode(creds_string) client = gspread.authorize(creds) # IF NO SPREADSHEET ENV VARIABLE HAS BEEN SET, SET UP NEW SPREADSHEET if secrets.get_var('SPREADSHEET') == None: spreadsheet = set_sheet(client) return spreadsheet else: SPREADSHEET = secrets.get_var('SPREADSHEET') spreadsheet = client.open_by_key(SPREADSHEET) return spreadsheet
def get_message(user_id): if os.environ.get('PORT') not in (None, ""): spreadsheet = auth() sheet:Worksheet = spreadsheet.get_worksheet(3) row_id = find_by_username(user_id, sheet) if not row_id: return None row = get_rows(sheet)[row_id-1] message = int(row[1]) return message else: messages = secrets.get_var('MESSAGES') if not messages: return None else: return messages.get(str(user_id))
def report_error(self, error=None, send_screenshot=False, screenshot_name=''): string = str(secrets.get_var('DEVS')).replace('[', '') string = string.replace(']', '') string = string.replace(' ', '') devs = list(string.split(',')) for dev in devs: if send_screenshot: self.send_photo( chat_id=int(dev), photo=open('{}.png'.format(screenshot_name), 'rb'), caption='There was an error with the FFInstaBot: \n{}'. format(error)) else: self.send_message( chat_id=int(dev), text='There was an error with the FFInstaBot: \n{}'.format( error))
def get_notification(user_id:int) -> Optional['Notification']: # TODO Change if you implement the scheduler """ Retrive last notification from GSheet Database Args: user_id (int): Telegram user ID to match Returns: Notification or None: Notification object (or None if no record is found) """ spreadsheet:Spreadsheet = auth() sheet:Worksheet = spreadsheet.get_worksheet(2) notis = get_all_notifications(user_id, sheet) if not notis: return None for noti in notis.keys(): if noti == secrets.get_var(f'instasession:{user_id}'): return notis.get(noti) return None
def set_notification(user_id:int, notification:'Notification'): """ Insert Notification inside the GSheet Database Args: user_id (int): Telegram user ID notification (Notification): Notification to insert """ spreadsheet:Spreadsheet = auth() sheet:Worksheet = spreadsheet.get_worksheet(2) row = find_by_username(str(user_id), sheet) notifications = dict() if row is not None: notifications = get_all_notifications(user_id, sheet) sheet.delete_row(row) # Add New Notification notifications[secrets.get_var(f'instasession:{user_id}')] = notification.to_dict() sheet.append_row([str(user_id), notifications]) log(datetime.utcnow(), user_id, 'SET NOTIFICATION')
def set_sheet(client:Client): """ Setup spreadsheet database if none exists yet. Will save the spreadsheet ID to Heroku Env Variables or to secrets.json file The service email you created throught the Google API will create the new spreadsheet and share it with the email you indicated in the GDRIVE_EMAIL enviroment variable. You will find the spreadsheet database in your google drive shared folder. Don't change the order of the worksheets or it will break the code. :param client: GSpread client to utilize :type client: Client :return: The newly created spreadsheet :rtype: Spreadsheet """ # CREATE SPREADSHEET spreadsheet:Spreadsheet = client.create('FFInstaBot') secrets.set_var('SPREADSHEET', spreadsheet.id) settings = spreadsheet.add_worksheet(title='Settings', rows=6, cols=2) settings.append_row(['USER ID', 'SETTINGS']) follows = spreadsheet.add_worksheet(title='Follows', rows=50, cols=1) follows.append_row(['FOLLOWS']) notifications = spreadsheet.add_worksheet(title='Notifications', rows=50, cols=2) notifications.append_row(['USER ID', 'LAST NOTIFICATION']) messages = spreadsheet.add_worksheet(title='Messages', rows=10, cols=2) messages.append_row(['USER ID', 'MESSAGE ID']) # CREATE LOGS SHEET logs = spreadsheet.add_worksheet(title="Logs", rows="500", cols="3") logs.append_row(["TIMESTAMP", "USER ID", "ACTION"]) # DELETE PRE-EXISTING SHEET sheet = spreadsheet.get_worksheet(0) spreadsheet.del_worksheet(sheet) # SHARE SPREADSHEET spreadsheet.share(value=secrets.get_var('GDRIVE_EMAIL'), perm_type="user", role="owner") return spreadsheet
def get_creds(self): session = self.get_session() if os.environ.get('PORT') in (None, ""): creds = secrets.get_var('instacreds:{}'.format(self.user_id)) if not creds: return False else: self.set_username(session if isinstance(session, str) else list(creds.keys())[0]) if creds.get(self.username): self.set_password(creds.get(self.username)) return True else: return False else: connector = redis.from_url(os.environ.get('REDIS_URL')) creds: dict = connector.hgetall('instacreds:{}'.format( self.user_id)) connector.close() if not creds or list(creds.keys()) == []: # No credentials return False else: self.set_username(session if isinstance(session, str) else list(creds.keys())[0].decode('utf-8')) applogger.debug(self.username) if creds.get(bytes(self.username, encoding='utf8')): self.set_password( creds.get(bytes(self.username, encoding='utf8')).decode('utf-8')) print( f'{self.username} {type(self.username)} : {self.password} {type(self.password)}' ) return True else: return False
import os, redis from ffinstabot.config import secrets from rq import Worker, Queue, Connection listen = ['high', 'default', 'low'] redis_url = secrets.get_var('REDISTOGO_URL', default='redis://localhost:6379') conn = redis.from_url(redis_url) if __name__ == '__main__': with Connection(conn): worker = Worker(map(Queue, listen)) worker.work()
driver.save_screenshot('error.png') bot.report_error('instaclient.__find_element() error.', send_screenshot=True, screenshot_name='error') os.remove('error.png') LOCALHOST = True queue = None if os.environ.get('PORT') not in (None, ""): # Code running locally LOCALHOST = False queue = Queue(connection=conn) # Initialize Bot from ffinstabot.config import secrets BOT_TOKEN = secrets.get_var('BOT_TOKEN') URL = secrets.get_var('SERVER_APP_DOMAIN') PORT = int(os.environ.get('PORT', 5000)) from ffinstabot.bot import telebot # set connection pool size for bot request = Request(con_pool_size=8) defaults = Defaults(parse_mode=ParseMode.HTML, run_async=True) q = mq.MessageQueue(all_burst_limit=3, all_time_limit_ms=3000) telegram_bot = MQBot(BOT_TOKEN, request=request, mqueue=q, defaults=defaults) updater = Updater(bot=telegram_bot, use_context=True) applogger.debug(f'Started bot of id: {telegram_bot.id}') # SET UP BOT COMMAND HANDLERS telebot.setup(updater)