├── .gitignore ├── SurveyBot.exe ├── __main__.py ├── __main__.spec ├── ca.crt ├── data └── .gitignore ├── drivers ├── Darwin │ └── chromedriver ├── Linux │ └── chromedriver └── Windows │ └── chromedriver.exe ├── geckodriver.log ├── js ├── answer_question.js ├── get_question.js └── open_survey.js ├── readme.md ├── requirements.txt ├── util ├── __pycache__ │ ├── data_manager.cpython-36.pyc │ ├── data_manager.cpython-37.pyc │ ├── network_manager.cpython-36.pyc │ ├── network_manager.cpython-37.pyc │ ├── swagbucks.cpython-36.pyc │ └── swagbucks.cpython-37.pyc ├── data_manager.py ├── network_manager.py └── swagbucks.py └── views ├── __pycache__ ├── question_screen.cpython-36.pyc └── question_screen.cpython-37.pyc ├── dashboard_screen.py └── question_screen.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | __pycache__/* 3 | data/* 4 | build/* 5 | dist/* 6 | venv/* 7 | -------------------------------------------------------------------------------- /SurveyBot.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeWonderland/super-survey-bot-desktop/a3b39a4203b0fe2b74d1cbe133770e2615eef74c/SurveyBot.exe -------------------------------------------------------------------------------- /__main__.py: -------------------------------------------------------------------------------- 1 | from util.swagbucks import SwagbucksCrawler 2 | from util.swagbucks import SwagbucksTestCrawler 3 | from util.data_manager import SSBDataManager 4 | from util.network_manager import NetworkManager 5 | 6 | import kivy 7 | 8 | from kivy.app import App 9 | from kivy.lang import Builder 10 | from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelHeader 11 | from views.question_screen import QuestionScreen 12 | from kivy.uix.button import Button 13 | 14 | kivy.require('1.0.6') 15 | 16 | Builder.load_string(""" 17 | 18 | """) 19 | 20 | 21 | class SSBContainer(TabbedPanel): 22 | def __init__(self, test_mode, **kwargs): 23 | super(SSBContainer, self).__init__(**kwargs) 24 | 25 | # Some Default Attribute Values 26 | self.current_question = "" 27 | 28 | # Establish Test Status 29 | self.test_mode = test_mode 30 | 31 | if self.test_mode: 32 | self.crawler = SwagbucksTestCrawler() 33 | 34 | else: 35 | self.crawler = SwagbucksCrawler() 36 | 37 | # Create Data Manager Instance 38 | if not self.test_mode: 39 | self.data_manager = SSBDataManager() 40 | 41 | # Create Answering Interface Tab 42 | self.answering_interface = TabbedPanelHeader(text="Answer Questions") 43 | 44 | self.add_widget(self.answering_interface) 45 | 46 | self.answering_interface.content = QuestionScreen() 47 | 48 | # Fetch Question 49 | question_data = self.get_question() 50 | 51 | self.delegate_answering(question_data) 52 | 53 | # Create Dash 54 | self.default_tab.text = "Dashboard" 55 | 56 | button = Button(text="Go Online", on_press=self.go_online) 57 | self.default_tab.content = button 58 | 59 | # Add network mananger 60 | self.network_manager = None 61 | 62 | def answer_question(self, data): 63 | # Make sure question is still unanswered 64 | if "QUESTION" in data and data["QUESTION"] == self.current_question: 65 | # Send data to crawler 66 | if "ANSWER_VALUES" in data: 67 | self.crawler.send_answer(data["ANSWER_VALUES"]) 68 | 69 | # Record non-test data in db 70 | if not self.test_mode and "QUESTION" in data and "ANSWER_LABELS" in data: 71 | self.record_answer(data["QUESTION"], data["ANSWER_LABELS"]) 72 | 73 | # Start next question 74 | self.delegate_answering(self.crawler.get_question()) 75 | 76 | def delegate_answering(self, question_data): 77 | # Update Current Question 78 | self.current_question = question_data["QUESTION"] 79 | 80 | # Send Question to Answering Interface 81 | self.answering_interface.content.set_question(question_data) 82 | 83 | def record_answer(self, question, answers): 84 | data = { 85 | "QUESTION": question, 86 | "ANSWERS": answers 87 | } 88 | 89 | if not self.test_mode: 90 | self.data_manager.input_data(data) 91 | 92 | def get_id(self): 93 | if self.test_mode: 94 | return "0" 95 | 96 | else: 97 | return self.data_manager.get_id() 98 | 99 | def get_question(self): return self.crawler.get_question() 100 | 101 | def go_online(self, instance): self.network_manager = NetworkManager(self) 102 | 103 | 104 | class SurveyBot(App): 105 | def __init__(self, **kwargs): 106 | super().__init__(**kwargs) 107 | 108 | def build(self): 109 | self.title = 'Super Survey Bot-Inator 9000' 110 | return SSBContainer(test_mode=False) 111 | 112 | 113 | if __name__ == "__main__": 114 | SurveyBot().run() 115 | -------------------------------------------------------------------------------- /__main__.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python -*- 2 | 3 | block_cipher = None 4 | 5 | 6 | a = Analysis(['__main__.py'], 7 | pathex=['.'], 8 | binaries=[], 9 | datas=[], 10 | hiddenimports=[], 11 | hookspath=[], 12 | runtime_hooks=[], 13 | excludes=[], 14 | win_no_prefer_redirects=False, 15 | win_private_assemblies=False, 16 | cipher=block_cipher, 17 | noarchive=False) 18 | pyz = PYZ(a.pure, a.zipped_data, 19 | cipher=block_cipher) 20 | exe = EXE(pyz, 21 | a.scripts, 22 | a.binaries, 23 | a.zipfiles, 24 | a.datas, 25 | [], 26 | name='__main__', 27 | debug=False, 28 | bootloader_ignore_signals=False, 29 | strip=False, 30 | upx=True, 31 | runtime_tmpdir=None, 32 | console=True ) 33 | -------------------------------------------------------------------------------- /ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGLTCCBBWgAwIBAgIUUC1RKvdSytOj8fqBixiJykseE3QwDQYJKoZIhvcNAQEL 3 | BQAwgaUxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdWZXJtb250MRMwEQYDVQQHDApC 4 | dXJsaW5ndG9uMRkwFwYDVQQKDBBTdXBlciBTdXJ2ZXkgQm90MQwwCgYDVQQLDANE 5 | ZXYxFzAVBgNVBAMMDmNvZGVXb25kZXJsYW5kMS0wKwYJKoZIhvcNAQkBFh5hbGlj 6 | ZS5lYXN0ZXJkZXZlbG9wc0BnbWFpbC5jb20wHhcNMTkwMjEwMTc0NzM2WhcNMjEx 7 | MTMwMTc0NzM2WjCBpTELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB1Zlcm1vbnQxEzAR 8 | BgNVBAcMCkJ1cmxpbmd0b24xGTAXBgNVBAoMEFN1cGVyIFN1cnZleSBCb3QxDDAK 9 | BgNVBAsMA0RldjEXMBUGA1UEAwwOY29kZVdvbmRlcmxhbmQxLTArBgkqhkiG9w0B 10 | CQEWHmFsaWNlLmVhc3RlcmRldmVsb3BzQGdtYWlsLmNvbTCCAiIwDQYJKoZIhvcN 11 | AQEBBQADggIPADCCAgoCggIBAKQaUO8nPxVLoKgs+qogh/RcLKOv/tOK95Gt0f+S 12 | K38Jxg1WKsp9rxSEmndoK3rg5di9yeET3tnbmFHetfynVARFqsUqTswt+WRIXQF0 13 | UMZczOpr1eOKIWV4FTypTfxEeFBAok/dmclAwakRwQ/aawiaAMz9N+PvPA3JCfs6 14 | IJKtHp8/3Ur2gUSO0m2qJh/UtvsYnmVNWt9XhRUX+qeliNkToP+XdPESbxhQExO1 15 | dOFC1dpOJ72NW1Pnk2voiGCmvJbbUO07SOXQ4YoCL864/suFSqUxj+dhkDGqLUAM 16 | niI4sDbkJ8U+mOwR4HDYgNBKCQzRQR0HY+M+K5j+1AnwY8ZgrolO2QLxQQcrwDgy 17 | lCxbpjenAK0yv7PJgW8OqaWGI0ccQ15/gV9PA7vBYTHCTxY52rL1NYlell92ZS9D 18 | msB2Rt9+gAfFSHIXzaR4UrAhyu11E+R82/IT124VOim00t3IbSufAVN3cgf473qe 19 | jCq5xzrinC6opxOk8W9R91PsGH+s8izYBBFRqxkChi1YgJqEl6bT53r1ucGBWYGe 20 | RvIMXcmuM5ZUoEvG9eADCjOIJz+8nmsI4I+axTKkb+xt1XDeJQzGQsMrzY7UbWAX 21 | lsrKpab4cqlrc/egrZ188UYs+PqT9V6ZC7nsQutsj4VDuB3HM1eu+9s5yNMn7WeQ 22 | owkbAgMBAAGjUzBRMB0GA1UdDgQWBBTwWFPy/RwDIOjoBy/tByyTTsL0ezAfBgNV 23 | HSMEGDAWgBTwWFPy/RwDIOjoBy/tByyTTsL0ezAPBgNVHRMBAf8EBTADAQH/MA0G 24 | CSqGSIb3DQEBCwUAA4ICAQBeVADMjT5AgJ6TZ0MUGxi4x0T5ZHm/+XWuYAz5TwiN 25 | egFYlOUDAqWm5z/SmjCL/eWOWmhHoZx7vWZ5Tz9F5GV69LBaN7m7ZD462XbRXHhM 26 | 7AFt+9dRpTFeVcoYJDNcqgtWYhVZIq2miQMaokIuzbvovZ5XrA3QOR2bKVmmOpdV 27 | gpEFjknFewjKX+94M72ie0Q0uWexhVt6iR3tbkAiWAKJkAI/nm3Ll7d4cgJJH01q 28 | P1tJ1jQCzUoZ8j9pxGVg/K0aj/FeGeFMVSz6YQGMy3LEffYABcizN+xz52E94hk8 29 | PR4oS5RZiaBprKH9s1I8gvqWmqm4JNsOLDvreYTSwUO5a/AwtNDWOmPS6izZ6npN 30 | ReDPU4AThvqgY9OtCnPFStHfl4Y12ZHpIOEnjY7cdsPJNBF+Gf8lhuPBQjXjM4lw 31 | lnwF1PXU0ptHu+AAp2Rzhy6sXNZ3Y3BHlpM6R1N63mZF4TLJTnGcnbFHL7Z23wrW 32 | WqA7oiWUNweEwI8oNRJw1fBDuADJjiNlyO1JNkY0E7PqfPoLZ0bdoSjBz8MyHSKc 33 | XjQbI/sdP9DAFWgjf02YU+GyifS8hs52c72fJYiIec/K7MYFLDiDYGUMB1AcaZ0J 34 | GZYaVvu5GXQVphvcoMS85M0S+yI/h+yduElFeTXe894pi/cPagDTSnTqjn7W3To6 35 | +Q== 36 | -----END CERTIFICATE----- 37 | -------------------------------------------------------------------------------- /data/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /drivers/Darwin/chromedriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeWonderland/super-survey-bot-desktop/a3b39a4203b0fe2b74d1cbe133770e2615eef74c/drivers/Darwin/chromedriver -------------------------------------------------------------------------------- /drivers/Linux/chromedriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeWonderland/super-survey-bot-desktop/a3b39a4203b0fe2b74d1cbe133770e2615eef74c/drivers/Linux/chromedriver -------------------------------------------------------------------------------- /drivers/Windows/chromedriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeWonderland/super-survey-bot-desktop/a3b39a4203b0fe2b74d1cbe133770e2615eef74c/drivers/Windows/chromedriver.exe -------------------------------------------------------------------------------- /geckodriver.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeWonderland/super-survey-bot-desktop/a3b39a4203b0fe2b74d1cbe133770e2615eef74c/geckodriver.log -------------------------------------------------------------------------------- /js/answer_question.js: -------------------------------------------------------------------------------- 1 | // grab a reference to the question in question 2 | let survey_question = document.getElementsByClassName("surveyQuestion"); 3 | 4 | // if the reference is valid 5 | if (survey_question.length) { 6 | // we extract the element from it's container 7 | survey_question = survey_question[0]; 8 | 9 | // grab all answer options 10 | let answer_options = survey_question.getElementsByClassName("questionDropdownOptions"); 11 | 12 | // if our reference is valid 13 | if (answer_options.length) { 14 | // we make an array from the span elements with the answers in them 15 | answer_options = Array.from(answer_options[0].getElementsByTagName("span")); 16 | 17 | // select answers on the page that match user answers 18 | answer_options.forEach(option => { 19 | // answers come as csv 20 | arguments[0].split(',') 21 | .forEach(user_answer => { 22 | if (user_answer === option.getAttribute("data-value")) { 23 | option.click(); 24 | } 25 | }); 26 | }); 27 | 28 | // swagbucks function to save answer 29 | sp.saveAnswer(); 30 | } 31 | } -------------------------------------------------------------------------------- /js/get_question.js: -------------------------------------------------------------------------------- 1 | // grab reference to question 2 | let survey_question = document.getElementsByClassName("surveyQuestion"); 3 | 4 | // make question data frame 5 | let question_data = { 6 | "QUESTION" : "", 7 | "TYPE" : "", 8 | "ANSWERS" : [] 9 | }; 10 | 11 | // make template for answers 12 | let answer_template = { 13 | "TEXT" : "", 14 | "data-value" : null 15 | }; 16 | 17 | // if our reference is valid 18 | if (survey_question.length) { 19 | // we extract the question from its container 20 | survey_question = survey_question[0]; 21 | 22 | // assign question text from page value 23 | question_data["QUESTION"] = survey_question.getElementsByClassName("surveyQuestionText")[0].innerText; 24 | 25 | // grab answer options 26 | let answer_options = survey_question.getElementsByClassName("questionDropdownOptions"); 27 | 28 | 29 | 30 | // if reference is valid 31 | if (answer_options.length) { 32 | 33 | // check answer options for type of question 34 | if (answer_options[0].classList.contains("activeSelectMenu")) { 35 | question_data["TYPE"] = 'CHECKBOX'; 36 | 37 | } else { 38 | question_data["TYPE"] = 'SELECT' 39 | } 40 | 41 | // grab answer options 42 | answer_options = Array.from(answer_options[0].getElementsByTagName("span")); 43 | 44 | // add each answer to the data frame 45 | answer_options.forEach(option => { 46 | // make sure to copy template, not grab reference 47 | let current_answer = Object.assign({}, answer_template); 48 | 49 | // assign values from page 50 | current_answer["TEXT"] = option.innerText; 51 | current_answer["DATA_VALUE"] = option.getAttribute("data-value"); 52 | 53 | // push current answer to data frame 54 | question_data["ANSWERS"].push(current_answer); 55 | }); 56 | } 57 | } 58 | 59 | // noinspection JSAnnotator 60 | return question_data; -------------------------------------------------------------------------------- /js/open_survey.js: -------------------------------------------------------------------------------- 1 | // grab a link to the survey 2 | let survey_link = document.getElementById("sbMainNavSectionListItemAnswer"); 3 | 4 | // if the element exists 5 | if (survey_link) { 6 | // we click the link inside :3 7 | survey_link.getElementsByTagName("a")[0].click(); 8 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Super Survey Bot Desktop 2 | 3 | ## Installation 4 | ### Windows 5 | Installation is really easy, just download the project and double click the SurveyBot.exe file 6 | 7 | ## Dev Setup 8 | ### Windows 9 | Open powershell, navigate to the project directory, and type the following: 10 | 11 | ``` 12 | $ virtualenv venv --distribute 13 | $ venv/Scripts/activate 14 | $ pip install -r requirements.txt 15 | ``` 16 | 17 | ### Unix Systems 18 | Open a terminal, navigate to the project directory, and type the following: 19 | 20 | ```bash 21 | $ virtualenv venv --distribute 22 | $ source venv/bin/activate 23 | $ pip install -r requirements.txt 24 | ``` 25 | 26 | To Disable Virtualenv: 27 | 28 | ```bash 29 | $ deactivate 30 | ``` 31 | 32 | ### Pycharm 33 | Navigate to `File > Settings > Project > Project Interpreter` 34 | 35 | Click on the dropdown next to project interpreter and select `Show All` and a new window will appear 36 | 37 | Click the plus, select `Virtualenv` then select the `Existing Environment` button. Set the interpeter to `$PROJECTDIR/venv/bin/python` 38 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.5.4 2 | altgraph==0.16.1 3 | async-timeout==3.0.1 4 | attrs==18.2.0 5 | certifi==2018.11.29 6 | chardet==3.0.4 7 | Cython==0.29.2 8 | docutils==0.14 9 | future==0.17.1 10 | idna==2.8 11 | idna-ssl==1.1.0 12 | Kivy==1.10.1 13 | Kivy-Garden==0.1.4 14 | macholib==1.11 15 | multidict==4.5.2 16 | pefile==2018.8.8 17 | pygame==1.9.4 18 | Pygments==2.3.1 19 | PyInstaller==3.4 20 | requests==2.21.0 21 | selenium==3.141.0 22 | typing-extensions==3.7.2 23 | urllib3==1.24.2 24 | yarl==1.3.0 25 | -------------------------------------------------------------------------------- /util/__pycache__/data_manager.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeWonderland/super-survey-bot-desktop/a3b39a4203b0fe2b74d1cbe133770e2615eef74c/util/__pycache__/data_manager.cpython-36.pyc -------------------------------------------------------------------------------- /util/__pycache__/data_manager.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeWonderland/super-survey-bot-desktop/a3b39a4203b0fe2b74d1cbe133770e2615eef74c/util/__pycache__/data_manager.cpython-37.pyc -------------------------------------------------------------------------------- /util/__pycache__/network_manager.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeWonderland/super-survey-bot-desktop/a3b39a4203b0fe2b74d1cbe133770e2615eef74c/util/__pycache__/network_manager.cpython-36.pyc -------------------------------------------------------------------------------- /util/__pycache__/network_manager.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeWonderland/super-survey-bot-desktop/a3b39a4203b0fe2b74d1cbe133770e2615eef74c/util/__pycache__/network_manager.cpython-37.pyc -------------------------------------------------------------------------------- /util/__pycache__/swagbucks.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeWonderland/super-survey-bot-desktop/a3b39a4203b0fe2b74d1cbe133770e2615eef74c/util/__pycache__/swagbucks.cpython-36.pyc -------------------------------------------------------------------------------- /util/__pycache__/swagbucks.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeWonderland/super-survey-bot-desktop/a3b39a4203b0fe2b74d1cbe133770e2615eef74c/util/__pycache__/swagbucks.cpython-37.pyc -------------------------------------------------------------------------------- /util/data_manager.py: -------------------------------------------------------------------------------- 1 | import shelve 2 | import uuid 3 | 4 | 5 | class SSBDataManager: 6 | def __init__(self): 7 | self.db = shelve.open('data/ssb_data') 8 | 9 | def input_data(self, data): 10 | if "QUESTION" in data and "ANSWERS" in data: 11 | self.db[data["QUESTION"]] = data["ANSWERS"] 12 | 13 | def get_answer(self, question): 14 | if question in self.db.keys(): 15 | return self.db[question] 16 | 17 | else: 18 | return None 19 | 20 | def set_id(self, user_id): 21 | self.db["USER_ID"] = user_id 22 | 23 | def get_id(self): 24 | # Check for existence of USER_ID 25 | if "USER_ID" in self.db.keys(): 26 | return self.db["USER_ID"] 27 | 28 | else: 29 | # Generate ID 30 | user_id = str(uuid.uuid4()) 31 | 32 | # Put ID in db 33 | self.db["USER_ID"] = user_id 34 | 35 | return user_id 36 | 37 | def __del__(self): 38 | try: 39 | self.db.close() 40 | 41 | except AttributeError: 42 | print("data manager has no db reference upon close") 43 | -------------------------------------------------------------------------------- /util/network_manager.py: -------------------------------------------------------------------------------- 1 | """async_client 2 | Champlain College CSI-235, Spring 2018 3 | Prof. Josh Auerbach 4 | Bare bones example of asynchronously receiving 5 | data from server and user input from stdin 6 | 7 | Last modified as 'AsycClient' for 'Chatterbox' by Alice Easter && Eric Cacciavillani on 4/26/18 8 | 9 | Last modified as 'NetworkManager' for 'Super Survey Bot Desktop' by Alice Easter on 4/26/18 10 | """ 11 | import json 12 | import ssl 13 | import struct 14 | import asyncio 15 | 16 | 17 | class NetworkManager: 18 | loop = None 19 | client = None 20 | main_app = None 21 | 22 | def __init__(self, main_app, server_name='localhost'): 23 | # Establish Connection to Main App 24 | NetworkManager.main_app = main_app 25 | 26 | # Get Async Event Loop 27 | NetworkManager.loop = asyncio.get_event_loop() 28 | 29 | # we only need one client instance 30 | NetworkManager.client = AsyncClient(main_app.get_id()) 31 | 32 | coro = NetworkManager.loop.create_connection(lambda: NetworkManager.client, 33 | host=server_name, 34 | port=9000) 35 | 36 | # SSL Version 37 | # the lambda client serves as a factory that just returns 38 | # the client instance we just created 39 | # purpose = ssl.Purpose.SERVER_AUTH 40 | # 41 | # if server_name == 'localhost': 42 | # context = ssl.create_default_context(purpose, cafile="ca.crt") 43 | # 44 | # else: 45 | # context = ssl.create_default_context(purpose, cafile=None) 46 | # 47 | # coro = NetworkManager.loop.create_connection(lambda: NetworkManager.client, 48 | # host=server_name, 49 | # port=9000, 50 | # ssl=context, 51 | # server_hostname=server_name) 52 | 53 | NetworkManager.loop.run_until_complete(coro) 54 | 55 | # Start a task which reads from standard input 56 | # asyncio.async(handle_user_input(NetworkManager.loop, NetworkManager.client)) 57 | 58 | try: 59 | NetworkManager.loop.run_forever() 60 | finally: 61 | NetworkManager.loop.close() 62 | 63 | 64 | class AsyncClient(asyncio.Protocol): 65 | def __init__(self, user_id): 66 | self.__buffer = "" 67 | self.is_logged_in = False 68 | self.user_id = user_id 69 | self.data_len = 0 70 | self.device_type = "DESKTOP" 71 | self.transport = None 72 | self.has_companion = False 73 | 74 | def connection_made(self, transport): 75 | self.transport = transport 76 | self.is_logged_in = False 77 | 78 | self.login() 79 | 80 | def login(self): 81 | login_data = { 82 | "DATA_TYPE": "USER_ID", 83 | "USER_ID": self.user_id 84 | } 85 | 86 | self.send_message(login_data) 87 | 88 | # Client sends message 89 | def send_message(self, data): 90 | data["DEVICE_TYPE"] = self.device_type 91 | 92 | # Encode Data 93 | data = json.dumps(data) 94 | data = data.encode("ascii") 95 | 96 | msg = b'' 97 | msg += struct.pack("!I", len(data)) 98 | msg += data 99 | self.transport.write(msg) 100 | 101 | # Handles the client reciving data 102 | def data_received(self, data): 103 | """simply prints any data that is received""" 104 | # Get data into usable format 105 | if self.__buffer == '': 106 | # Find first brace and offset the data by that 107 | brace_index = data.find(b'{') 108 | self.data_len = struct.unpack("!I", data[0:brace_index])[0] 109 | data = data[brace_index:(self.data_len + brace_index)] 110 | 111 | data = data.decode('ascii') 112 | self.__buffer += data 113 | 114 | # Buffer contains full message 115 | if len(self.__buffer) == self.data_len: 116 | 117 | # Extract to JSON object 118 | data = json.loads(self.__buffer) 119 | 120 | # Clear pre and post 121 | self.__buffer = '' 122 | self.data_len = 0 123 | 124 | print(data) 125 | 126 | key = data["DATA_TYPE"] 127 | 128 | # Check json key value 129 | if key == "LOGIN_DATA": 130 | if data["LOGIN_SUCCESSFUL"]: 131 | self.is_logged_in = True 132 | print('\nSuccessfully Logged In') 133 | else: 134 | # TODO: CREATE VISUAL FEEDBACK FOR USER 135 | print("ISSUE LOGGING IN") 136 | 137 | # ---- 138 | elif key == "ANSWER_DATA": 139 | self.answer_question(data) 140 | 141 | # ---- 142 | elif key == "QUESTION_REQUEST": 143 | self.send_question() 144 | 145 | # ---- 146 | elif key == "COMPANION_LOST": 147 | pass 148 | 149 | # Encapsulates error and other servers' additional features 150 | else: 151 | # If we get something we aren't expecting, print it 152 | print("UNEXPECTED RESP FROM SERVER - " + key) 153 | 154 | # Send question data from main app to server for remote answering 155 | def send_question(self): 156 | question_data = NetworkManager.main_app.get_question() 157 | question_data["DATA_TYPE"] = "QUESTION_DATA" 158 | 159 | self.send_message(question_data) 160 | 161 | # TODO: Send answer data to server for backup 162 | def send_answer(self, data): 163 | pass 164 | 165 | # Send answer data to main application 166 | @staticmethod 167 | def answer_question(data): 168 | """ 169 | Take in answer data from server, 170 | format said data for our answering system, 171 | then forward the answer to main app 172 | :param data: 173 | :return: 174 | """ 175 | 176 | NetworkManager.main_app.answer_question(data) 177 | 178 | # When the client is disconnected from the server 179 | def connection_lost(self, exc): 180 | print('Connection to server lost') 181 | print('(Press RET to exit)') 182 | self.is_logged_in = False 183 | 184 | NetworkManager.loop.run_in_executor(None, input, "") 185 | exit(0) 186 | -------------------------------------------------------------------------------- /util/swagbucks.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | import time 3 | import platform 4 | import os 5 | import random 6 | 7 | 8 | class SwagbucksCrawler: 9 | def __init__(self): 10 | # determine current os 11 | system = platform.system() 12 | 13 | # fetch appropriate driver 14 | self.driver = webdriver.Chrome("drivers/" + system + "/chromedriver") 15 | 16 | # load up the login page 17 | self.driver.get("https://www.swagbucks.com/p/login") 18 | 19 | # while until the user has logged in 20 | while "Login | Swagbucks" in self.driver.title: 21 | time.sleep(5) 22 | 23 | # navigate to the survey page 24 | self.driver.get("https://www.swagbucks.com/surveys") 25 | 26 | # since we called the survey page via js 27 | # we wait for the survey page to load 28 | while "Gold Surveys | Swagbucks" not in self.driver.title: 29 | time.sleep(5) 30 | 31 | def get_question(self): 32 | return self.driver.execute_script(open("./js/get_question.js").read()) 33 | 34 | def send_answer(self, user_answer): 35 | # send answer to page 36 | self.driver.execute_script(open("./js/answer_question.js").read(), user_answer) 37 | 38 | # Emulate decision making time for humans 39 | time.sleep(random.randint(3, 5)) 40 | 41 | # return new question 42 | return self.get_question() 43 | 44 | 45 | class SwagbucksTestCrawler(): 46 | def get_question(self): 47 | return {'ANSWERS': [{'DATA_VALUE': '1', 'TEXT': 'First Person Shooter/Action (e.g. Call of Duty)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '2', 'TEXT': '3rd Person Shooter/Action (e.g. Gears of War)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '4', 'TEXT': '3rd Person Adventure (e.g. Super Mario Galaxy)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '7', 'TEXT': 'Point & Click Adventure (e.g. Monkey Island)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '8', 'TEXT': 'Life Simulations (e.g. The Sims)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '10', 'TEXT': 'Music (e.g. Rockband)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '12', 'TEXT': 'Sports: General (e.g. FIFA)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '15', 'TEXT': 'Real Time Strategy (e.g. Command & Conquer)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '17', 'TEXT': 'Role Playing Game: General (e.g. Final Fantasy)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '19', 'TEXT': 'Massively Multiplayer Online: Role Playing (e.g. Warcraft)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '21', 'TEXT': 'Racing: General (e.g. Need for Speed)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '23', 'TEXT': 'Flight Simulation (e.g. MS Flight Simulator)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '25', 'TEXT': 'Fighting (e.g. Street Fighter)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '28', 'TEXT': 'Puzzle (e.g. Professor Layton)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '29', 'TEXT': 'Party Games (e.g. Wii Sports)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '32', 'TEXT': 'Casual (e.g. Facebook games)'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '33', 'TEXT': 'Other'}, {'DATA_VALUE': None, 'TEXT': ''}, {'DATA_VALUE': '34', 'TEXT': "I don't play video/computer games"}], 'QUESTION': 'What kind(s) of video/computer games do you play?', 'TYPE': 'CHECKBOX'} 48 | 49 | def send_answer(self, user_answer): 50 | print(user_answer) 51 | return self.get_question() 52 | 53 | @staticmethod 54 | def answer_question_cli(question_data): 55 | print(question_data["QUESTION"]) 56 | 57 | for answer_option in question_data["ANSWERS"]: 58 | if answer_option["DATA_VALUE"] is not None: 59 | print(answer_option["DATA_VALUE"] + ") " + answer_option["TEXT"]) 60 | 61 | user_answer = None 62 | 63 | while user_answer is None: 64 | user_answer = input("Which answer(s) do you choose (enter the number(s) as comma seperated list): ") 65 | 66 | for user_choice in user_answer.split(','): 67 | if user_choice not in map(lambda choice: choice["DATA_VALUE"], question_data["ANSWERS"]): 68 | user_answer = None 69 | 70 | return user_answer 71 | -------------------------------------------------------------------------------- /views/__pycache__/question_screen.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeWonderland/super-survey-bot-desktop/a3b39a4203b0fe2b74d1cbe133770e2615eef74c/views/__pycache__/question_screen.cpython-36.pyc -------------------------------------------------------------------------------- /views/__pycache__/question_screen.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeWonderland/super-survey-bot-desktop/a3b39a4203b0fe2b74d1cbe133770e2615eef74c/views/__pycache__/question_screen.cpython-37.pyc -------------------------------------------------------------------------------- /views/dashboard_screen.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeWonderland/super-survey-bot-desktop/a3b39a4203b0fe2b74d1cbe133770e2615eef74c/views/dashboard_screen.py -------------------------------------------------------------------------------- /views/question_screen.py: -------------------------------------------------------------------------------- 1 | from kivy.lang import Builder 2 | from kivy.uix.gridlayout import GridLayout 3 | from kivy.properties import StringProperty 4 | from kivy.uix.togglebutton import ToggleButton 5 | 6 | Builder.load_string(""" 7 | : 8 | id: question_screen 9 | cols: 1 10 | Label: 11 | id: question_text 12 | text: root.current_question 13 | size_hint_y: None 14 | height: '48dp' 15 | GridLayout: 16 | id: answer_container 17 | cols: 2 18 | padding: 5,5,5,5 19 | AnchorLayout: 20 | size_hint_y: None 21 | height: '48dp' 22 | Button: 23 | id: answer_button 24 | size_hint_y: None 25 | height: '48dp' 26 | size_hint_x: None 27 | width: '80dp' 28 | text: 'Confirm' 29 | anchor_x: 'center' 30 | on_press: root.answer_question() 31 | 32 | """) 33 | 34 | 35 | class QuestionScreen(GridLayout): 36 | current_question = StringProperty() 37 | 38 | def __init__(self, **kwargs): 39 | super(QuestionScreen, self).__init__(**kwargs) 40 | 41 | self.current_question = 'Hello World!' 42 | 43 | def set_question(self, question_data): 44 | print(question_data) 45 | if question_data is not None: 46 | self.current_question = question_data["QUESTION"] 47 | 48 | if question_data["TYPE"] == 'CHECKBOX': 49 | for answer_option in question_data["ANSWERS"]: 50 | if answer_option["DATA_VALUE"] is not None: 51 | option = ToggleButton( 52 | text=answer_option["TEXT"], 53 | id=answer_option["DATA_VALUE"] 54 | ) 55 | 56 | self.ids['answer_container'].add_widget(option) 57 | 58 | elif question_data["TYPE"] == 'SELECT': 59 | for answer_option in question_data["ANSWERS"]: 60 | print("OKAY") 61 | if answer_option["DATA_VALUE"] is not None: 62 | option = ToggleButton( 63 | text=answer_option["TEXT"], 64 | id=answer_option["DATA_VALUE"], 65 | group='radio' 66 | ) 67 | 68 | self.ids['answer_container'].add_widget(option) 69 | 70 | def answer_question(self): 71 | # Get list of all answer options 72 | answers = self.ids['answer_container'].children 73 | 74 | # Filter answers for selected ones 75 | answers = list( 76 | filter( 77 | lambda x: x.state == 'down', 78 | answers 79 | ) 80 | ) 81 | 82 | # Get text of answers 83 | answer_labels = list( 84 | map( 85 | lambda x: x.text, 86 | answers 87 | ) 88 | ) 89 | 90 | # Get answer id list 91 | answer_values = list( 92 | map( 93 | lambda x: x.id, 94 | answers 95 | ) 96 | ) 97 | 98 | # Formatting Data 99 | answer_values = ','.join(answer_values) 100 | 101 | # Clear the board 102 | self.ids['answer_container'].clear_widgets() 103 | 104 | # Send back data 105 | self.parent.parent.answer_question({ 106 | "QUESTION": self.current_question, 107 | "ANSWER_LABELS": answer_labels, 108 | "ANSWER_VALUES": answer_values 109 | }) 110 | --------------------------------------------------------------------------------