|
| 1 | +#!/usr/bin/env python |
| 2 | +# -*- coding: utf-8 -*- |
| 3 | + |
| 4 | +from codebender_testing.config import get_path |
| 5 | +import disqusapi |
| 6 | +import requests |
| 7 | +import simplejson |
| 8 | +import base64 |
| 9 | +import hashlib |
| 10 | +import hmac |
| 11 | +import time |
| 12 | +import random |
| 13 | +import os |
| 14 | +import re |
| 15 | + |
| 16 | + |
| 17 | +FORUM = 'codebender-cc' |
| 18 | +AUTHOR_NAME = 'codebender' |
| 19 | +AUTHOR_URL = 'https://codebender.cc/user/codebender' |
| 20 | +DISQUS_REQUESTS_PER_HOUR = 1000 |
| 21 | +DISQUS_WAIT = (DISQUS_REQUESTS_PER_HOUR / 60) / 60 |
| 22 | +CHANGE_LOG = 'examples_compile_log.json' |
| 23 | +DISQUS_COMMENTS = 'disqus_comments.json' |
| 24 | +EXAMPLES_WITHOUT_LIBRARY_DB = 'examples_without_library.json' |
| 25 | + |
| 26 | + |
| 27 | +class DisqusWrapper: |
| 28 | + def __init__(self, log_time): |
| 29 | + self.log_time = log_time |
| 30 | + self.DISQUS_API_SECRET = os.getenv('DISQUS_API_SECRET', None) |
| 31 | + self.DISQUS_API_PUBLIC = os.getenv('DISQUS_API_PUBLIC', None) |
| 32 | + self.DISQUS_ACCESS_TOKEN = os.getenv('DISQUS_ACCESS_TOKEN', None) |
| 33 | + self.user = { |
| 34 | + 'id': os.getenv('DISQUS_SSO_ID', None), |
| 35 | + 'username': os.getenv('DISQUS_SSO_USERNAME', None), |
| 36 | + 'email': os.getenv('DISQUS_SSO_EMAIL', None), |
| 37 | + } |
| 38 | + self.SSO_KEY = self.get_disqus_sso(self.user) |
| 39 | + self.disqus = disqusapi.DisqusAPI(api_secret=self.DISQUS_API_SECRET, public_key=self.DISQUS_API_PUBLIC, remote_auth=self.SSO_KEY) |
| 40 | + self.change_log = {} |
| 41 | + self.last_post = None |
| 42 | + self.last_library = None |
| 43 | + |
| 44 | + with open(get_path('data', DISQUS_COMMENTS)) as f: |
| 45 | + self.messages = simplejson.loads(f.read()) |
| 46 | + |
| 47 | + with open(get_path('data', EXAMPLES_WITHOUT_LIBRARY_DB)) as f: |
| 48 | + self.examples_without_library = simplejson.loads(f.read()) |
| 49 | + |
| 50 | + def get_disqus_sso(self, user): |
| 51 | + # create a JSON packet of our data attributes |
| 52 | + data = simplejson.dumps(user) |
| 53 | + # encode the data to base64 |
| 54 | + message = base64.b64encode(data) |
| 55 | + # generate a timestamp for signing the message |
| 56 | + timestamp = int(time.time()) |
| 57 | + # generate our hmac signature |
| 58 | + sig = hmac.HMAC(self.DISQUS_API_SECRET, '%s %s' % (message, timestamp), hashlib.sha1).hexdigest() |
| 59 | + return "{0} {1} {2}".format(message, sig, timestamp) |
| 60 | + |
| 61 | + def update_comment(self, sketch, results, current_date, log_entry, openFailFlag, counter, total_sketches): |
| 62 | + # Comment examples |
| 63 | + if not openFailFlag: |
| 64 | + log_entry = self.handle_example_comment(sketch, results, current_date, log_entry) |
| 65 | + |
| 66 | + # Comment libraries when finished with the examples |
| 67 | + library_match = re.match(r'.+\/example\/(.+)\/.+', sketch) |
| 68 | + library = None |
| 69 | + if library_match: |
| 70 | + library = library_match.group(1) |
| 71 | + if not self.last_library: |
| 72 | + self.last_library = library |
| 73 | + if library and library != self.last_library and (library not in self.examples_without_library or counter >= total_sketches-1): |
| 74 | + log_entry = self.handle_library_comment(library, current_date, log_entry) |
| 75 | + last_library = library |
| 76 | + |
| 77 | + return log_entry |
| 78 | + |
| 79 | + def handle_library_comment(self, library, current_date, log): |
| 80 | + url = '/library/' + library |
| 81 | + identifier = 'ident:' + url |
| 82 | + paginator = disqusapi.Paginator(self.disqus.api.threads.list, forum=FORUM, thread=identifier, method='GET') |
| 83 | + if paginator: |
| 84 | + for page in paginator: |
| 85 | + post_id, existing_message = self.get_posts(page['id']) |
| 86 | + if post_id and existing_message: |
| 87 | + new_message = self.messages['library'].replace('TEST_DATE', current_date) |
| 88 | + if url not in log: |
| 89 | + log[url] = {} |
| 90 | + log[url]['comment'] = self.update_post(post_id, new_message) |
| 91 | + else: |
| 92 | + log[url][comment] = False |
| 93 | + return log |
| 94 | + |
| 95 | + def handle_example_comment(self, url, results, current_date, log): |
| 96 | + identifier = url.replace('https://codebender.cc', '') |
| 97 | + identifier = 'ident:' + identifier |
| 98 | + paginator = disqusapi.Paginator(self.disqus.api.threads.list, forum=FORUM, thread=identifier, method='GET') |
| 99 | + if paginator: |
| 100 | + for page in paginator: |
| 101 | + post_id, existing_message = self.get_posts(page['id']) |
| 102 | + if post_id and existing_message: |
| 103 | + boards = [] |
| 104 | + for result in results: |
| 105 | + if result['status'] == 'success': |
| 106 | + board = result['board'] |
| 107 | + if re.match(r'Arduino Mega.+', board): |
| 108 | + board = 'Arduino Mega' |
| 109 | + boards.append(board) |
| 110 | + |
| 111 | + new_message = self.messages['example_fail'].replace('TEST_DATE', current_date) |
| 112 | + if len(boards) > 0: |
| 113 | + new_message = self.messages['example_success'].replace('TEST_DATE', current_date).replace('BOARDS_LIST', ', '.join(boards)) |
| 114 | + log[url]['comment'] = self.update_post(post_id, new_message) |
| 115 | + break |
| 116 | + else: |
| 117 | + log[url]['comment'] = False |
| 118 | + return log |
| 119 | + |
| 120 | + def get_posts(self, thread_id): |
| 121 | + post_found = False |
| 122 | + post_id = None |
| 123 | + raw_message = None |
| 124 | + paginator = disqusapi.Paginator(self.disqus.api.posts.list, forum=FORUM, thread=thread_id, order='asc', method='GET') |
| 125 | + if paginator: |
| 126 | + for result in paginator: |
| 127 | + if result['author']['name'] == AUTHOR_NAME and result['author']['url'] == AUTHOR_URL: |
| 128 | + post_id = result['id'] |
| 129 | + raw_message = result['raw_message'] |
| 130 | + break |
| 131 | + return post_id, raw_message |
| 132 | + |
| 133 | + def update_post(self, post_id, message): |
| 134 | + if not self.last_post: |
| 135 | + self.last_post = message |
| 136 | + elif re.match(r'^.+\.$', self.last_post): |
| 137 | + message = message[:-1] |
| 138 | + self.last_post = message |
| 139 | + try: |
| 140 | + response = self.disqus.posts.update(api_secret=self.DISQUS_API_SECRET, api_key=self.DISQUS_API_PUBLIC, remote_auth=self.SSO_KEY, access_token=self.DISQUS_ACCESS_TOKEN, post=post_id, message=message, method='POST') |
| 141 | + if response['raw_message'] == message: |
| 142 | + return True |
| 143 | + return False |
| 144 | + except Exception as error: |
| 145 | + print 'Error:', error |
| 146 | + return False |
0 commit comments