├── runtime.txt ├── templates ├── profile.css ├── result.html ├── __init__.py ├── attachment.py ├── quick_replies.py ├── text.py ├── button.py ├── generic.py ├── profile.html └── receipt.py ├── static ├── endchat.jpg ├── endchat1.jpg ├── gifs │ ├── giphy.gif │ ├── giphy-downsized.gif │ ├── giphy-downsized (1).gif │ └── giphy-downsized (2).gif └── startchat.jpg ├── DB_Wrappers ├── __init__.py ├── WaitingList.py ├── ActiveChats.py └── Users.py ├── Procfile ├── manage.py ├── modules ├── __init__.py ├── image.py ├── gifs.py ├── interrupts.py ├── quick_replies.py ├── postback.py ├── campaign.py ├── critical_operations.py ├── setup.py ├── debug.py ├── gamification.py ├── subscription.py ├── alias.py ├── startChat.py ├── utilities.py └── endChat.py ├── requirements.txt ├── config.py ├── analytics.py ├── .gitignore ├── LICENSE ├── models.py ├── README.md └── app.py /runtime.txt: -------------------------------------------------------------------------------- 1 | python-2.7.14 2 | -------------------------------------------------------------------------------- /templates/profile.css: -------------------------------------------------------------------------------- 1 | .container-fluid{ 2 | background: #f5d9d5; 3 | } -------------------------------------------------------------------------------- /static/endchat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayukh18/BlindChat/HEAD/static/endchat.jpg -------------------------------------------------------------------------------- /static/endchat1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayukh18/BlindChat/HEAD/static/endchat1.jpg -------------------------------------------------------------------------------- /static/gifs/giphy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayukh18/BlindChat/HEAD/static/gifs/giphy.gif -------------------------------------------------------------------------------- /static/startchat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayukh18/BlindChat/HEAD/static/startchat.jpg -------------------------------------------------------------------------------- /static/gifs/giphy-downsized.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayukh18/BlindChat/HEAD/static/gifs/giphy-downsized.gif -------------------------------------------------------------------------------- /static/gifs/giphy-downsized (1).gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayukh18/BlindChat/HEAD/static/gifs/giphy-downsized (1).gif -------------------------------------------------------------------------------- /static/gifs/giphy-downsized (2).gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayukh18/BlindChat/HEAD/static/gifs/giphy-downsized (2).gif -------------------------------------------------------------------------------- /DB_Wrappers/__init__.py: -------------------------------------------------------------------------------- 1 | from Users import UsersDB 2 | from ActiveChats import ActiveChatsDB 3 | from WaitingList import WaitingListDB -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: python manage.py runserver --host 0.0.0.0 --port ${PORT} 2 | init: python manage.py db init 3 | migrate: python manage.py db migrate 4 | upgrade: python manage.py db upgrade 5 | -------------------------------------------------------------------------------- /templates/result.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 |

INTERESTS AND BIO SAVED

10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | from flask_script import Manager 2 | from flask_migrate import Migrate, MigrateCommand 3 | 4 | from app import app, db, setup_all 5 | 6 | migrate = Migrate(app, db) 7 | 8 | manager = Manager(app) 9 | manager.add_command('db', MigrateCommand) 10 | 11 | 12 | if __name__ == '__main__': 13 | setup_all() 14 | manager.run() -------------------------------------------------------------------------------- /modules/__init__.py: -------------------------------------------------------------------------------- 1 | from postback import handle_postback 2 | from utilities import send_message, send_help, isGreeting, handle_greetings 3 | from interrupts import Interrupts 4 | from quick_replies import handle_quick_reply 5 | from image import handle_image 6 | from setup import setup_all 7 | from debug import handle_debug 8 | from gamification import Game -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | alembic==0.9.2 2 | Flask==0.10.1 3 | Flask-Migrate==2.0.4 4 | Flask-Script==2.0.5 5 | Flask-SQLAlchemy==2.2 6 | gunicorn==19.6.0 7 | html5lib==1.0b8 8 | Jinja2==2.8 9 | jsonschema==2.5.1 10 | requests==2.17.3 11 | requests-cache==0.4.13 12 | simplejson==3.10.0 13 | six==1.10.0 14 | SQLAlchemy==1.1.10 15 | sqlalchemy-migrate==0.11.0 16 | psycopg2==2.7.1 -------------------------------------------------------------------------------- /templates/__init__.py: -------------------------------------------------------------------------------- 1 | from text import TextTemplate 2 | from generic import GenericTemplate 3 | from button import ButtonTemplate 4 | from quick_replies import add_quick_reply 5 | from attachment import AttachmentTemplate 6 | 7 | __all__ = [ 8 | 'TextTemplate', 9 | 'GenericTemplate', 10 | 'ButtonTemplate', 11 | 'add_quick_reply', 12 | 'AttachmentTemplate' 13 | ] -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | import os 2 | basedir = os.path.abspath(os.path.dirname(__file__)) 3 | 4 | # Database setup 5 | SQLALCHEMY_DATABASE_URI = 'YOUR_DATABASE_URI' 6 | SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository') 7 | SQLALCHEMY_TRACK_MODIFICATIONS = False 8 | 9 | # Facebook 10 | ACCESS_TOKEN = 'YOUR_FACEBOOK_APP_ACCESS_TOKEN' 11 | VERIFY_TOKEN = 'FACEBOOK_APP_VERIFY_TOKEN' 12 | 13 | # App url 14 | APP_URL = 'APP_URL' 15 | 16 | # For analytics purposes 17 | CHATMETRICS_TOKEN = 'CHATMETRICS_TOKEN' 18 | 19 | # For debugging 20 | PAGE_ID = 'FACEBOOK_PAGE_PSID' 21 | ADMIN_ID = "ADMIN_PSID" 22 | 23 | -------------------------------------------------------------------------------- /analytics.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import config 4 | import requests 5 | 6 | class Analytics: 7 | def __init__(self): 8 | self.token = os.environ.get('CHATMETRICS_TOKEN', config.CHATMETRICS_TOKEN) 9 | 10 | def record(self, entry): 11 | try: 12 | data = {"object":"page"} 13 | data["entry"] = entry 14 | r = requests.post(url="https://api.chatbottle.co/v2/updates/messenger/"+self.token+"/", data=json.dumps(data)) 15 | print("analytics result", r.json(), data) 16 | except Exception, e: 17 | print("ANALYTICS ERROR", str(e)) 18 | 19 | 20 | -------------------------------------------------------------------------------- /modules/image.py: -------------------------------------------------------------------------------- 1 | from templates import AttachmentTemplate, TextTemplate 2 | from app import activechatsdb 3 | from utilities import send_message 4 | 5 | def handle_image(sender, url): 6 | try: 7 | partner = activechatsdb.get_partner(sender) 8 | alias = activechatsdb.get_alias(sender) 9 | message = TextTemplate(text=alias+" has sent you an image.") 10 | send_message(message.get_message(), id=partner) 11 | message = AttachmentTemplate(url=url, type='image') 12 | send_message(message.get_message(), id=partner) 13 | #dummy1 14 | except Exception, e: 15 | print("IMAGE ERROR", str(e)) -------------------------------------------------------------------------------- /modules/gifs.py: -------------------------------------------------------------------------------- 1 | _male_start_hi = ['https://media.giphy.com/media/dzaUX7CAG0Ihi/giphy-downsized.gif', 2 | 'https://media.giphy.com/media/oJiCqvIqPZE3u/giphy.gif'] 3 | 4 | _female_start_hi = ['https://media.giphy.com/media/a1QLZUUtCcgyA/giphy-downsized.gif', 5 | 'https://media.giphy.com/media/EPJZhOrStSpz2/giphy-downsized.gif'] 6 | 7 | import random 8 | def get_start_hi(gender): 9 | if gender == "male": 10 | #return random.choice(_male_start_hi) 11 | return _male_start_hi[1] 12 | elif gender == "female": 13 | #return random.choice(_female_start_hi) 14 | return _female_start_hi[1] 15 | else: 16 | return random.choice(_male_start_hi) -------------------------------------------------------------------------------- /templates/attachment.py: -------------------------------------------------------------------------------- 1 | template = { 2 | 'template_type': 'attachment', 3 | 'value': { 4 | 'attachment': { 5 | 'type': 'file', 6 | 'payload': { 7 | 'url': '' 8 | } 9 | } 10 | } 11 | } 12 | 13 | class AttachmentTemplate: 14 | def __init__(self, url='', type='file'): 15 | self.template = template['value'] 16 | self.url = url 17 | self.type = type 18 | def set_url(self, url=''): 19 | self.url = url 20 | def set_type(self, type=''): 21 | # image / audio / video / file 22 | self.type = type 23 | def get_message(self): 24 | self.template['attachment']['payload']['url'] = self.url 25 | self.template['attachment']['type'] = self.type 26 | return self.template 27 | -------------------------------------------------------------------------------- /templates/quick_replies.py: -------------------------------------------------------------------------------- 1 | from copy import deepcopy as copy 2 | 3 | QUICK_REPLIES_LIMIT = 11 4 | TITLE_CHARACTER_LIMIT = 20 5 | PAYLOAD_CHARACTER_LIMIT = 1000 6 | 7 | def add_quick_reply(message, title='', payload=''): 8 | message_with_quick_reply = copy(message) 9 | if 'quick_replies' not in message_with_quick_reply: 10 | message_with_quick_reply['quick_replies'] = [] 11 | if len(message_with_quick_reply['quick_replies']) < QUICK_REPLIES_LIMIT: 12 | quick_reply = {} 13 | # TODO: location + image_url 14 | quick_reply['content_type'] = 'text' 15 | quick_reply['title'] = title[:TITLE_CHARACTER_LIMIT] 16 | quick_reply['payload'] = payload[:PAYLOAD_CHARACTER_LIMIT] 17 | message_with_quick_reply['quick_replies'].append(quick_reply) 18 | return message_with_quick_reply 19 | -------------------------------------------------------------------------------- /templates/text.py: -------------------------------------------------------------------------------- 1 | TEXT_CHARACTER_LIMIT = 640 2 | 3 | template = { 4 | 'template_type': 'text', 5 | 'value': { 6 | 'text': '' 7 | } 8 | } 9 | 10 | class TextTemplate: 11 | def __init__(self, text='', post_text='', limit=TEXT_CHARACTER_LIMIT): 12 | self.template = template['value'] 13 | self.text = text 14 | self.post_text = post_text 15 | self.limit = limit 16 | def set_text(self, text=''): 17 | self.text = text 18 | def set_post_text(self, post_text=''): 19 | self.post_text = post_text 20 | def set_limit(self, limit=TEXT_CHARACTER_LIMIT): 21 | self.limit = limit 22 | def get_message(self): 23 | n = self.limit - len(self.post_text) 24 | if n > len(self.text): 25 | self.template['text'] = self.text + self.post_text 26 | else: 27 | # append ellipsis (length = 3) 28 | self.template['text'] = self.text[:n-3].rsplit(' ', 1)[0] + '...' + self.post_text 29 | return self.template 30 | -------------------------------------------------------------------------------- /modules/interrupts.py: -------------------------------------------------------------------------------- 1 | from utilities import send_help, send_newchat_prompt, send_profile_prompt 2 | from critical_operations import restart_bot, execute_exit 3 | 4 | 5 | 6 | class Interrupts: 7 | 8 | def __init__(self): 9 | self.commands = ["quit", "exit", "restart", "help", "start", "startchat", "profile"] 10 | 11 | def isValidCommand(self, command): 12 | text = command.lower().replace(" ", "") 13 | if text in self.commands: 14 | return True 15 | return False 16 | 17 | def handleCommand(self, command, sender): 18 | text = command.lower().replace(" ", "") 19 | print("INTERRUPT", text) 20 | if text == "help": 21 | send_help(sender) 22 | elif text == "restart": 23 | restart_bot(sender) 24 | elif text == "quit" or text == "exit": 25 | execute_exit(id = sender) 26 | elif text == "start" or text == "startchat": 27 | send_newchat_prompt(id=sender) 28 | elif text == "profile": 29 | send_profile_prompt(id=sender) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | .idea/ 7 | migrations/ 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | env/ 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *,cover 49 | .hypothesis/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | 58 | # Sphinx documentation 59 | docs/_build/ 60 | 61 | # PyBuilder 62 | target/ 63 | 64 | #Ipython Notebook 65 | .ipynb_checkpoints 66 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Mayukh Bhattacharyya 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /modules/quick_replies.py: -------------------------------------------------------------------------------- 1 | from startChat import startChat 2 | from endChat import share_profile 3 | from subscription import handle_subscribe_payload 4 | from utilities import * 5 | from app import usersdb 6 | import json 7 | 8 | def handle_quick_reply(sender, payload): 9 | try: 10 | usersdb.setPauseStatus(id=sender, status=False) 11 | print("1") 12 | send_paused_messages(id=sender) 13 | except Exception, e: 14 | print("QUICK_REPLY_ERROR", str(e)) 15 | 16 | payload = json.loads(payload) 17 | print("QUICKREPLYPAYLOAD", payload) 18 | 19 | if payload["keyword"] == "newchat": 20 | if payload["ans"] == "y": 21 | send_interest_menu(sender=sender) 22 | if payload["ans"] == "n": 23 | message = TextTemplate(text="Cool. When you come back use the menu to look for a new chat") 24 | send_message(message=message.get_message(), id = sender) 25 | if payload["ans"] == "p": 26 | send_profile_prompt(id=sender) 27 | 28 | elif payload["keyword"] == "interest": 29 | print("interest selected") 30 | startChat(sender=sender,interest=payload["interest"]) 31 | 32 | elif payload["keyword"] == "profile_share": 33 | share_profile(sender, payload=payload) 34 | 35 | elif payload["keyword"] == "subscribe": 36 | handle_subscribe_payload(id=sender, payload=payload) -------------------------------------------------------------------------------- /templates/button.py: -------------------------------------------------------------------------------- 1 | from copy import deepcopy as copy 2 | 3 | from text import TextTemplate 4 | TextTemplate.get_text = lambda self: self.get_message()['text'] 5 | 6 | TEXT_CHARACTER_LIMIT = 320 7 | 8 | template = { 9 | 'template_type': 'button', 10 | 'value': { 11 | 'attachment': { 12 | 'type': 'template', 13 | 'payload': { 14 | 'template_type': 'button', 15 | 'text': '', 16 | 'buttons': [] 17 | } 18 | } 19 | } 20 | } 21 | 22 | class ButtonTemplate: 23 | def __init__(self, text=''): 24 | self.template = copy(template['value']) 25 | self.text = text 26 | def add_web_url(self, title='', url=''): 27 | web_url_button = {} 28 | web_url_button['type'] = 'web_url' 29 | web_url_button['title'] = title 30 | web_url_button['url'] = url 31 | self.template['attachment']['payload']['buttons'].append(web_url_button) 32 | def add_postback(self, title='', payload=''): 33 | postback_button = {} 34 | postback_button['type'] = 'postback' 35 | postback_button['title'] = title 36 | postback_button['payload'] = payload 37 | self.template['attachment']['payload']['buttons'].append(postback_button) 38 | def set_text(self, text=''): 39 | self.text = text 40 | def get_message(self): 41 | self.template['attachment']['payload']['text'] = self.text 42 | return self.template 43 | -------------------------------------------------------------------------------- /DB_Wrappers/WaitingList.py: -------------------------------------------------------------------------------- 1 | from models import WaitingListUser 2 | 3 | class WaitingListDB(): 4 | def __init__(self, db): 5 | self.db = db 6 | 7 | def get_match(self, gender, interest): 8 | waitlist = WaitingListUser.query.all() 9 | print("WAITLIST", waitlist, gender, interest) 10 | for i in range(len(waitlist)): 11 | user = waitlist[i] 12 | print("user waiting", user.gender, user.interest) 13 | if user.interest == gender or user.interest == "random": 14 | print("IN 1") 15 | if user.gender == interest or interest == "random": 16 | print("IN 2") 17 | Id = user.id 18 | self.db.session.delete(user) 19 | self.db.session.commit() 20 | return Id 21 | print("NO MATCH FOUND") 22 | return None 23 | 24 | def enlist(self, id, gender, interest): 25 | user = WaitingListUser(id = id, gender=gender, interest=interest) 26 | self.db.session.add(user) 27 | self.db.session.commit() 28 | 29 | def isWaiting(self, id): 30 | user = WaitingListUser.query.get(id) 31 | if user is None: 32 | return False 33 | return True 34 | 35 | def delist(self, id): 36 | try: 37 | user = WaitingListUser.query.get(id) 38 | self.db.session.delete(user) 39 | self.db.session.commit() 40 | except Exception, e: 41 | print("Not in waitlist", str(e)) -------------------------------------------------------------------------------- /modules/postback.py: -------------------------------------------------------------------------------- 1 | from templates import TextTemplate 2 | from utilities import send_help, send_message, send_newchat_prompt 3 | from endChat import endChat, share_profile 4 | from interrupts import Interrupts 5 | import json 6 | 7 | valid_payloads = [ 8 | "restart", 9 | "help", 10 | "quit", 11 | "exit", 12 | "getstarted" 13 | ] 14 | 15 | interrupts = Interrupts() 16 | 17 | def handle_postback(payload, sender): 18 | 19 | if payload not in valid_payloads and json.loads(payload)["keyword"] not in valid_payloads: 20 | message = TextTemplate(text="Not sure if this is a valid command") 21 | send_message(message.get_message(), id=sender) 22 | 23 | elif payload == "restart": 24 | interrupts.handleCommand(command="restart", sender=sender) 25 | elif payload == "help": 26 | send_help(sender = sender) 27 | elif payload == "quit": 28 | interrupts.handleCommand(command="quit", sender=sender) 29 | elif payload == "getstarted": 30 | print("GET STARTED DETECTED") 31 | message = TextTemplate("Hello there, a big welcome to BlindChat. Chat with people all over the "+ 32 | "world anonymously. Share your profile only when you want to.\n\n"+ 33 | "We are adding cool new features every single day, so keep "+ 34 | "on exploring. Cheers!\n\nAnd by the way, when in need, type"+ 35 | " \"help\" to see the list of available commands") 36 | send_message(message.get_message(), id=sender) 37 | send_newchat_prompt(id=sender) 38 | -------------------------------------------------------------------------------- /templates/generic.py: -------------------------------------------------------------------------------- 1 | from copy import deepcopy as copy 2 | 3 | from button import ButtonTemplate 4 | ButtonTemplate.get_buttons = lambda self: self.template['attachment']['payload']['buttons'] 5 | 6 | TITLE_CHARACTER_LIMIT = 80 7 | SUBTITLE_CHARACTER_LIMIT = 80 8 | BUTTON_TITLE_CHARACTER_LIMIT = 20 9 | BUTTON_LIMIT = 3 10 | ELEMENTS_LIMIT = 10 11 | 12 | template = { 13 | 'template_type': 'generic', 14 | 'value': { 15 | 'attachment': { 16 | 'type': 'template', 17 | 'payload': { 18 | 'template_type': 'generic', 19 | 'elements': [] 20 | } 21 | } 22 | } 23 | } 24 | 25 | class GenericTemplate: 26 | def __init__(self): 27 | self.template = copy(template['value']) 28 | self.elements = [] 29 | def add_element(self, title='', item_url='', image_url='', subtitle='', buttons=[]): 30 | element = {} 31 | element['title'] = title[:TITLE_CHARACTER_LIMIT] 32 | if item_url != '': 33 | element['item_url'] = item_url 34 | element['image_url'] = image_url 35 | if subtitle != '': 36 | element['subtitle'] = subtitle[:SUBTITLE_CHARACTER_LIMIT] 37 | for button in buttons: 38 | button['title'] = button['title'][:BUTTON_TITLE_CHARACTER_LIMIT] 39 | if len(buttons) > 0: 40 | element['buttons'] = buttons[:BUTTON_LIMIT] 41 | if len(self.elements) < ELEMENTS_LIMIT: 42 | self.elements.append(element) 43 | def get_message(self): 44 | self.template['attachment']['payload']['elements'] = self.elements 45 | return self.template 46 | -------------------------------------------------------------------------------- /modules/campaign.py: -------------------------------------------------------------------------------- 1 | from models import User 2 | from templates import TextTemplate 3 | from utilities import send_message 4 | 5 | def send_campaign(): 6 | message = TextTemplate(text="NEW FEATURE: SUBSCRIPTIONS \n\n"+ 7 | "Hi there, this week a new feature is coming out and that is SUBSCRIPTIONS.\n\n"+ 8 | "How it works: When someone gets into the Waiting List due to non availability of "+ 9 | "partners, we will send out a message to our subscribed users. For example, if you "+ 10 | "subscribe for women, we will notify you when a woman is looking for a partner even "+ 11 | "when you are not active and hence you'll gain the chance to chat if you are free. \n\n"+ 12 | "The feature will be made available to every user after one month but some users will "+ 13 | "be given access to it within 1-2 days. To be eligible for getting access, LIKE our "+ 14 | "page and leave a REVIEW on our page within 36 hours. Just to emphasize, please "+ 15 | "complete both to be eligible. \n\nIf you have any question, post it on our page. "+ 16 | "We'll guide you, but make it within the 36 hours because after that, the feature will be out.") 17 | print("IN CAMPAIGN") 18 | message = TextTemplate(text="FUCKING TEST") 19 | #users = User.query.all() 20 | #for user in users: 21 | # id = user.id 22 | #send_message(message, id=id) 23 | users = ["1708022462556195", "1145959985508112"] 24 | for user in users: 25 | send_message(message, id=user) 26 | 27 | -------------------------------------------------------------------------------- /DB_Wrappers/ActiveChats.py: -------------------------------------------------------------------------------- 1 | from models import ActiveChatsUser 2 | 3 | class ActiveChatsDB: 4 | def __init__(self, db): 5 | self.db = db 6 | 7 | def isActive(self, user): 8 | u = ActiveChatsUser.query.get(user) 9 | if u != None: 10 | return True 11 | else: 12 | return False 13 | 14 | def get_partner(self, user): 15 | user = ActiveChatsUser.query.get(user) 16 | return user.partner 17 | 18 | def create_new_chat(self, user1, user2): 19 | u1 = ActiveChatsUser(id=user1, partner=user2) 20 | u2 = ActiveChatsUser(id=user2, partner=user1) 21 | 22 | try: 23 | self.db.session.add(u1) 24 | except: 25 | self.db.session.delete(u1) 26 | self.db.session.add(u1) 27 | 28 | try: 29 | self.db.session.add(u2) 30 | except: 31 | self.db.session.delete(u2) 32 | self.db.session.add(u2) 33 | 34 | self.db.session.commit() 35 | 36 | def delete_chat_entries(self, user): 37 | partner = self.get_partner(user=user) 38 | user1 = ActiveChatsUser.query.get(user) 39 | user2 = ActiveChatsUser.query.get(partner) 40 | self.db.session.delete(user1) 41 | self.db.session.delete(user2) 42 | self.db.session.commit() 43 | 44 | def get_alias(self, user): 45 | u = ActiveChatsUser.query.get(user) 46 | return u.alias 47 | 48 | def set_alias(self, user, alias): 49 | u = ActiveChatsUser.query.get(user) 50 | u.alias = alias 51 | self.db.session.commit() 52 | 53 | def clear_data(self, user): 54 | user = ActiveChatsUser.query.get(user) 55 | if user != None: 56 | self.db.session.delete(user) 57 | self.db.session.commit() -------------------------------------------------------------------------------- /modules/critical_operations.py: -------------------------------------------------------------------------------- 1 | from app import waitlistdb, activechatsdb 2 | from templates import TextTemplate 3 | from utilities import send_message, show_typing, send_newchat_prompt 4 | from endChat import endChat 5 | 6 | def restart_bot(id): 7 | show_typing(id=id, duration=1) 8 | print("here") 9 | if activechatsdb.isActive(id): 10 | print("ACTIVE", id) 11 | partner = activechatsdb.get_partner(id) 12 | activechatsdb.delete_chat_entries(id) 13 | message = TextTemplate(text="Your active chat has been ended.") 14 | send_message(message=message.get_message(), id=id) 15 | message = TextTemplate(text="Your active chat has been ended from the other side.") 16 | send_message(message=message.get_message(), id=partner) 17 | 18 | show_typing(id=partner, duration=1) 19 | send_newchat_prompt(id=partner) 20 | 21 | 22 | if waitlistdb.isWaiting(id): 23 | waitlistdb.delist(id) 24 | message = TextTemplate(text="You have been removed from the waitlist") 25 | send_message(message=message.get_message(), id=id) 26 | 27 | show_typing(id=id, duration=1) 28 | send_newchat_prompt(id=id) 29 | 30 | 31 | def execute_exit(id): 32 | show_typing(id=id, duration=1) 33 | print("EXECUTING EXIT") 34 | 35 | if activechatsdb.isActive(id): 36 | endChat(id) 37 | 38 | elif waitlistdb.isWaiting(id): 39 | waitlistdb.delist(id) 40 | message = TextTemplate(text="You have been removed from the waitlist") 41 | send_message(message=message.get_message(), id=id) 42 | 43 | show_typing(id=id, duration=1) 44 | send_newchat_prompt(id=id) 45 | 46 | else: 47 | message = TextTemplate(text="You are not in an active chat or in the waitlist. Type \"start\" to start a new chat") 48 | send_message(message=message.get_message(), id=id) 49 | 50 | 51 | -------------------------------------------------------------------------------- /modules/setup.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import config 3 | import os 4 | 5 | ACCESS_TOKEN = os.environ.get('ACCESS_TOKEN', config.ACCESS_TOKEN) 6 | APP_URL = os.environ.get('APP_URL', config.APP_URL) 7 | URL = "https://graph.facebook.com/v2.6/me/messenger_profile" 8 | 9 | 10 | def setup_menu(): 11 | 12 | data = { 13 | "persistent_menu":[ 14 | { 15 | "locale":"default", 16 | "call_to_actions":[ 17 | { 18 | "title": "Help", 19 | "type": "postback", 20 | "payload": "help" 21 | }, 22 | { 23 | "title": "Quit Chat", 24 | "type": "postback", 25 | "payload": "quit" 26 | }, 27 | { 28 | "title": "Restart Bot", 29 | "type": "postback", 30 | "payload": "restart" 31 | } 32 | ] 33 | } 34 | ] 35 | } 36 | r = requests.post(url=URL, params={'access_token': ACCESS_TOKEN}, 37 | json=data) 38 | 39 | def setup_getStarted(): 40 | data = { 41 | "get_started":{ 42 | "payload": "getstarted" 43 | } 44 | } 45 | r = requests.post(url=URL, params={'access_token': ACCESS_TOKEN}, 46 | json=data) 47 | 48 | def setup_greeting(): 49 | data = { 50 | "greeting":[ 51 | { 52 | "locale":"default", 53 | "text":"Get Started to chat anonymously" 54 | } 55 | ] 56 | } 57 | r = requests.post(url=URL, params={'access_token': ACCESS_TOKEN}, 58 | json=data) 59 | 60 | def setup_whitelist(): 61 | data = { 62 | "whitelisted_domains":[ 63 | APP_URL 64 | ] 65 | } 66 | r = requests.post(url=URL, params={'access_token': ACCESS_TOKEN}, 67 | json=data) 68 | 69 | def setup_all(): 70 | setup_menu() 71 | setup_getStarted() 72 | setup_greeting() 73 | setup_whitelist() -------------------------------------------------------------------------------- /modules/debug.py: -------------------------------------------------------------------------------- 1 | from models import User, WaitingListUser, ActiveChatsUser, db 2 | from campaign import send_campaign 3 | from utilities import send_message 4 | from templates import TextTemplate 5 | import os 6 | import config 7 | 8 | APP_URL = os.environ.get('APP_URL', config.APP_URL) 9 | 10 | def log_waitlisted_users(): 11 | waitlist = WaitingListUser.query.all() 12 | i=0 13 | print("WAITLIST IS BELOW") 14 | try: 15 | for user in waitlist: 16 | id = user.id 17 | u = User.query.get(id) 18 | print(i, u.name, user.gender, user.interest) 19 | i = i+1 20 | except Exception, e: 21 | print("LOG WAITLIST ERROR", e) 22 | 23 | def update_users(): 24 | for u in User.query.all(): 25 | u.status = False 26 | u.messages = "" 27 | db.session.commit() 28 | 29 | def send_emoticon(id): 30 | happy = u'\u2B50' 31 | print("EMOTICON") 32 | message = TextTemplate(text="Hi "+happy) 33 | send_message(message.get_message(), id=id) 34 | print("EMOTICON 1") 35 | 36 | def handle_debug(text, id): 37 | if text[3:] == "waitlist": 38 | log_waitlisted_users() 39 | elif text[3:] == "update": 40 | update_users() 41 | elif text[3:] == "campaign": 42 | send_campaign() 43 | elif text[3:] == "emoticon": 44 | send_emoticon(id) 45 | elif text[3:] == "webview": 46 | message = { 47 | "attachment":{ 48 | "type":"template", 49 | "payload":{ 50 | "template_type":"button", 51 | "text":"Test Webview?", 52 | "buttons":[ 53 | { 54 | "type":"web_url", 55 | "url":APP_URL+"webview/", 56 | "title":"Show page", 57 | "webview_height_ratio": "compact" 58 | } 59 | ] 60 | } 61 | } 62 | } 63 | send_message(message=message, id=id) 64 | 65 | 66 | -------------------------------------------------------------------------------- /models.py: -------------------------------------------------------------------------------- 1 | from app import db 2 | 3 | 4 | class User(db.Model): 5 | id = db.Column(db.String(64), primary_key=True) 6 | name = db.Column(db.String(64)) 7 | gender = db.Column(db.String(10)) 8 | first_name = db.Column(db.String(64)) 9 | pic_url = db.Column(db.String(250)) 10 | status = db.Column(db.Boolean) # pause status-- True if messages are paused, may be at a quick reply 11 | messages = db.Column(db.String(2000)) # upto two messages stored while convo is paused 12 | subscription = db.Column(db.String(10)) 13 | interests = db.Column(db.String(100)) 14 | bio = db.Column(db.String(100)) 15 | level = db.Column(db.Integer) 16 | 17 | def __init__(self, id): 18 | self.id = id 19 | self.status = False 20 | self.messages = "" 21 | 22 | def add_details(self, name, first_name, gender, pic_url): 23 | if name is not None: 24 | self.name = name 25 | if gender is not None: 26 | self.gender = gender 27 | if first_name is not None: 28 | self.first_name = first_name 29 | if pic_url is not None: 30 | self.pic_url = pic_url 31 | 32 | def setStatus(self, status): 33 | self.status = status 34 | 35 | def getStatus(self): 36 | return self.status 37 | 38 | def __repr__(self): 39 | return '' % (self.nickname) 40 | 41 | 42 | 43 | class WaitingListUser(db.Model): 44 | id = db.Column(db.String(64), primary_key=True) 45 | gender = db.Column(db.String(10)) 46 | interest = db.Column(db.String(10)) 47 | 48 | def __init__(self, id, gender, interest): 49 | self.id = id 50 | self.gender = gender 51 | self.interest = interest 52 | 53 | class ActiveChatsUser(db.Model): 54 | id = db.Column(db.String(64), primary_key=True) 55 | partner = db.Column(db.String(64)) 56 | alias = db.Column(db.String(80)) 57 | 58 | def __init__(self, id, partner): 59 | self.id = id 60 | self.partner = partner 61 | 62 | def add_alias(self, alias): 63 | self.alias = alias 64 | -------------------------------------------------------------------------------- /modules/gamification.py: -------------------------------------------------------------------------------- 1 | from templates import TextTemplate 2 | from utilities import send_message 3 | from app import usersdb 4 | 5 | class Game: 6 | def __init__(self, db): 7 | self.db = db 8 | self.hints = ["All is fair in ____ and war", "Hello in Spanish", "Yes in French", "How to train your _____", "Tom Marvolo Riddle <<>> I am Lord _________"] 9 | self.ans = ["love", "hola", "oui", "dragon", "voldemort"] 10 | self.valid_words = ["hint", "hints"]+self.ans 11 | 12 | def isGame(self, event): 13 | if 'message' in event and 'text' in event['message']: 14 | text = event['message']['text'] 15 | text = text.lower().replace(" ", "") 16 | print("STOP THIS ALREADY", text, self.valid_words) 17 | if text in self.valid_words: 18 | print("returning ") 19 | return True 20 | return False 21 | 22 | def send_hint(self, level, id): 23 | print("game 1.5", level) 24 | message = TextTemplate(text=self.hints[level]) 25 | send_message(message=message.get_message(), id=id) 26 | 27 | def upgrade_level(self, id): 28 | print("game upgrade") 29 | user = usersdb.get(id) 30 | if user.level == None: 31 | user.level = 0 32 | user.level = user.level+1 33 | self.db.session.commit() 34 | message = TextTemplate(text="Congrats! You have guessed the correct word. You are now at " + \ 35 | "level "+str(user.level)+".") 36 | send_message(message.get_message(), id) 37 | if user.level!=5: 38 | message = TextTemplate(text="Here is your hint for the next level:\n\n"+self.hints[user.level]) 39 | send_message(message.get_message(), id) 40 | 41 | def gamify(self, command, id): 42 | try: 43 | command = command.lower().replace(" ", "") 44 | u_level = usersdb.get(id).level 45 | print("U_LEVEL", u_level) 46 | if u_level == None: 47 | u_level = 0 48 | print("game 1", command) 49 | if command == "hint" or command == "hints": 50 | print("game 2") 51 | self.send_hint(u_level, id) 52 | return True 53 | else: 54 | a_level = self.ans.index(command) 55 | print("game 3", a_level) 56 | if a_level - u_level == 0: 57 | self.upgrade_level(id) 58 | return True 59 | else: 60 | return False 61 | except Exception, e: 62 | print("GAME ERROR", str(e)) 63 | -------------------------------------------------------------------------------- /modules/subscription.py: -------------------------------------------------------------------------------- 1 | from templates import TextTemplate, add_quick_reply 2 | import json 3 | from utilities import send_message 4 | from app import usersdb 5 | 6 | 7 | def send_subscription_prompt(id): 8 | message = TextTemplate(text="Subscribe to our notifications? We'll send out a message to you "+ 9 | "when someone of your choice is looking for a partner to chat with. Sounds good?").get_message() 10 | replies = [ 11 | { 12 | "title": "Yes. Subscribe", 13 | "payload": json.dumps({"keyword": "subscribe", "ans": "y"}) 14 | }, 15 | { 16 | "title": "No, thanks", 17 | "payload": json.dumps({"keyword": "subscribe", "ans": "n"}) 18 | }, 19 | { 20 | "title": "Don't show this", 21 | "payload": json.dumps({"keyword": "subscribe", "ans": "x"}) 22 | } 23 | ] 24 | message = add_quick_reply(message, title=replies[0]["title"], payload=replies[0]["payload"]) 25 | message = add_quick_reply(message, title=replies[1]["title"], payload=replies[1]["payload"]) 26 | message = add_quick_reply(message, title=replies[2]["title"], payload=replies[2]["payload"]) 27 | 28 | send_message(message,id) 29 | 30 | def send_pref_prompt(id): 31 | message = TextTemplate(text="Whom do you want to chat with? We will notify when someone of the selected gender is waiting to chat.").get_message() 32 | replies = [ 33 | { 34 | "title": "Men", 35 | "payload": json.dumps({"keyword": "subscribe", "ans": "male"}) 36 | }, 37 | { 38 | "title": "Women", 39 | "payload": json.dumps({"keyword": "subscribe", "ans": "female"}) 40 | } 41 | ] 42 | message = add_quick_reply(message, title=replies[0]["title"], payload=replies[0]["payload"]) 43 | message = add_quick_reply(message, title=replies[1]["title"], payload=replies[1]["payload"]) 44 | send_message(message,id) 45 | 46 | def handle_subscribe_payload(id, payload): 47 | print("inside this") 48 | if payload["ans"] == "male" or payload["ans"] == "female": 49 | usersdb.subscribe(id, pref=payload["ans"]) 50 | message = TextTemplate(text="You are subscribed. We will notify you. Promise.").get_message() 51 | send_message(message, id) 52 | 53 | elif payload["ans"] == "y": 54 | send_pref_prompt(id) 55 | 56 | elif payload["ans"] == "n": 57 | message = TextTemplate(text="Okay. You can find the option to subscribe in the menu if you change your mind.").get_message() 58 | send_message(message, id) 59 | 60 | elif payload["ans"] == "x": 61 | usersdb.setSubsValue(id, val="x") 62 | message = TextTemplate(text="Alright. In case you change your mind later on, the option to subscribe is in the menu.").get_message() 63 | send_message(message, id) 64 | -------------------------------------------------------------------------------- /DB_Wrappers/Users.py: -------------------------------------------------------------------------------- 1 | import os 2 | import config 3 | import requests 4 | from models import User 5 | 6 | class UsersDB: 7 | def __init__(self, db): 8 | self.db = db 9 | 10 | def hasDataOf(self, id): 11 | u = User.query.get(id) 12 | if u is None: 13 | return False 14 | return True 15 | 16 | def add(self, id): 17 | r = requests.get('https://graph.facebook.com/v2.6/' + str(id), params={ 18 | 'fields': 'first_name,last_name,gender,profile_pic', 19 | 'access_token': os.environ.get('ACCESS_TOKEN', config.ACCESS_TOKEN) 20 | }) 21 | data = r.json() 22 | try: 23 | first_name = data["first_name"] 24 | except: 25 | first_name = "" 26 | 27 | try: 28 | last_name = data["last_name"] 29 | except: 30 | last_name = "" 31 | 32 | try: 33 | gender = data["gender"] 34 | except: 35 | gender = "male" 36 | 37 | name = first_name + " " + last_name 38 | user = User(id=id) 39 | user.add_details(name=name, first_name=data["first_name"], gender=gender, pic_url=data["profile_pic"]) 40 | self.db.session.add(user) 41 | self.db.session.commit() 42 | 43 | def get(self, id): 44 | user = User.query.get(id) 45 | return user 46 | 47 | def getPauseStatus(self, id): 48 | user = User.query.get(id) 49 | return user.status 50 | 51 | def setPauseStatus(self, id, status): 52 | user = User.query.get(id) 53 | user.status = status 54 | self.db.session.commit() 55 | 56 | def addMessage(self, id, message): 57 | user = User.query.get(id) 58 | m = user.messages 59 | if m == None or m == "": 60 | user.messages = message 61 | elif len(m.split('#&#')) == 1: 62 | user.messages = m + "#&#" + message 63 | 64 | self.db.session.commit() 65 | 66 | def getMessages(self, id): 67 | user = User.query.get(id) 68 | m = user.messages 69 | if m == "": 70 | return None 71 | 72 | user.messages = "" 73 | self.db.session.commit() 74 | 75 | return m.split("#&#") 76 | 77 | def subscribe(self, id, pref): 78 | user = User.query.get(id) 79 | user.subscription = pref 80 | self.db.session.commit() 81 | 82 | def unsubscribe(self, id): 83 | user = User.query.get(id) 84 | user.subscription = None 85 | self.db.session.commit() 86 | 87 | def getSubsValue(self, id): 88 | user = User.query.get(id) 89 | return user.subscription 90 | 91 | def setSubsValue(self, id, val): 92 | user = User.query.get(id) 93 | user.subscription = val 94 | self.db.session.commit() 95 | 96 | def setLevel(self, id, level): 97 | user = User.query.get(id) 98 | user.level = level 99 | self.db.session.commit() -------------------------------------------------------------------------------- /templates/profile.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Profile 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 52 | 53 | 54 |
55 |
56 |
57 |
58 |
59 |
60 |

Welcome to your profile

61 |
62 | 65 |

{{ level }}

66 |
67 |
68 | 69 | 70 |
71 |
72 | 73 | 74 |
75 | 76 |
77 |

Click Save below to save your profile

78 | 79 |
80 |
81 |
82 |
83 |
84 | 85 |
86 | 87 | 88 | --> 89 | 90 | 91 | -------------------------------------------------------------------------------- /templates/receipt.py: -------------------------------------------------------------------------------- 1 | from copy import deepcopy as copy 2 | 3 | template = { 4 | 'template_type': 'receipt', 5 | 'value': { 6 | 'attachment': { 7 | 'type': 'template', 8 | 'payload': { 9 | 'template_type': 'receipt', 10 | 'recipient_name': '', 11 | 'order_number': '', 12 | 'currency': '', 13 | 'payment_method': '' 14 | } 15 | } 16 | } 17 | } 18 | 19 | class ReceiptTemplate: 20 | def __init__(self, recipient_name='', order_number='', currency='', payment_method='', timestamp='', order_url=''): 21 | self.template = copy(template['value']) 22 | self.template['attachment']['payload']['recipient_name'] = recipient_name 23 | self.template['attachment']['payload']['order_number'] = order_number 24 | self.template['attachment']['payload']['currency'] = currency 25 | self.template['attachment']['payload']['payment_method'] = payment_method 26 | if timestamp != '': 27 | self.template['attachment']['payload']['timestamp'] = timestamp 28 | if order_url != '': 29 | self.template['attachment']['payload']['order_url'] = order_url 30 | self.elements = [] 31 | self.address = {} 32 | self.summary = {} 33 | self.adjustments = [] 34 | def add_element(self, title='', subtitle='', quantity=-1, price=0, currency='', image_url=''): 35 | element = {} 36 | element['title'] = title 37 | if subtitle != '': 38 | element['subtitle'] = subtitle 39 | if quantity != -1: 40 | element['quantity'] = quantity 41 | element['price'] = price 42 | if currency != '': 43 | element['currency'] = currency 44 | if image_url != '': 45 | element['image_url'] = image_url 46 | self.elements.append(element) 47 | def set_address(self, street_1='', street_2='', city='', postal_code='', state='', country=''): 48 | self.address['street_1'] = street_1 49 | if street_2 != '': 50 | self.address['street_2'] = street_2 51 | self.address['city'] = city 52 | self.address['postal_code'] = postal_code 53 | self.address['state'] = state 54 | self.address['country'] = country 55 | def set_summary(self, subtotal=-1, shipping_cost=-1, total_tax=-1, total_cost=0): 56 | if subtotal != -1: 57 | self.summary['subtotal'] = subtotal 58 | if shipping_cost != -1: 59 | self.summary['shipping_cost'] = shipping_cost 60 | if total_tax != -1: 61 | self.summary['total_tax'] = total_tax 62 | self.summary['total_cost'] = total_cost 63 | def add_adjustment(self, name='', amount=0): 64 | adjustment = {} 65 | adjustment['name'] = name 66 | adjustment['amount'] = amount 67 | self.adjustments.append(adjustment) 68 | def get_message(self): 69 | self.template['attachment']['payload']['elements'] = self.elements 70 | if self.address != {}: 71 | self.template['attachment']['payload']['address'] = self.address 72 | self.template['attachment']['payload']['summary'] = self.summary 73 | if self.adjustments != []: 74 | self.template['attachment']['payload']['adjustments'] = self.adjustments 75 | return self.template 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BlindChat 2 | 3 | A Facebook messenger bot that allows users to chat with other people on Facebook anonymously. 4 | 5 | You can find it live [***here***](https://m.me/blindchat.go). 6 | 7 | 8 | #### NOTE: The app and the project is not maintained anymore. PRs will be unattended. 9 | 10 | 11 | ### A bit of a background 12 | 13 | I started out building BlindChat just to try out the messenger platform of Facebook and to try to build something usable out of it while learning in the process. It is more of an app rather than an AI chatbot. The outcome got a bit of traction and hence I improved certain parts of it, however, most of the code may be in an unorganized condition since those are built for quick prototyping. 14 | 15 | 16 | 17 | 18 | 19 | ### Local development / Setup your version of the app 20 | 21 | BlindChat is currently hosted on [Heroku](https://www.heroku.com/) and uses their offered database. Thus, the code and setup are written for it. If you don't want to use Heroku, you'll have to modify the code in a few places but if you are okay with Heroku, then you are just fine. It helps to have a bit of knowledge setting up a messenger bot. 22 | 23 | 24 | 25 | 1. Clone the repository by opening up your terminal/cmd and running the following command to set up your local repository: 26 | ``` 27 | git clone https://github.com/mayukh18/BlindChat.git/ 28 | ``` 29 | 30 | 2. Create a messenger app on Facebook. Add and configure the webhook and be certain to note down both the *Access Token* and *Verify Token*. 31 | 32 | 3. Install the *Heroku CLI toolbelt* if you don't already have it. Then create an app on Heroku by opening up your terminal/cmd and running the following command: 33 | ``` 34 | heroku create yourappname 35 | ``` 36 | 37 | 4. Run the following command to install the required libraries to your local environment: 38 | ``` 39 | pip install -r requirements.txt 40 | ``` 41 | 42 | 5. Run the following command to set up a Postgres database with Heroku: 43 | ``` 44 | heroku addons:add heroku-postgresql:hobby-dev 45 | ``` 46 | - For more information, refer to the [official guide from Heroku](https://devcenter.heroku.com/articles/heroku-postgresql#set-up-postgres-on-windows) on setting up a Postgres database. You'll find it pretty helpful. 47 | 48 | 6. Next run the following lines: 49 | ``` 50 | heroku run python 51 | >> import os 52 | >> os.environ.get('DATABASE_URL') 53 | ``` 54 | - The URL returned from running the above commands is your *SQLALCHEMY_DATABASE_URI*. 55 | 56 | 7. Open the **config.py** file and replace `'YOUR_FACEBOOK_APP_ACCESS_TOKEN'` and `'FACEBOOK_APP_VERIFY_TOKEN'` with the respective tokens from Step 2, replace `'APP_URL'` with your Heroku app URL `https://yourappname.herokuapp.com/` and finally, replace `'YOUR_DATABASE_URI'` with your database URI from step 6.. 57 | 58 | 8. Next, to set up and migrate the models into your database, run 59 | ``` 60 | python manage.py db init 61 | python manage.py db migrate 62 | python manage.py db upgrade 63 | ``` 64 | 65 | 9. Lastly, deploy to Heroku with the following command, and Voila! 66 | ``` 67 | git push heroku master 68 | ``` 69 | 70 | **Note:** 71 | - You may find [this memo](https://gist.github.com/mayukh18/2223bc8fc152631205abd7cbf1efdd41/) helpful if you run into problems while setting this up. 72 | - You *may* need to install PostgreSQL on your system if you run into some issues in the above step. Check [this](https://devcenter.heroku.com/articles/heroku-postgresql#set-up-postgres-on-windows) on the official guide. 73 | 74 | 75 | 76 | ### Directory structure 77 | 78 | - DB_Wrappers: Contains the wrapper classes for the models in the database. 79 | - modules: Contains all the functionalities from starting a chat session to sending a message. 80 | - templates: Contains different message templates and webviews. 81 | 82 | 83 | 84 | ### Contributing 85 | 86 | All contributions are welcome. Please discuss your ideas on the community first to avoid clash of others working on the same thing. A few issues are marked as "beginner friendly" which are suitable for beginners to try out. 87 | 88 | Ask in Issues if you are not sure on something. Cheers! 89 | -------------------------------------------------------------------------------- /modules/alias.py: -------------------------------------------------------------------------------- 1 | _prefixes = [ 2 | 'Aged', 'Ancient', 'Bubbly', 'Bitter', 'Black', 'Blue', 'Bold', 'Brave', 3 | 'Broad', 'Broken', 'Calm', 'Cold','Colossal', 'Cool', 'Crimson', 'Curly', 'Damp', 4 | 'Dark', 'Daring', 'Delicate', 'Falling', 'Fancy', 'Super', 'Jiggly', 5 | 'Flat', 'Fragrant', 'Frosty', 'Gentle', 'Green', 'Legendary', 6 | 'Icy', 'Jolly', 'Jumping', 'Little', 'Lively', 'Lucky', 'Lonely', 7 | 'Muddy', 'Mute', 'Noisy', 'Odd', 'Old', 'Orange', 'Polished', 'Proud', 8 | 'Purple', 'Quiet', 'Rapid', 'Red', 'Restless', 'Rough', 'Round', 'Royal', 'Shiny', 9 | 'Shy', 'Silent', 'Small', 'Snowy', 'Soft', 'Solitary', 'Sparkling', 'Spring', 10 | 'Square', 'Super', 'Sweet', 'Tight', 'Tiny', 'White', 'Wild', 'Yellow', 'Young', 'Sticky', 11 | 'Fluffy', 'Petite', 'Grumpy', 'Happy', 'Sleepy', 'Gray', 'Average', 'Hungry', 'Honorable', 12 | 'Kind', 'Lazy', 'Lethal', 'Macho', 'Massive', 'Puzzled', 'Rare', 'Spooky', 'Sassy', 'Tricky', 13 | 'Unique', 'Naive', 'Drowzy', 'Hot', 'Innocent', 'Naughty', 'Mischievous', 'Smart', 'Fun', 14 | 'Crazy', 'Shrewd', 'Basic', 'Gutsy', 'Cute', 'Drunk', 'Sober', 'Depressed', 'Slimy', 'Gross', 15 | 'Needy', 'Dark', 'Light', 'Roaring', 'Soaring', 'Noble', 'Vain', 'Terrifying', 'Scary', 16 | 'Studious', 'Huge', 'Enormous', 'Big', 'Giant', 'Great', 'Playful', 'Classy', 'Cold', 17 | 'Early', 'Deep', 'Awesome', 'Enhanced' 18 | ] 19 | 20 | _nouns_male = [ 21 | 'King', 'Prince', 'Bandit', 'Hulk', 'Thor', 'Leo', 'Deadpool', 'Trump', 22 | 'Moustache', 'Arrow', 'Caspian', 'Horse', 'Frog', 'Monkey', 'Lion', 23 | 'Tiger', 'Cheetah', 'Eagle', 'Wizard', 'Hawk', 'Jack', 'Hippo' , 'Stallion' , 'Bull' , 'Buck', 24 | 'Emperor','Ram', 'Captain', 'Batman', 'Robin', 'Deathstroke', 'Cyborg', 'Wolverine', 'Spiderman', 25 | 'Flash', 'Panther', 'Daredevil', 'Ironman', 'Joker', 'Aquaman', 'Necromancer', 'Warlock', 'Magneto', 26 | 'Gambit', 'Cyclops', 'Ronin', 'Warden', 'Duke', 'Lord', 'Darth', 'Vader', 'Goku', 'Gohan', 'Broly', 27 | 'Ash', 'Antman', 'Doom', 'General', 'Snake', 'Devil', 'Sergeant', 'Detective', 'Demon', 'Birdman', 28 | 'Jarvis', 'Ultron', 'Stark', 'Lannister', 'Baratheon', 'Tully', 'Greyjoy', 'Tarth', 'Phasma', 29 | 'Sailor', 'Mufasa', 'Simba', 'Ninja', 'Swordsman', 'Don', 'Gangster', 'Superman', 'Doomsday', 30 | 'Lucifer', 'Serpent', 'Count', 'Anakin', 'Luke', 'Sherlock', 'Watson', 'House', 'Nemo' 31 | ] 32 | 33 | _nouns_female = [ 34 | 'Alexa','Lili', 'Princess', 'Rihanna', 'Swift', 'Queen', 'LaserGirl', 'Mermaid', 35 | 'Butterfly', 'Batgirl', 'Madonna', 'Foxie', 'Lioness', 'Monroe', 'Eve', 'Xiry', 36 | 'Snail', 'Unicorn', 'Moon', 'Dove', 'Witch', 'Rose', 'Zebra', 'Seahorse', 'Squirrel' , 'Doe', 'Empress', 37 | 'Vixen', 'Widow', 'Supergirl', 'Storm', 'Catwoman', 'WonderWoman', 'Hawkgirl', 'Amazon', 'Mystique', 'Raven', 38 | 'Banshee', 'Enchantress', 'Ivy', 'Minx', 'Nova', 'Duchess', 'Bachelorette', 'Cat', 'Flower', 'Daisy', 39 | 'Sunflower', 'Lady', 'Mist', 'Misty', 'Superwoman', 'Gal', 'Dynamo', 'Connoisseur', 'Huntress', 40 | 'Angel', 'Goddess', 'Mystery', 'Maiden', 'Dame', 'Damsel', 'Beauty', 'Artist', 'Chick', 'Snake', 41 | 'Heroine', 'Tomboy', 'Doll', 'Spinster', 'Bride', 'Countess', 'Babe', 'Dora', 'Mistress', 'Highness', 42 | 'Ariana', 'Emma', 'Harley' 43 | ] 44 | 45 | _suffixes = [ 46 | 'OfAdua', 'OfAtlantis', 'OfCimmeria', 'OfDarkWood', 'OfDune', 47 | 'OfEgypt', 'OfLalaland', 'OfMidgard', 'OfNowhere', 'OfOz', 'OfSparta', 48 | 'OfTheDesert', 'OfTheForest', 'OfTheFuture', 'OfTheIsland', 49 | 'OfTheJungle', 'OfTheLand', 'OfTheSea','OfTheWorld', 'TheAgeless', 50 | 'TheBabyface', 'TheBarbarian', 'TheBetrayer', 'TheBrave', 51 | 'TheDestroyer', 'TheGhost', 'TheGreat', 'TheHammer', 'TheLionheart', 52 | 'TheOld', 'TheQuiet', 'TheSecond', 'TheShadow', 'TheTall', 53 | 'TheTemplar', 'TheTraveler', 'TheWanderer', 'TheWeakest', 'TheWise', 54 | 'UnderThePass', 'ofTheBay', 'ofTheDay', 'ofTheNight' 55 | ] 56 | 57 | import random 58 | 59 | 60 | def generate_alias(gender): 61 | noun = "" 62 | prefix = "" 63 | suffix = "" 64 | if gender == "male": 65 | noun = random.choice(_nouns_male) 66 | else: 67 | noun = random.choice(_nouns_female) 68 | if _toss_a_coin(): 69 | prefix = random.choice(_prefixes) 70 | else: 71 | suffix = random.choice(_suffixes) 72 | return '{0}{1}{2}'.format(prefix, noun, suffix) 73 | 74 | 75 | def _toss_a_coin(): 76 | return random.randint(0, 1) == 0 77 | -------------------------------------------------------------------------------- /modules/startChat.py: -------------------------------------------------------------------------------- 1 | from utilities import send_message 2 | from alias import generate_alias 3 | from templates import TextTemplate, GenericTemplate, AttachmentTemplate 4 | from app import waitlistdb, activechatsdb, usersdb 5 | from debug import log_waitlisted_users 6 | import os 7 | import config 8 | APP_URL = os.environ.get('APP_URL', config.APP_URL) 9 | 10 | def startChat(sender, interest): 11 | # handles the initiation of a new chat after the user selects the interest 12 | print("START1", log_waitlisted_users()) 13 | 14 | try: 15 | gender = usersdb.get(sender).gender # gets the gender from the 16 | except Exception, e: 17 | gender = "male" 18 | print("ERROR #0001", str(e)) 19 | try: 20 | # returns the PSID of the match 21 | match = waitlistdb.get_match(gender, interest) 22 | print("START2", match) 23 | except Exception, e: 24 | print("ERROR #0002", str(e)) 25 | 26 | if match == None: 27 | try: 28 | waitlistdb.delist(id=sender) # delist because there's no guarantee that it already isn't there 29 | waitlistdb.enlist(id=sender, gender=gender, interest=interest) 30 | except Exception, e: 31 | print("ERROR #0003", str(e)) 32 | message = TextTemplate(text="No match found right now. You are in the wait list. We will match you as soon"+\ 33 | " as someone becomes available") 34 | send_message(message.get_message(), id=sender) 35 | 36 | else: 37 | match_gender = usersdb.get(match).gender 38 | alias1 = generate_alias(gender=gender) 39 | alias2 = generate_alias(gender=match_gender) 40 | try: 41 | activechatsdb.clear_data(user=sender) 42 | activechatsdb.clear_data(user=match) 43 | activechatsdb.create_new_chat(user1=sender, user2=match) 44 | activechatsdb.set_alias(user=sender, alias=alias1) 45 | activechatsdb.set_alias(user=match, alias=alias2) 46 | except Exception, e: 47 | print("ERROR #0004", str(e)) 48 | 49 | 50 | imurl = APP_URL+"static/startchat.jpg/" 51 | 52 | # ------------------------------------ MATCH ---------------------------------------- # 53 | 54 | #message = AttachmentTemplate(url=get_start_hi(gender=gender),type="image") 55 | #send_message(message.get_message(), id=match) 56 | 57 | sender_bio = usersdb.get(sender).bio 58 | if sender_bio is None: 59 | bio = "No bio" 60 | else: 61 | bio = "Bio: " + sender_bio 62 | sender_interests = usersdb.get(sender).interests 63 | if sender_interests is None: 64 | intr = "No interests." 65 | else: 66 | intr = "Interests: " + sender_interests 67 | 68 | sender_level = usersdb.get(sender).level 69 | if sender_level == None: 70 | usersdb.setLevel(sender, 0) 71 | sender_level = usersdb.get(sender).level 72 | 73 | level_str = u'\u2B50' 74 | for i in range(sender_level): 75 | level_str = level_str + u'\u2B50' 76 | 77 | message = GenericTemplate() 78 | message.add_element(title="You are matched with "+alias1, subtitle=level_str, image_url=imurl) 79 | send_message(message=message.get_message(), id=match) 80 | message = TextTemplate(text=bio + " | "+ intr) 81 | send_message(message.get_message(), id=match) 82 | 83 | # ------------------------------------- SENDER -------------------------------------------- # 84 | 85 | #message = AttachmentTemplate(url=get_start_hi(gender=match_gender), type="image") 86 | #send_message(message.get_message(), id=sender) 87 | 88 | match_bio = usersdb.get(match).bio 89 | if match_bio is None: 90 | bio = "No bio" 91 | else: 92 | bio = "Bio: " + match_bio 93 | 94 | match_interests = usersdb.get(match).interests 95 | if match_interests is None: 96 | intr = "No interests." 97 | else: 98 | intr = "Interests: " + match_interests 99 | 100 | match_level = usersdb.get(match).level 101 | if match_level == None: 102 | usersdb.setLevel(match, 0) 103 | match_level = usersdb.get(match).level 104 | 105 | level_str = u'\u2B50' 106 | for i in range(match_level): 107 | level_str = level_str + u'\u2B50' 108 | 109 | message = GenericTemplate() 110 | message.add_element(title="You are matched with " + alias2, subtitle=level_str, image_url=imurl) 111 | send_message(message=message.get_message(), id=sender) 112 | message = TextTemplate(text=bio + " | " + intr) 113 | send_message(message.get_message(), id=sender) 114 | 115 | 116 | -------------------------------------------------------------------------------- /modules/utilities.py: -------------------------------------------------------------------------------- 1 | from templates import TextTemplate, add_quick_reply 2 | import requests 3 | import config 4 | import os 5 | import json 6 | from app import usersdb 7 | 8 | ACCESS_TOKEN = os.environ.get('ACCESS_TOKEN', config.ACCESS_TOKEN) 9 | APP_URL = os.environ.get('APP_URL', config.APP_URL) 10 | 11 | def send_interest_menu(sender): 12 | out = {"keyword":"interest"} 13 | message = TextTemplate(text="Whom do you want to chat with?").get_message() 14 | out["interest"] = "male" 15 | message = add_quick_reply(message=message, title="Men", payload=json.dumps(out)) 16 | out["interest"] = "female" 17 | message = add_quick_reply(message=message, title="Women", payload=json.dumps(out)) 18 | out["interest"] = "random" 19 | message = add_quick_reply(message=message, title="Random", payload=json.dumps(out)) 20 | 21 | send_message(message, sender) 22 | 23 | 24 | def send_newchat_prompt(id): 25 | payload = {"keyword": "newchat"} 26 | payload["ans"] = "y" 27 | message = TextTemplate(text="Are you ready to start a new chat").get_message() 28 | message = add_quick_reply(message=message, title="Oh! Yes!", payload=json.dumps(payload)) 29 | payload["ans"] = "n" 30 | message = add_quick_reply(message=message, title="No. Later", payload=json.dumps(payload)) 31 | payload["ans"] = "p" 32 | message = add_quick_reply(message=message, title="Edit Profile", payload=json.dumps(payload)) 33 | send_message(message, id) 34 | 35 | def isGreeting(text): 36 | valid = ["hi", "hello", "hey"] 37 | if text.lower() in valid: 38 | return True 39 | return False 40 | 41 | def handle_greetings(text, id, name): 42 | message = TextTemplate(text="Hi "+name+". Nice to meet you. To get a list of available commands, type \"help\"") 43 | send_message(message.get_message(), id) 44 | 45 | def send_message(message, id, pause_check=False): 46 | 47 | if isinstance(message, dict) == False: 48 | message = message.get_message() 49 | try: 50 | if pause_check and usersdb.getPauseStatus(id): 51 | print("USER PAUSED, MESSAGE STORED") 52 | usersdb.addMessage(id=id, message=json.dumps(message)) 53 | return 54 | except Exception, e: 55 | print("STORAGE", str(e)) 56 | 57 | try: 58 | if 'quick_replies' in message: 59 | usersdb.setPauseStatus(id=id, status=True) 60 | except: 61 | print("hoola") 62 | 63 | payload = { 64 | 'recipient': { 65 | 'id': id 66 | }, 67 | 'message': message 68 | } 69 | r = requests.post('https://graph.facebook.com/v2.6/me/messages', params={'access_token': ACCESS_TOKEN}, 70 | json=payload) 71 | 72 | def send_help(sender): 73 | helptext = """BlindChat allows you to chat with people without revealing your identity. 74 | The bot will match you with strangers all over the world. 75 | You can choose to share your profile with the other person after ending the chat. 76 | 77 | Available commands: 78 | quit - quits from the active chat or from the waitlist 79 | help - view the help menu 80 | start - starts to look for a new chatrestart - restart the bot 81 | profile - modify your chat profile 82 | """ 83 | 84 | message = TextTemplate(text=helptext) 85 | send_message(message.get_message(), sender) 86 | 87 | 88 | def show_typing(id, duration): 89 | from time import sleep 90 | payload = { 91 | 'recipient': { 92 | 'id': id 93 | }, 94 | "sender_action":"typing_on" 95 | } 96 | r = requests.post('https://graph.facebook.com/v2.6/me/messages', params={'access_token': ACCESS_TOKEN}, 97 | json=payload) 98 | 99 | sleep(duration) 100 | payload["sender_action"] = "typing_off" 101 | r = requests.post('https://graph.facebook.com/v2.6/me/messages', params={'access_token': ACCESS_TOKEN}, 102 | json=payload) 103 | 104 | def send_paused_messages(id): 105 | if usersdb.getPauseStatus(id) == False: 106 | m_list = usersdb.getMessages(id) 107 | print("MLIST", m_list) 108 | try: 109 | if m_list is None or len(m_list[0])==0: 110 | return 111 | except Exception, e: 112 | print("problem is here", m_list) 113 | for m in m_list: 114 | send_message(message=json.loads(m), id=id) 115 | 116 | def send_profile_prompt(id): 117 | message = { 118 | "attachment":{ 119 | "type":"template", 120 | "payload":{ 121 | "template_type":"button", 122 | "text":"To modify or edit your chat profile, click the PROFILE button", 123 | "buttons":[ 124 | { 125 | "type":"web_url", 126 | "url":APP_URL+"webview?id="+str(id), 127 | "title":"PROFILE", 128 | "webview_height_ratio": "compact" 129 | } 130 | ] 131 | } 132 | } 133 | } 134 | send_message(message=message, id=id) 135 | -------------------------------------------------------------------------------- /modules/endChat.py: -------------------------------------------------------------------------------- 1 | from templates import * 2 | from app import activechatsdb, usersdb 3 | from subscription import send_subscription_prompt 4 | from utilities import send_message, send_newchat_prompt, show_typing 5 | import requests 6 | import config 7 | import os 8 | import json 9 | 10 | ADMIN_ID = os.environ.get('ADMIN_ID', config.ADMIN_ID) 11 | ACCESS_TOKEN = os.environ.get('ACCESS_TOKEN', config.ACCESS_TOKEN) 12 | APP_URL = os.environ.get('APP_URL', config.APP_URL) 13 | 14 | def endChat(sender): 15 | 16 | try: 17 | partner = activechatsdb.get_partner(sender) 18 | alias1 = activechatsdb.get_alias(sender) 19 | alias2 = activechatsdb.get_alias(partner) 20 | except: 21 | message = TextTemplate(text="No open chat was found which can be closed") 22 | send_message(message.get_message(), id=sender) 23 | show_typing(id=sender, duration=2) 24 | send_newchat_prompt(id=sender) 25 | return 26 | 27 | imurl = APP_URL+"static/endchat1.jpg/" 28 | 29 | # -------------------------- SENDER --------------------------- # 30 | 31 | replies_sender = [ 32 | { 33 | "title":"Share profile", 34 | "payload":json.dumps({"keyword":"profile_share","ans":"y", "alias":alias1, "partner":partner}) 35 | }, 36 | { 37 | "title":"Don't share", 38 | "payload":json.dumps({"keyword":"profile_share","ans":"n", "alias":alias1, "partner":partner}) 39 | } 40 | ] 41 | 42 | message = GenericTemplate() 43 | title = "You have ended the chat with "+alias2 44 | subtitle = "Hope you had a nice experience." 45 | message.add_element(title=title, subtitle=subtitle, image_url=imurl) 46 | send_message(message=message.get_message(), id=sender) 47 | 48 | message = TextTemplate(text="Would you like to share your profile with "+alias2+"?").get_message() 49 | message = add_quick_reply(message, title=replies_sender[0]["title"], payload=replies_sender[0]["payload"]) 50 | message = add_quick_reply(message, title=replies_sender[1]["title"], payload=replies_sender[1]["payload"]) 51 | send_message(message=message, id=sender) 52 | 53 | # ----------------------------------------------------------------------- # 54 | 55 | # ------------------------------- PARTNER ------------------------------- # 56 | 57 | replies_partner = [ 58 | { 59 | "title": "Share profile", 60 | "payload": json.dumps({"keyword": "profile_share", "ans": "y", "alias": alias2, "partner": sender}) 61 | }, 62 | { 63 | "title": "Don't share", 64 | "payload": json.dumps({"keyword": "profile_share", "ans": "n", "alias": alias2, "partner": sender}) 65 | } 66 | ] 67 | 68 | message = GenericTemplate() 69 | title = alias1+" has quit the chat" 70 | subtitle = "Hope you had a nice experience while it lasted." 71 | message.add_element(title=title, subtitle=subtitle, image_url=imurl) 72 | send_message(message=message.get_message(), id=partner, pause_check=True) 73 | 74 | message = TextTemplate(text="Would you like to share your profile with " + alias1 + "?").get_message() 75 | message = add_quick_reply(message, title=replies_partner[0]["title"], payload=replies_partner[0]["payload"]) 76 | message = add_quick_reply(message, title=replies_partner[1]["title"], payload=replies_partner[1]["payload"]) 77 | send_message(message=message, id=partner, pause_check=True) 78 | 79 | # --------------------------------------------------------------- # 80 | 81 | try: 82 | activechatsdb.delete_chat_entries(user=sender) 83 | except Exception, e: 84 | print("ENDCHAT ERROR", str(e)) 85 | 86 | 87 | 88 | def share_profile(sender, payload): 89 | if isinstance(payload, str) or isinstance(payload, unicode): 90 | payload = json.loads(str(payload)) 91 | print("SHAREPROFILE PAYLOAD", payload) 92 | 93 | alias = payload["alias"] 94 | partner = payload["partner"] 95 | 96 | if payload["ans"] == "y": 97 | r = requests.get('https://graph.facebook.com/v2.6/' + str(sender), params={ 98 | 'fields': 'first_name,last_name,profile_pic', 99 | 'access_token': os.environ.get('ACCESS_TOKEN', config.ACCESS_TOKEN) 100 | }) 101 | userData = r.json() 102 | 103 | message = TextTemplate(text=alias + " has shared his/her profile with you") 104 | send_message(message=message.get_message(), id=partner, pause_check=True) 105 | message = GenericTemplate() 106 | message.add_element(title=userData["first_name"] + " " + userData["last_name"],image_url=userData["profile_pic"], 107 | subtitle="Search on Facebook by the name and recognise by the profile picture") 108 | send_message(message=message.get_message(), id=partner, pause_check=True) 109 | 110 | else: 111 | message = TextTemplate(text=alias + " has chosen not to share his/her profile with you") 112 | send_message(message=message.get_message(), id=partner, pause_check=True) 113 | 114 | show_typing(id=sender, duration=1) 115 | if sender != ADMIN_ID: 116 | send_newchat_prompt(id=sender) 117 | elif usersdb.getSubsValue(id=sender) != "x": 118 | send_subscription_prompt(id=sender) 119 | 120 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import os 2 | import config 3 | from flask import Flask, request, render_template 4 | from flask_sqlalchemy import SQLAlchemy 5 | from analytics import Analytics 6 | 7 | # --------------------------------------------------------------- # 8 | 9 | ACCESS_TOKEN = os.environ.get('ACCESS_TOKEN', config.ACCESS_TOKEN) 10 | VERIFY_TOKEN = os.environ.get('VERIFY_TOKEN', config.VERIFY_TOKEN) 11 | PAGE_ID = os.environ.get('PAGE_ID', config.PAGE_ID) 12 | ADMIN_ID = os.environ.get('ADMIN_ID', config.ADMIN_ID) 13 | 14 | # --------------------------------------------------------------- # 15 | 16 | app = Flask(__name__) 17 | app.config.from_object('config') 18 | db = SQLAlchemy(app) 19 | 20 | # --------------------------------------------------------------- # 21 | 22 | from models import User, WaitingListUser, ActiveChatsUser 23 | from templates import TextTemplate 24 | from DB_Wrappers import * 25 | 26 | usersdb = UsersDB(db=db) 27 | waitlistdb = WaitingListDB(db=db) 28 | activechatsdb = ActiveChatsDB(db=db) 29 | 30 | from modules import * 31 | setup_all() 32 | metrics = Analytics() 33 | Int = Interrupts() 34 | game = Game(db=db) 35 | 36 | # --------------------------------------------------------------- # 37 | @app.route('/webview/', methods=['POST']) 38 | def getProfile(): 39 | try: 40 | print("FORM SUBMITTED", dict(request.form)) 41 | bio = request.form['bio'] 42 | interests = request.form['interests'] 43 | id = request.form['psid'] 44 | print("USER ID", id) 45 | user = usersdb.get(id) 46 | user.interests = interests 47 | user.bio = bio 48 | user.liked = True 49 | db.session.commit() 50 | return render_template('result.html') 51 | except Exception, e: 52 | print("FORM ERROR", str(e)) 53 | 54 | @app.route('/webview/', methods=['GET']) 55 | def render(): 56 | id = request.args.get('id') 57 | print("PROFILE ID", id) 58 | user = usersdb.get(id) 59 | bio = user.bio 60 | interests = user.interests 61 | level = user.level 62 | level_str = u'\u2B50' 63 | for i in range(level): 64 | level_str = level_str + u'\u2B50' 65 | 66 | if bio is None: 67 | bio = "" 68 | if interests is None: 69 | interests = "" 70 | return render_template('profile.html', id=id, bio=bio, interests=interests, level=level_str) 71 | 72 | 73 | @app.route('/webhook/', methods=['GET', 'POST']) 74 | def webhook(): 75 | if request.method == 'POST': 76 | data = request.get_json(force=True) 77 | 78 | # analytics api post 79 | metrics.record(entry=data["entry"]) 80 | 81 | messaging_events = data['entry'][0]['messaging'] 82 | for event in messaging_events: 83 | sender = event['sender']['id'] 84 | print("EVENT", event) 85 | 86 | try: 87 | if sender != PAGE_ID and usersdb.hasDataOf(sender) is False: 88 | usersdb.add(sender) 89 | except Exception, e: 90 | print("ERROR", str(e)) 91 | 92 | 93 | try: 94 | if 'postback' in event and 'payload' in event['postback']: 95 | postback_payload = event['postback']['payload'] 96 | print("postback payload", postback_payload) 97 | handle_postback(payload=postback_payload, sender=sender) 98 | print("postback handled") 99 | continue 100 | elif 'message' in event and 'text' in event['message']: 101 | if Int.isValidCommand(event['message']['text']): 102 | print("interrupt detected", event['message']['text']) 103 | Int.handleCommand(command=event['message']['text'], sender=sender) 104 | print("interrupt handled") 105 | continue 106 | else: 107 | print("NOT POSTBACK OR INTERRUPT") 108 | except Exception, e: 109 | print("POSTBACK/INTERRUPT ERROR", str(e)) 110 | db.session.rollback() 111 | return '' 112 | 113 | if game.isGame(event) == True: 114 | x = game.gamify(event['message']['text'], id=sender) 115 | if x == True: 116 | continue 117 | 118 | if activechatsdb.isActive(sender): 119 | alias = activechatsdb.get_alias(sender) 120 | if 'message' in event and 'text' in event['message']: 121 | text = event['message']['text'] 122 | 123 | if 'quick_reply' in event['message'] and 'payload' in event['message']['quick_reply']: 124 | quick_reply_payload = event['message']['quick_reply']['payload'] 125 | handle_quick_reply(sender=sender, payload=quick_reply_payload) 126 | 127 | else: 128 | message = TextTemplate(text=alias+": "+text) 129 | recipient = activechatsdb.get_partner(sender) 130 | send_message(message=message.get_message(), id=recipient) 131 | 132 | elif 'message' in event and 'attachments' in event['message'] and 'type' in event['message']['attachments'][0]: 133 | if event['message']['attachments'][0]['type'] == "image": 134 | handle_image(sender=sender, url=event['message']['attachments'][0]['payload']['url']) 135 | else: 136 | recipient = sender 137 | if 'message' in event and 'text' in event['message']: 138 | text = event['message']['text'] 139 | 140 | try: 141 | if text[:3] == ":::": 142 | handle_debug(text, id=sender) 143 | message = TextTemplate(text="Debug command executed") 144 | send_message(message.get_message(), id=recipient) 145 | continue 146 | except Exception, e: 147 | print("DEBUG ERROR", str(e)) 148 | 149 | if 'quick_reply' in event['message'] and 'payload' in event['message']['quick_reply']: 150 | quick_reply_payload = event['message']['quick_reply']['payload'] 151 | handle_quick_reply(sender=sender, payload=quick_reply_payload) 152 | else: 153 | if(isGreeting(text)): 154 | handle_greetings(text, sender, usersdb.get(sender).first_name) 155 | continue 156 | message = TextTemplate(text="I didn't understand what you intended. Type \"help\" to"+ 157 | " get the set of available commands. Use those commands or"+ 158 | " the menu options to interact with the bot") 159 | send_message(message.get_message(), id=recipient) 160 | 161 | return '' # 200 OK 162 | 163 | elif request.method == 'GET': # Verification 164 | if request.args.get('hub.verify_token') == VERIFY_TOKEN: 165 | return request.args.get('hub.challenge') 166 | else: 167 | return 'Error, wrong validation token' 168 | 169 | 170 | if __name__ == '__main__': 171 | app.run() 172 | #, port=int(os.environ.get('PORT', 4431)) --------------------------------------------------------------------------------