def update_procedure(self, thing_id, created, lifetime, last_updated, interval):
        pass

    def general_action(self, body, thing_id, subreddit, username):
        if not subreddit.lower() in self.APPROVE or 'leafeator' in username.lower():
            # filtering out all other stuff
            return False

        result = self.REGEX.search(body)
        if result:
            self.oauth.refresh()
            self.session._add_comment(thing_id, self.RESPONSE)
            return True
        return False

    def on_new_message(self, message):
        pass


def init(database):
    """Init Call from module importer to return only the object itself, rather than the module."""
    return LeafeatorBot(database)


if __name__ == '__main__':
    from praw import Reddit
    r = Reddit(user_agent='Manual Testing')
    cmt = r.get_info(thing_id='t1_cud1d76')
    lb = LeafeatorBot(None)
    lb.execute_comment(cmt)
class OAuth2RedditTest(PRAWTest):
    def setUp(self):
        self.configure()
        self.r = Reddit(USER_AGENT, site_name='reddit_oauth_test',
                        disable_update_check=True)

    def test_authorize_url(self):
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired, self.r.get_authorize_url,
                          'dummy_state')
        self.r.set_oauth_app_info(self.r.config.client_id,
                                  self.r.config.client_secret,
                                  self.r.config.redirect_uri)
        url, params = self.r.get_authorize_url('...').split('?', 1)
        self.assertTrue('api/v1/authorize/' in url)
        params = dict(x.split('=', 1) for x in params.split('&'))
        expected = {'client_id': self.r.config.client_id,
                    'duration': 'temporary',
                    'redirect_uri': ('https%3A%2F%2F127.0.0.1%3A65010%2F'
                                     'authorize_callback'),
                    'response_type': 'code', 'scope': 'identity',
                    'state': '...'}
        self.assertEqual(expected, params)

    @betamax()
    def test_get_access_information(self):
        # If this test fails, the following URL will need to be visted in order
        # to obtain a new code to pass to `get_access_information`:
        # self.r.get_authorize_url('...')
        token = self.r.get_access_information('MQALrr1di8GzcnT8szbTWhLcBUQ')
        expected = {'access_token': self.r.access_token,
                    'refresh_token': None,
                    'scope': set(('identity',))}
        self.assertEqual(expected, token)
        self.assertEqual('PyAPITestUser2', text_type(self.r.user))

    @betamax()
    def test_get_access_information_with_invalid_code(self):
        self.assertRaises(errors.OAuthInvalidGrant,
                          self.r.get_access_information, 'invalid_code')

    def test_invalid_app_access_token(self):
        self.r.clear_authentication()
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired,
                          self.r.get_access_information, 'dummy_code')

    def test_invalid_app_authorize_url(self):
        self.r.clear_authentication()
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired,
                          self.r.get_authorize_url, 'dummy_state')

    @betamax()
    def test_invalid_set_access_credentials(self):
        self.assertRaises(errors.OAuthInvalidToken,
                          self.r.set_access_credentials,
                          set(('identity',)), 'dummy_access_token')

    def test_oauth_scope_required(self):
        self.r.set_oauth_app_info('dummy_client', 'dummy_secret', 'dummy_url')
        self.r.set_access_credentials(set('dummy_scope',), 'dummy_token')
        self.assertRaises(errors.OAuthScopeRequired, self.r.get_me)

    @betamax()
    def test_scope_edit(self):
        self.r.refresh_access_information(self.refresh_token['edit'])
        submission = Submission.from_id(self.r, self.submission_edit_id)
        self.assertEqual(submission, submission.edit('Edited text'))

    @betamax()
    def test_scope_history(self):
        self.r.refresh_access_information(self.refresh_token['history'])
        self.assertTrue(list(self.r.get_redditor(self.un).get_upvoted()))

    @betamax()
    def test_scope_identity(self):
        self.r.refresh_access_information(self.refresh_token['identity'])
        self.assertEqual(self.un, self.r.get_me().name)

    @betamax()
    def test_scope_modconfig(self):
        self.r.refresh_access_information(self.refresh_token['modconfig'])
        self.r.get_subreddit(self.sr).set_settings('foobar')
        retval = self.r.get_subreddit(self.sr).get_stylesheet()
        self.assertTrue('images' in retval)

    @betamax()
    def test_scope_modflair(self):
        self.r.refresh_access_information(self.refresh_token['modflair'])
        self.r.get_subreddit(self.sr).set_flair(self.un, 'foobar')

    @betamax()
    def test_scope_modlog(self):
        num = 50
        self.r.refresh_access_information(self.refresh_token['modlog'])
        result = self.r.get_subreddit(self.sr).get_mod_log(limit=num)
        self.assertEqual(num, len(list(result)))

    @betamax()
    def test_scope_modothers_modself(self):
        subreddit = self.r.get_subreddit(self.sr)
        self.r.refresh_access_information(self.refresh_token['modothers'])
        subreddit.add_moderator(self.other_user_name)

        # log in as other user
        self.r.refresh_access_information(self.other_refresh_token['modself'])
        self.r.accept_moderator_invite(self.sr)

        # now return to original user.
        self.r.refresh_access_information(self.refresh_token['modothers'])
        subreddit.remove_moderator(self.other_user_name)

    @betamax()
    def test_scope_modposts(self):
        self.r.refresh_access_information(self.refresh_token['modposts'])
        Submission.from_id(self.r, self.submission_edit_id).remove()

    @betamax()
    def test_scope_mysubreddits(self):
        self.r.refresh_access_information(self.refresh_token['mysubreddits'])
        self.assertTrue(list(self.r.get_my_moderation()))

    @betamax()
    def test_scope_creddits(self):
        # Assume there are insufficient creddits.
        self.r.refresh_access_information(
            self.refresh_token['creddits'])
        redditor = self.r.get_redditor('bboe')
        sub = self.r.get_submission(url=self.comment_url)

        # Test error conditions
        self.assertRaises(TypeError, sub.gild, months=1)
        for value in (False, 0, -1, '0', '-1'):
            self.assertRaises(TypeError, redditor.gild, value)

        # Test object gilding
        self.assertRaises(errors.InsufficientCreddits, redditor.gild)
        self.assertRaises(errors.InsufficientCreddits, sub.gild)
        self.assertRaises(errors.InsufficientCreddits, sub.comments[0].gild)

    @betamax()
    def test_scope_privatemessages(self):
        self.r.refresh_access_information(
            self.refresh_token['privatemessages'])
        self.assertTrue(list(self.r.get_inbox()))

    @betamax()
    def test_scope_read(self):
        self.r.refresh_access_information(self.refresh_token['read'])
        self.assertTrue(self.r.get_subreddit(self.priv_sr).subscribers > 0)
        fullname = '{0}_{1}'.format(self.r.config.by_object[Submission],
                                    self.priv_submission_id)
        method1 = self.r.get_info(thing_id=fullname)
        method2 = self.r.get_submission(submission_id=self.priv_submission_id)
        self.assertEqual(method1, method2)

    @betamax()
    def test_scope_read_get_front_page(self):
        self.r.refresh_access_information(self.refresh_token['mysubreddits'])
        subscribed = list(self.r.get_my_subreddits(limit=None))
        self.r.refresh_access_information(self.refresh_token['read'])
        for post in self.r.get_front_page():
            self.assertTrue(post.subreddit in subscribed)

    @betamax()
    def test_scope_read_get_sub_listingr(self):
        self.r.refresh_access_information(self.refresh_token['read'])
        subreddit = self.r.get_subreddit(self.priv_sr)
        self.assertTrue(list(subreddit.get_top()))

    @betamax()
    def test_scope_read_get_submission_by_url(self):
        url = ("https://www.reddit.com/r/reddit_api_test_priv/comments/16kbb7/"
               "google/")
        self.r.refresh_access_information(self.refresh_token['read'])
        submission = Submission.from_url(self.r, url)
        self.assertTrue(submission.num_comments != 0)

    @betamax()
    def test_scope_read_priv_sr_comments(self):
        self.r.refresh_access_information(self.refresh_token['read'])
        self.assertTrue(list(self.r.get_comments(self.priv_sr)))

    @betamax()
    def test_scope_wikiread_wiki_page(self):
        self.r.refresh_access_information(self.refresh_token['wikiread'])
        self.assertTrue(self.r.get_wiki_page(self.sr, 'index'))

    @betamax()
    def test_scope_read_priv_sub_comments(self):
        self.r.refresh_access_information(self.refresh_token['read'])
        submission = Submission.from_id(self.r, self.priv_submission_id)
        self.assertTrue(submission.comments)

    @betamax()
    def test_scope_submit(self):
        self.r.refresh_access_information(self.refresh_token['submit'])
        result = self.r.submit(self.sr, 'OAuth Submit', text='Foo')
        self.assertTrue(isinstance(result, Submission))

    @betamax()
    def test_scope_subscribe(self):
        self.r.refresh_access_information(self.refresh_token['subscribe'])
        self.r.get_subreddit(self.sr).subscribe()

    @betamax()
    def test_scope_vote(self):
        self.r.refresh_access_information(self.refresh_token['vote'])
        submission = Submission.from_id(self.r, self.submission_edit_id)
        submission.clear_vote()

    @betamax()
    def test_set_access_credentials(self):
        self.assertTrue(self.r.user is None)
        result = self.r.refresh_access_information(
            self.refresh_token['identity'], update_session=False)
        self.assertTrue(self.r.user is None)
        self.r.set_access_credentials(**result)
        self.assertFalse(self.r.user is None)

    @betamax()
    def test_oauth_without_identy_doesnt_set_user(self):
        self.assertTrue(self.r.user is None)
        self.r.refresh_access_information(self.refresh_token['edit'])
        self.assertTrue(self.r.user is None)
Example #3
0
class OAuth2RedditTest(PRAWTest):
    def setUp(self):
        self.configure()
        self.r = Reddit(USER_AGENT, site_name='reddit_oauth_test',
                        disable_update_check=True)

    def test_authorize_url(self):
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired, self.r.get_authorize_url,
                          'dummy_state')
        self.r.set_oauth_app_info(self.r.config.client_id,
                                  self.r.config.client_secret,
                                  self.r.config.redirect_uri)
        url, params = self.r.get_authorize_url('...').split('?', 1)
        self.assertTrue('api/v1/authorize/' in url)
        params = dict(x.split('=', 1) for x in params.split('&'))
        expected = {'client_id': self.r.config.client_id,
                    'duration': 'temporary',
                    'redirect_uri': ('https%3A%2F%2F127.0.0.1%3A65010%2F'
                                     'authorize_callback'),
                    'response_type': 'code', 'scope': 'identity',
                    'state': '...'}
        self.assertEqual(expected, params)

    # @betamax() is currently broken for this test because the cassettes
    # are caching too aggressively and not performing a token refresh.
    def test_auto_refresh_token(self):
        self.r.refresh_access_information(self.refresh_token['identity'])
        old_token = self.r.access_token

        self.r.access_token += 'x'  # break the token
        self.r.user.refresh()
        current_token = self.r.access_token
        self.assertNotEqual(old_token, current_token)

        self.r.user.refresh()
        self.assertEqual(current_token, self.r.access_token)

    @betamax()
    def test_get_access_information(self):
        # If this test fails, the following URL will need to be visted in order
        # to obtain a new code to pass to `get_access_information`:
        # self.r.get_authorize_url('...')
        token = self.r.get_access_information('MQALrr1di8GzcnT8szbTWhLcBUQ')
        expected = {'access_token': self.r.access_token,
                    'refresh_token': None,
                    'scope': set(('identity',))}
        self.assertEqual(expected, token)
        self.assertEqual('PyAPITestUser2', text_type(self.r.user))

    @betamax()
    def test_get_access_information_with_invalid_code(self):
        self.assertRaises(errors.OAuthInvalidGrant,
                          self.r.get_access_information, 'invalid_code')

    def test_invalid_app_access_token(self):
        self.r.clear_authentication()
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired,
                          self.r.get_access_information, 'dummy_code')

    def test_invalid_app_authorize_url(self):
        self.r.clear_authentication()
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired,
                          self.r.get_authorize_url, 'dummy_state')

    @betamax()
    def test_invalid_set_access_credentials(self):
        self.assertRaises(errors.OAuthInvalidToken,
                          self.r.set_access_credentials,
                          set(('identity',)), 'dummy_access_token')

    def test_oauth_scope_required(self):
        self.r.set_oauth_app_info('dummy_client', 'dummy_secret', 'dummy_url')
        self.r.set_access_credentials(set('dummy_scope',), 'dummy_token')
        self.assertRaises(errors.OAuthScopeRequired, self.r.get_me)

    def test_raise_client_exception(self):
        def raise_client_exception(*args):
            raise errors.ClientException(*args)

        self.assertRaises(errors.ClientException, raise_client_exception)
        self.assertRaises(errors.ClientException, raise_client_exception,
                          'test')

        ce_message = errors.ClientException('Test')
        ce_no_message = errors.ClientException()
        self.assertEqual(ce_message.message, str(ce_message))
        self.assertEqual(ce_no_message.message, str(ce_no_message))

    def test_raise_http_exception(self):
        def raise_http_exception():
            raise errors.HTTPException('fakeraw')

        self.assertRaises(errors.HTTPException, raise_http_exception)
        http_exception = errors.HTTPException('fakeraw')
        self.assertEqual(http_exception.message, str(http_exception))

    def test_raise_oauth_exception(self):
        oerrormessage = "fakemessage"
        oerrorurl = "http://oauth.reddit.com/"

        def raise_oauth_exception():
            raise errors.OAuthException(oerrormessage, oerrorurl)

        self.assertRaises(errors.OAuthException, raise_oauth_exception)
        oauth_exception = errors.OAuthException(oerrormessage, oerrorurl)
        self.assertEqual(oauth_exception.message +
                         " on url {0}".format(oauth_exception.url),
                         str(oauth_exception))

    def test_raise_redirect_exception(self):
        apiurl = "http://api.reddit.com/"
        oauthurl = "http://oauth.reddit.com/"

        def raise_redirect_exception():
            raise errors.RedirectException(apiurl, oauthurl)

        self.assertRaises(errors.RedirectException, raise_redirect_exception)
        redirect_exception = errors.RedirectException(apiurl, oauthurl)
        self.assertEqual(redirect_exception.message, str(redirect_exception))

    @betamax()
    def test_scope_history(self):
        self.r.refresh_access_information(self.refresh_token['history'])
        self.assertTrue(list(self.r.get_redditor(self.un).get_upvoted()))

    @betamax()
    def test_scope_identity(self):
        self.r.refresh_access_information(self.refresh_token['identity'])
        self.assertEqual(self.un, self.r.get_me().name)

    @betamax()
    def test_scope_mysubreddits(self):
        self.r.refresh_access_information(self.refresh_token['mysubreddits'])
        self.assertTrue(list(self.r.get_my_moderation()))

    @betamax()
    def test_scope_creddits(self):
        # Assume there are insufficient creddits.
        self.r.refresh_access_information(
            self.refresh_token['creddits'])
        redditor = self.r.get_redditor('bboe')
        sub = self.r.get_submission(url=self.comment_url)

        # Test error conditions
        self.assertRaises(TypeError, sub.gild, months=1)
        for value in (False, 0, -1, '0', '-1'):
            self.assertRaises(TypeError, redditor.gild, value)

        # Test object gilding
        self.assertRaises(errors.InsufficientCreddits, redditor.gild)
        self.assertRaises(errors.InsufficientCreddits, sub.gild)
        self.assertRaises(errors.InsufficientCreddits, sub.comments[0].gild)

    @betamax()
    def test_scope_privatemessages(self):
        self.r.refresh_access_information(
            self.refresh_token['privatemessages'])
        self.assertTrue(list(self.r.get_inbox()))

    @betamax()
    def test_scope_read(self):
        self.r.refresh_access_information(self.refresh_token['read'])
        self.assertTrue(self.r.get_subreddit(self.priv_sr).subscribers > 0)
        fullname = '{0}_{1}'.format(self.r.config.by_object[Submission],
                                    self.priv_submission_id)
        method1 = self.r.get_info(thing_id=fullname)
        method2 = self.r.get_submission(submission_id=self.priv_submission_id)
        self.assertEqual(method1, method2)

    @betamax()
    def test_scope_read_get_front_page(self):
        self.r.refresh_access_information(self.refresh_token['mysubreddits'])
        subscribed = list(self.r.get_my_subreddits(limit=None))
        self.r.refresh_access_information(self.refresh_token['read'])
        for post in self.r.get_front_page():
            self.assertTrue(post.subreddit in subscribed)

    @betamax()
    def test_set_access_credentials(self):
        self.assertTrue(self.r.user is None)
        result = self.r.refresh_access_information(
            self.refresh_token['identity'], update_session=False)
        self.assertTrue(self.r.user is None)
        self.r.set_access_credentials(**result)
        self.assertFalse(self.r.user is None)

    @betamax()
    def test_solve_captcha(self):
        # Use the alternate account because it has low karma,
        # so we can test the captcha.
        self.r.refresh_access_information(self.other_refresh_token['submit'])
        original_stdin = sys.stdin
        sys.stdin = FakeStdin('ljgtoo')  # Comment this line when rebuilding
        self.r.submit(self.sr, 'captcha test', 'body')
        sys.stdin = original_stdin

    @betamax()
    def test_oauth_without_identy_doesnt_set_user(self):
        self.assertTrue(self.r.user is None)
        self.r.refresh_access_information(self.refresh_token['edit'])
        self.assertTrue(self.r.user is None)
Example #4
0
class OAuth2RedditTest(PRAWTest):
    def setUp(self):
        self.configure()
        self.r = Reddit(USER_AGENT,
                        site_name='reddit_oauth_test',
                        disable_update_check=True)

    def test_authorize_url(self):
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired, self.r.get_authorize_url,
                          'dummy_state')
        self.r.set_oauth_app_info(self.r.config.client_id,
                                  self.r.config.client_secret,
                                  self.r.config.redirect_uri)
        url, params = self.r.get_authorize_url('...').split('?', 1)
        self.assertTrue('api/v1/authorize/' in url)
        params = dict(x.split('=', 1) for x in params.split('&'))
        expected = {
            'client_id':
            self.r.config.client_id,
            'duration':
            'temporary',
            'redirect_uri': ('https%3A%2F%2F127.0.0.1%3A65010%2F'
                             'authorize_callback'),
            'response_type':
            'code',
            'scope':
            'identity',
            'state':
            '...'
        }
        self.assertEqual(expected, params)

    @betamax()
    @mock_sys_stream("stdin")
    def test_empty_captcha_file(self):
        # Use the alternate account because it has low karma,
        # so we can test the captcha.
        self.r.refresh_access_information(self.other_refresh_token['submit'])
        self.assertRaises(errors.InvalidCaptcha, self.r.submit, self.sr,
                          'captcha test will fail', 'body')

    @betamax()
    def test_get_access_information(self):
        # If this test fails, the following URL will need to be visted in order
        # to obtain a new code to pass to `get_access_information`:
        # self.r.get_authorize_url('...')
        token = self.r.get_access_information('MQALrr1di8GzcnT8szbTWhLcBUQ')
        expected = {
            'access_token': self.r.access_token,
            'refresh_token': None,
            'scope': set(('identity', ))
        }
        self.assertEqual(expected, token)
        self.assertEqual('PyAPITestUser2', text_type(self.r.user))

    @betamax()
    def test_get_access_information_with_invalid_code(self):
        self.assertRaises(errors.OAuthInvalidGrant,
                          self.r.get_access_information, 'invalid_code')

    @betamax()
    @mock_sys_stream("stdin")
    def test_inject_captcha_into_kwargs_and_raise(self):
        # Use the alternate account because it has low karma,
        # so we can test the captcha.
        self.r.refresh_access_information(self.other_refresh_token['submit'])

        # praw doesn't currently add the captcha into kwargs so lets
        # write a function in which it would and alias it to Reddit.submit
        @decorators.restrict_access(scope='submit')
        @decorators.require_captcha
        def submit_alias(r, sr, title, text, **kw):
            return self.r.submit.__wrapped__.__wrapped__(
                r, sr, title, text, captcha=kw.get('captcha'))

        self.assertRaises(errors.InvalidCaptcha, submit_alias, self.r, self.sr,
                          'captcha test will fail', 'body')

    def test_invalid_app_access_token(self):
        self.r.clear_authentication()
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired,
                          self.r.get_access_information, 'dummy_code')

    def test_invalid_app_authorize_url(self):
        self.r.clear_authentication()
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired, self.r.get_authorize_url,
                          'dummy_state')

    @betamax()
    def test_invalid_set_access_credentials(self):
        self.assertRaises(errors.OAuthInvalidToken,
                          self.r.set_access_credentials, set(
                              ('identity', )), 'dummy_access_token')

    def test_oauth_scope_required(self):
        self.r.set_oauth_app_info('dummy_client', 'dummy_secret', 'dummy_url')
        self.r.set_access_credentials(set('dummy_scope', ), 'dummy_token')
        self.assertRaises(errors.OAuthScopeRequired, self.r.get_me)

    def test_raise_client_exception(self):
        def raise_client_exception(*args):
            raise errors.ClientException(*args)

        self.assertRaises(errors.ClientException, raise_client_exception)
        self.assertRaises(errors.ClientException, raise_client_exception,
                          'test')

        ce_message = errors.ClientException('Test')
        ce_no_message = errors.ClientException()
        self.assertEqual(ce_message.message, str(ce_message))
        self.assertEqual(ce_no_message.message, str(ce_no_message))

    def test_raise_http_exception(self):
        def raise_http_exception():
            raise errors.HTTPException('fakeraw')

        self.assertRaises(errors.HTTPException, raise_http_exception)
        http_exception = errors.HTTPException('fakeraw')
        self.assertEqual(http_exception.message, str(http_exception))

    def test_raise_oauth_exception(self):
        oerrormessage = "fakemessage"
        oerrorurl = "http://oauth.reddit.com/"

        def raise_oauth_exception():
            raise errors.OAuthException(oerrormessage, oerrorurl)

        self.assertRaises(errors.OAuthException, raise_oauth_exception)
        oauth_exception = errors.OAuthException(oerrormessage, oerrorurl)
        self.assertEqual(
            oauth_exception.message +
            " on url {0}".format(oauth_exception.url), str(oauth_exception))

    def test_raise_redirect_exception(self):
        apiurl = "http://api.reddit.com/"
        oauthurl = "http://oauth.reddit.com/"

        def raise_redirect_exception():
            raise errors.RedirectException(apiurl, oauthurl)

        self.assertRaises(errors.RedirectException, raise_redirect_exception)
        redirect_exception = errors.RedirectException(apiurl, oauthurl)
        self.assertEqual(redirect_exception.message, str(redirect_exception))

    @betamax()
    def test_scope_history(self):
        self.r.refresh_access_information(self.refresh_token['history'])
        self.assertTrue(list(self.r.get_redditor(self.un).get_upvoted()))

    @betamax()
    def test_scope_identity(self):
        self.r.refresh_access_information(self.refresh_token['identity'])
        self.assertEqual(self.un, self.r.get_me().name)

    @betamax()
    def test_scope_mysubreddits(self):
        self.r.refresh_access_information(self.refresh_token['mysubreddits'])
        self.assertTrue(list(self.r.get_my_moderation()))

    @betamax()
    def test_scope_creddits(self):
        # Assume there are insufficient creddits.
        self.r.refresh_access_information(self.refresh_token['creddits'])
        redditor = self.r.get_redditor('bboe')
        sub = self.r.get_submission(url=self.comment_url)

        # Test error conditions
        self.assertRaises(TypeError, sub.gild, months=1)
        for value in (False, 0, -1, '0', '-1', 37, '37'):
            self.assertRaises(TypeError, redditor.gild, value)

        # Test object gilding
        self.assertRaises(errors.InsufficientCreddits, redditor.gild)
        self.assertRaises(errors.InsufficientCreddits, sub.gild)
        self.assertRaises(errors.InsufficientCreddits, sub.comments[0].gild)

    @betamax()
    def test_scope_privatemessages(self):
        self.r.refresh_access_information(
            self.refresh_token['privatemessages'])
        self.assertTrue(list(self.r.get_inbox()))

    @betamax()
    def test_scope_read(self):
        self.r.refresh_access_information(self.refresh_token['read'])
        self.assertTrue(self.r.get_subreddit(self.priv_sr).subscribers > 0)
        fullname = '{0}_{1}'.format(self.r.config.by_object[Submission],
                                    self.priv_submission_id)
        method1 = self.r.get_info(thing_id=fullname)
        method2 = self.r.get_submission(submission_id=self.priv_submission_id)
        self.assertEqual(method1, method2)

    @betamax()
    def test_scope_read_get_front_page(self):
        self.r.refresh_access_information(self.refresh_token['mysubreddits'])
        subscribed = list(self.r.get_my_subreddits(limit=None))
        self.r.refresh_access_information(self.refresh_token['read'])
        for post in self.r.get_front_page():
            self.assertTrue(post.subreddit in subscribed)

    @betamax()
    def test_set_access_credentials(self):
        self.assertTrue(self.r.user is None)
        result = self.r.refresh_access_information(
            self.refresh_token['identity'], update_session=False)
        self.assertTrue(self.r.user is None)
        self.r.set_access_credentials(**result)
        self.assertFalse(self.r.user is None)

    @betamax()
    def test_set_access_credentials_with_list(self):
        self.assertTrue(self.r.user is None)
        result = self.r.refresh_access_information(
            self.refresh_token['identity'], update_session=False)
        self.assertTrue(self.r.user is None)
        result['scope'] = list(result['scope'])
        self.r.set_access_credentials(**result)
        self.assertFalse(self.r.user is None)

    @betamax()
    def test_set_access_credentials_with_string(self):
        self.assertTrue(self.r.user is None)
        result = self.r.refresh_access_information(
            self.refresh_token['identity'], update_session=False)
        self.assertTrue(self.r.user is None)
        result['scope'] = ' '.join(result['scope'])
        self.r.set_access_credentials(**result)
        self.assertFalse(self.r.user is None)

    @betamax()
    @mock_sys_stream("stdin", "ljgtoo")
    def test_solve_captcha(self):
        # Use the alternate account because it has low karma,
        # so we can test the captcha.
        self.r.refresh_access_information(self.other_refresh_token['submit'])
        self.r.submit(self.sr, 'captcha test', 'body')

    @betamax()
    @mock_sys_stream("stdin", "DFIRSW")
    def test_solve_captcha_on_bound_subreddit(self):
        # Use the alternate account because it has low karma,
        # so we can test the captcha.
        self.r.refresh_access_information(self.other_refresh_token['submit'])
        subreddit = self.r.get_subreddit(self.sr)

        # praw doesn't currently have a function in which require_captcha
        # gets a reddit instance from a subreddit and uses it, so lets
        # write a function in which it would and alias it to Reddit.submit
        @decorators.restrict_access(scope='submit')
        @decorators.require_captcha
        def submit_alias(sr, title, text, **kw):
            return self.r.submit.__wrapped__.__wrapped__(
                self.r, sr, title, text, captcha=kw.get('captcha'))

        submit_alias(subreddit, 'captcha test on bound subreddit', 'body')

    @betamax()
    def test_oauth_without_identy_doesnt_set_user(self):
        self.assertTrue(self.r.user is None)
        self.r.refresh_access_information(self.refresh_token['edit'])
        self.assertTrue(self.r.user is None)
class Reddit_Cleverbot:

  def __init__(self, username, password, subreddit='all', useragent=USERAGENT):
    self.username = username
    self.password = password
    self.useragent = useragent
    self.subreddit = subreddit
    self.reddit = Reddit(useragent)
    self.reddit.login(username, password)
    self.stopped = True
    self.thread = None
    self.done = set()
    self.conversations = dict()

  def random_hot_comment(self):
    sub = self.reddit.get_subreddit(self.subreddit)
    hot = [post for post in sub.get_hot(limit=25)]
    post = random.choice(hot)
    comments = praw.helpers.flatten_tree(post.comments)
    # filter the comments to remove already-replied ones
    comments = [comment for comment in comments if comment not in self.done and isinstance(comment, praw.objects.Comment)]
    return random.choice(comments[0:100])

  def random_comment(self):
    comments = self.reddit.get_comments(self.subreddit)
    # filter the comments to remove already-replied ones
    comments = [comment for comment in comments if comment not in self.done]
    return random.choice(comments)

  def get_summoned_comments(self):
    comments = self.reddit.get_comments(self.subreddit)
    children = [comment for comment in comments 
      if comment not in self.done and SUMMON in comment.body]
    # print "--> " + str(len(children)) + " summons found!"
    return [self.reddit.get_info(thing_id=comment.parent_id) for comment in children]

  def reply(self, comment):
    if self.reddit.get_info(thing_id=comment.parent_id).author.name == self.username:
      # TODO: handle a threaded conversation over restarts. will need a DB. ugh
      pass
    if comment.parent_id in self.conversations:
      cleverbot = self.conversations[comment.parent_id]
    else:
      cleverbot = Cleverbot()
    response = cleverbot.ask(comment.body)
    post = comment.reply(response)
    self.done.add(comment.id)
    self.conversations[post.id] = copy(cleverbot)

  def reply_unread(self, interval):
    for item in self.reddit.get_unread():
      if item.parent_id not in self.conversations:
        print "Could not find conversation! Ignoring for now."
        pass
      self.reply(item)
      item.mark_as_read()
      time.sleep(interval)

  def reply_to_summons(self):
    summons = self.get_summoned_comments()
    for comment in summons:
      self.reply(comment)

  def _run_random(self, interval):
    while not self.stopped:
      self.reply_unread(interval)
      self.reply(self.random_hot_comment())
      time.sleep(interval)

  def run_random(self, interval):
    self.stopped = False
    self.thread = Thread(target=self._run_random, args=(interval,))
    self.thread.start()

  def stop(self):
    self.stopped = True
    #self.thread.join()
Example #6
0
                return False

            self.oauth.refresh()
            self.session._add_comment(thing.name, self.RESPONSE)
            self.database.insert_into_storage(thread_id, self.BOT_NAME)
            return True
        return False

    def on_new_message(self, message):
        pass


def init(database):
    """Init Call from module importer to return only the object itself, rather than the module."""
    return LeafeatorBot(database)


if __name__ == "__main__":
    from praw import Reddit
    from core.DatabaseProvider import DatabaseProvider
    from core import LogProvider

    logger = LogProvider.setup_logging(log_level="DEBUG")
    db = DatabaseProvider()
    r = Reddit(user_agent="Manual Testing")
    subm = r.get_info(thing_id="t3_3ik036")
    cmt = r.get_info(thing_id="t1_cuilwo5")
    lb = LeafeatorBot(db)
    lb.execute_comment(cmt)
    # lb.execute_submission(subm)
Example #7
0
class OAuth2RedditTest(PRAWTest):
    def setUp(self):
        self.configure()
        self.r = Reddit(USER_AGENT,
                        site_name='reddit_oauth_test',
                        disable_update_check=True)

    def test_authorize_url(self):
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired, self.r.get_authorize_url,
                          'dummy_state')
        self.r.set_oauth_app_info(self.r.config.client_id,
                                  self.r.config.client_secret,
                                  self.r.config.redirect_uri)
        url, params = self.r.get_authorize_url('...').split('?', 1)
        self.assertTrue('api/v1/authorize/' in url)
        params = dict(x.split('=', 1) for x in params.split('&'))
        expected = {
            'client_id':
            self.r.config.client_id,
            'duration':
            'temporary',
            'redirect_uri': ('https%3A%2F%2F127.0.0.1%3A65010%2F'
                             'authorize_callback'),
            'response_type':
            'code',
            'scope':
            'identity',
            'state':
            '...'
        }
        self.assertEqual(expected, params)

    # @betamax() is currently broken for this test because the cassettes
    # are caching too aggressively and not performing a token refresh.
    def test_auto_refresh_token(self):
        self.r.refresh_access_information(self.refresh_token['identity'])
        old_token = self.r.access_token

        self.r.access_token += 'x'  # break the token
        self.r.user.refresh()
        current_token = self.r.access_token
        self.assertNotEqual(old_token, current_token)

        self.r.user.refresh()
        self.assertEqual(current_token, self.r.access_token)

    @betamax()
    def test_get_access_information(self):
        # If this test fails, the following URL will need to be visted in order
        # to obtain a new code to pass to `get_access_information`:
        # self.r.get_authorize_url('...')
        token = self.r.get_access_information('MQALrr1di8GzcnT8szbTWhLcBUQ')
        expected = {
            'access_token': self.r.access_token,
            'refresh_token': None,
            'scope': set(('identity', ))
        }
        self.assertEqual(expected, token)
        self.assertEqual('PyAPITestUser2', text_type(self.r.user))

    @betamax()
    def test_get_access_information_with_invalid_code(self):
        self.assertRaises(errors.OAuthInvalidGrant,
                          self.r.get_access_information, 'invalid_code')

    def test_invalid_app_access_token(self):
        self.r.clear_authentication()
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired,
                          self.r.get_access_information, 'dummy_code')

    def test_invalid_app_authorize_url(self):
        self.r.clear_authentication()
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired, self.r.get_authorize_url,
                          'dummy_state')

    @betamax()
    def test_invalid_set_access_credentials(self):
        self.assertRaises(errors.OAuthInvalidToken,
                          self.r.set_access_credentials, set(
                              ('identity', )), 'dummy_access_token')

    def test_oauth_scope_required(self):
        self.r.set_oauth_app_info('dummy_client', 'dummy_secret', 'dummy_url')
        self.r.set_access_credentials(set('dummy_scope', ), 'dummy_token')
        self.assertRaises(errors.OAuthScopeRequired, self.r.get_me)

    def test_raise_client_exception(self):
        def raise_client_exception(*args):
            raise errors.ClientException(*args)

        self.assertRaises(errors.ClientException, raise_client_exception)
        self.assertRaises(errors.ClientException, raise_client_exception,
                          'test')

        ce_message = errors.ClientException('Test')
        ce_no_message = errors.ClientException()
        self.assertEqual(ce_message.message, str(ce_message))
        self.assertEqual(ce_no_message.message, str(ce_no_message))

    def test_raise_http_exception(self):
        def raise_http_exception():
            raise errors.HTTPException('fakeraw')

        self.assertRaises(errors.HTTPException, raise_http_exception)
        http_exception = errors.HTTPException('fakeraw')
        self.assertEqual(http_exception.message, str(http_exception))

    def test_raise_oauth_exception(self):
        oerrormessage = "fakemessage"
        oerrorurl = "http://oauth.reddit.com/"

        def raise_oauth_exception():
            raise errors.OAuthException(oerrormessage, oerrorurl)

        self.assertRaises(errors.OAuthException, raise_oauth_exception)
        oauth_exception = errors.OAuthException(oerrormessage, oerrorurl)
        self.assertEqual(
            oauth_exception.message +
            " on url {0}".format(oauth_exception.url), str(oauth_exception))

    def test_raise_redirect_exception(self):
        apiurl = "http://api.reddit.com/"
        oauthurl = "http://oauth.reddit.com/"

        def raise_redirect_exception():
            raise errors.RedirectException(apiurl, oauthurl)

        self.assertRaises(errors.RedirectException, raise_redirect_exception)
        redirect_exception = errors.RedirectException(apiurl, oauthurl)
        self.assertEqual(redirect_exception.message, str(redirect_exception))

    @betamax()
    def test_scope_history(self):
        self.r.refresh_access_information(self.refresh_token['history'])
        self.assertTrue(list(self.r.get_redditor(self.un).get_upvoted()))

    @betamax()
    def test_scope_identity(self):
        self.r.refresh_access_information(self.refresh_token['identity'])
        self.assertEqual(self.un, self.r.get_me().name)

    @betamax()
    def test_scope_mysubreddits(self):
        self.r.refresh_access_information(self.refresh_token['mysubreddits'])
        self.assertTrue(list(self.r.get_my_moderation()))

    @betamax()
    def test_scope_creddits(self):
        # Assume there are insufficient creddits.
        self.r.refresh_access_information(self.refresh_token['creddits'])
        redditor = self.r.get_redditor('bboe')
        sub = self.r.get_submission(url=self.comment_url)

        # Test error conditions
        self.assertRaises(TypeError, sub.gild, months=1)
        for value in (False, 0, -1, '0', '-1'):
            self.assertRaises(TypeError, redditor.gild, value)

        # Test object gilding
        self.assertRaises(errors.InsufficientCreddits, redditor.gild)
        self.assertRaises(errors.InsufficientCreddits, sub.gild)
        self.assertRaises(errors.InsufficientCreddits, sub.comments[0].gild)

    @betamax()
    def test_scope_privatemessages(self):
        self.r.refresh_access_information(
            self.refresh_token['privatemessages'])
        self.assertTrue(list(self.r.get_inbox()))

    @betamax()
    def test_scope_read(self):
        self.r.refresh_access_information(self.refresh_token['read'])
        self.assertTrue(self.r.get_subreddit(self.priv_sr).subscribers > 0)
        fullname = '{0}_{1}'.format(self.r.config.by_object[Submission],
                                    self.priv_submission_id)
        method1 = self.r.get_info(thing_id=fullname)
        method2 = self.r.get_submission(submission_id=self.priv_submission_id)
        self.assertEqual(method1, method2)

    @betamax()
    def test_scope_read_get_front_page(self):
        self.r.refresh_access_information(self.refresh_token['mysubreddits'])
        subscribed = list(self.r.get_my_subreddits(limit=None))
        self.r.refresh_access_information(self.refresh_token['read'])
        for post in self.r.get_front_page():
            self.assertTrue(post.subreddit in subscribed)

    @betamax()
    def test_set_access_credentials(self):
        self.assertTrue(self.r.user is None)
        result = self.r.refresh_access_information(
            self.refresh_token['identity'], update_session=False)
        self.assertTrue(self.r.user is None)
        self.r.set_access_credentials(**result)
        self.assertFalse(self.r.user is None)

    @betamax()
    def test_solve_captcha(self):
        # Use the alternate account because it has low karma,
        # so we can test the captcha.
        self.r.refresh_access_information(self.other_refresh_token['submit'])
        original_stdin = sys.stdin
        sys.stdin = FakeStdin('ljgtoo')  # Comment this line when rebuilding
        self.r.submit(self.sr, 'captcha test', 'body')
        sys.stdin = original_stdin

    @betamax()
    def test_oauth_without_identy_doesnt_set_user(self):
        self.assertTrue(self.r.user is None)
        self.r.refresh_access_information(self.refresh_token['edit'])
        self.assertTrue(self.r.user is None)
Example #8
0
class OAuth2RedditTest(PRAWTest):
    def setUp(self):
        self.configure()
        site_name = (os.getenv('REDDIT_SITE') or 'reddit') + '_oauth_test'
        self.r = Reddit(USER_AGENT,
                        site_name=site_name,
                        disable_update_check=True)

    def test_authorize_url(self):
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired, self.r.get_authorize_url,
                          'dummy_state')
        self.r.set_oauth_app_info(self.r.config.client_id,
                                  self.r.config.client_secret,
                                  self.r.config.redirect_uri)
        url, params = self.r.get_authorize_url('...').split('?', 1)
        self.assertTrue('api/v1/authorize/' in url)
        params = dict(x.split('=', 1) for x in params.split('&'))
        expected = {
            'client_id':
            self.r.config.client_id,
            'duration':
            'temporary',
            'redirect_uri': ('https%3A%2F%2F127.0.0.1%3A65010%2F'
                             'authorize_callback'),
            'response_type':
            'code',
            'scope':
            'identity',
            'state':
            '...'
        }
        self.assertEqual(expected, params)

    @betamax
    def test_get_access_information(self):
        # If this test fails, the following URL will need to be visted in order
        # to obtain a new code to pass to `get_access_information`:
        # self.r.get_authorize_url('...')
        token = self.r.get_access_information('MQALrr1di8GzcnT8szbTWhLcBUQ')
        expected = {
            'access_token': self.r.access_token,
            'refresh_token': None,
            'scope': set(('identity', ))
        }
        self.assertEqual(expected, token)
        self.assertEqual('PyAPITestUser2', text_type(self.r.user))

    @betamax
    def test_get_access_information_with_invalid_code(self):
        self.assertRaises(errors.OAuthInvalidGrant,
                          self.r.get_access_information, 'invalid_code')

    def test_invalid_app_access_token(self):
        self.r.clear_authentication()
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired,
                          self.r.get_access_information, 'dummy_code')

    def test_invalid_app_authorize_url(self):
        self.r.clear_authentication()
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired, self.r.get_authorize_url,
                          'dummy_state')

    @betamax
    def test_invalid_set_access_credentials(self):
        self.assertRaises(errors.OAuthInvalidToken,
                          self.r.set_access_credentials, set(
                              ('identity', )), 'dummy_access_token')

    def test_oauth_scope_required(self):
        self.r.set_oauth_app_info('dummy_client', 'dummy_secret', 'dummy_url')
        self.r.set_access_credentials(set('dummy_scope', ), 'dummy_token')
        self.assertRaises(errors.OAuthScopeRequired, self.r.get_me)

    @betamax
    def test_scope_edit(self):
        self.r.refresh_access_information(self.refresh_token['edit'])
        submission = Submission.from_id(self.r, self.submission_edit_id)
        self.assertEqual(submission, submission.edit('Edited text'))

    @betamax
    def test_scope_history(self):
        self.r.refresh_access_information(self.refresh_token['history'])
        self.assertTrue(list(self.r.get_redditor(self.un).get_liked()))

    @betamax
    def test_scope_identity(self):
        self.r.refresh_access_information(self.refresh_token['identity'])
        self.assertEqual(self.un, self.r.get_me().name)

    @betamax
    def test_scope_modconfig(self):
        self.r.refresh_access_information(self.refresh_token['modconfig'])
        self.r.get_subreddit(self.sr).set_settings('foobar')
        retval = self.r.get_subreddit(self.sr).get_stylesheet()
        self.assertTrue('images' in retval)

    @betamax
    def test_scope_modflair(self):
        self.r.refresh_access_information(self.refresh_token['modflair'])
        self.r.get_subreddit(self.sr).set_flair(self.un, 'foobar')

    @betamax
    def test_scope_modlog(self):
        num = 50
        self.r.refresh_access_information(self.refresh_token['modlog'])
        result = self.r.get_subreddit(self.sr).get_mod_log(limit=num)
        self.assertEqual(num, len(list(result)))

    @betamax
    def test_scope_modposts(self):
        self.r.refresh_access_information(self.refresh_token['modposts'])
        Submission.from_id(self.r, self.submission_edit_id).remove()

    @betamax
    def test_scope_mysubreddits(self):
        self.r.refresh_access_information(self.refresh_token['mysubreddits'])
        self.assertTrue(list(self.r.get_my_moderation()))

    @betamax
    def test_scope_creddits(self):
        # Assume there are insufficient creddits.
        self.r.refresh_access_information(self.refresh_token['creddits'])
        redditor = self.r.get_redditor('bboe')
        sub = self.r.get_submission(url=self.comment_url)

        # Test error conditions
        self.assertRaises(TypeError, sub.gild, months=1)
        for value in (False, 0, -1, '0', '-1'):
            self.assertRaises(TypeError, redditor.gild, value)

        # Test object gilding
        self.assertRaises(errors.InsufficientCreddits, redditor.gild)
        self.assertRaises(errors.InsufficientCreddits, sub.gild)
        self.assertRaises(errors.InsufficientCreddits, sub.comments[0].gild)

    @betamax
    def test_scope_privatemessages(self):
        self.r.refresh_access_information(
            self.refresh_token['privatemessages'])
        self.assertTrue(list(self.r.get_inbox()))

    @betamax
    def test_scope_read(self):
        self.r.refresh_access_information(self.refresh_token['read'])
        self.assertTrue(self.r.get_subreddit(self.priv_sr).subscribers > 0)
        fullname = '{0}_{1}'.format(self.r.config.by_object[Submission],
                                    self.priv_submission_id)
        method1 = self.r.get_info(thing_id=fullname)
        method2 = self.r.get_submission(submission_id=self.priv_submission_id)
        self.assertEqual(method1, method2)

    @betamax
    def test_scope_read_get_front_page(self):
        self.r.refresh_access_information(self.refresh_token['mysubreddits'])
        subscribed = list(self.r.get_my_subreddits(limit=None))
        self.r.refresh_access_information(self.refresh_token['read'])
        for post in self.r.get_front_page():
            self.assertTrue(post.subreddit in subscribed)

    @betamax
    def test_scope_read_get_sub_listingr(self):
        self.r.refresh_access_information(self.refresh_token['read'])
        subreddit = self.r.get_subreddit(self.priv_sr)
        self.assertTrue(list(subreddit.get_top()))

    @betamax
    def test_scope_read_get_submission_by_url(self):
        url = ("https://www.reddit.com/r/reddit_api_test_priv/comments/16kbb7/"
               "google/")
        self.r.refresh_access_information(self.refresh_token['read'])
        submission = Submission.from_url(self.r, url)
        self.assertTrue(submission.num_comments != 0)

    @betamax
    def test_scope_read_priv_sr_comments(self):
        self.r.refresh_access_information(self.refresh_token['read'])
        self.assertTrue(list(self.r.get_comments(self.priv_sr)))

    @betamax
    def test_scope_read_priv_sub_comments(self):
        self.r.refresh_access_information(self.refresh_token['read'])
        submission = Submission.from_id(self.r, self.priv_submission_id)
        self.assertTrue(submission.comments)

    @betamax
    def test_scope_submit(self):
        self.r.refresh_access_information(self.refresh_token['submit'])
        result = self.r.submit(self.sr, 'OAuth Submit', text='Foo')
        self.assertTrue(isinstance(result, Submission))

    @betamax
    def test_scope_subscribe(self):
        self.r.refresh_access_information(self.refresh_token['subscribe'])
        self.r.get_subreddit(self.sr).subscribe()

    @betamax
    def test_scope_vote(self):
        self.r.refresh_access_information(self.refresh_token['vote'])
        submission = Submission.from_id(self.r, self.submission_edit_id)
        submission.clear_vote()

    @betamax
    def test_set_access_credentials(self):
        self.assertTrue(self.r.user is None)
        result = self.r.refresh_access_information(
            self.refresh_token['identity'], update_session=False)
        self.assertTrue(self.r.user is None)
        self.r.set_access_credentials(**result)
        self.assertFalse(self.r.user is None)

    @betamax
    def test_oauth_without_identy_doesnt_set_user(self):
        self.assertTrue(self.r.user is None)
        self.r.refresh_access_information(self.refresh_token['edit'])
        self.assertTrue(self.r.user is None)
Example #9
0
class StatisticsFeeder:
    """
    :type db: Database
    :type session: Reddit
    """
    def __init__(self, database, handler, path='../html/'):
        self.db = database
        self.path = path
        self.session = Reddit(user_agent='Statistics poller for RedditRover', handler=handler)
        self.config = ConfigParser()
        self.config.read(resource_filename('config', 'bot_config.ini'))
        self.authors = self.get_authors()
        self.status_online()
        atexit.register(self.status_offline)

    def _set_status(self, state, message):
        template_info = '''<span class="label label-{type}">Status: {title}</span>'''
        if state == 'online':
            info = template_info.format(type='success', title='Online', content=message)
        elif state == 'offline':
            info = template_info.format(type='danger', title='Offline', content=message)
        elif state == 'warning':
            info = template_info.format(type='warn', title='Warning', content=message)
        else:
            info = ''
        self._write_meta(info=info)

    def _write_meta(self, info):
        meta_stats = self.db.select_day_from_meta(time())
        if meta_stats:
            date, subm, comments, cycles = meta_stats
            reacted = self.db.get_total_responses_per_day(time())[0]
            rate = reacted * 100 / (comments + subm)
        else:
            subm, comments, cycles, rate = 0, 0, 0, 0
        with open(self.path + '_data/_meta.json', 'w') as f:
            f.write(json.dumps(
                {'status': info, 'submissions': subm, 'comments': comments, 'cycles': cycles,
                 'rate': '{:.5f}'.format(rate)}
            ))

    def status_online(self):
        self._set_status('online', 'The bot is currently running, last update was {}'.format(time()))

    def status_offline(self):
        self._set_status('offline', 'The bot is currently offline.')

    def status_warning(self, traceback=None):
        if traceback:
            self._set_status('warning', 'Here is the latest traceback: <br /><pre>{}</pre>'.format(traceback))
        else:
            self._set_status('warning', 'Check the console, there is maybe an error. (no traceback given)')

    def get_authors(self):
        carelist = []
        for section in self.config.sections():
            for option in self.config.options(section):
                if option == 'username':
                    carelist.append(self.config.get(section, option).lower())
        return carelist

    def get_old_comment_karma(self):
        threads = self.db.get_karma_loads()
        for thread in threads:  # tuple of tuple
            thing_id = thread[0]
            thing = self.session.get_info(thing_id=thing_id)
            author_votes = thing.score
            if type(thing) is Comment:
                replies = thing.replies
            elif type(thing) is Submission:
                thing.replace_more_comments(limit=None, threshold=1)
                replies = thing.comments
            elif type(thing) is MoreComments:
                replies = thing.comments(update=True)
            for comment in replies:
                if comment.author and comment.author.name.lower() in self.authors:
                    self.db.update_karma_count(thing_id, author_votes, comment.score)
                    break
            else:
                self.db.update_karma_count_with_null(thing_id, author_votes)

    def _write_filler_karma(self):
        from random import randint
        threads = self.db.get_karma_loads()
        for thread in threads:
            thread_id = thread[0]
            self.db.update_karma_count(thread_id, randint(-50, 350), randint(-50, 350))

    def render_overview(self):
        self.status_online()
        self._table_rows()
        self._plugin_activity()
        self._subreddit_activity()
        self._post_histogram()

    def _table_rows(self):
        dataset = self.db.get_all_stats()
        carelist = []
        title = '<a href="{url}" target="_blank" class="text-primary"> {text} </a>'
        subreddit = '<a href="http://reddit.com/r/{sub}" target="_blank" class="text-warning"> {sub} </a>'
        author = '<a href="http://reddit.com/u/{usr}" target="_blank"> {usr} </a>'
        for line in dataset:
            if line[8] and line[7]:
                result = line[8] - line[7]
                line_7 = line[7]
                line_8 = line[8]  # @TODO: Better variable assignment
            else:
                line_7 = '-'
                line_8 = '-'
                result = '-'
            carelist.append({'id': line[0], 'plugin': line[1], 'time': line[2],
                             'title': title.format(url=line[6], text=line[3]), 'username': author.format(usr=line[4]),
                             'subreddit': subreddit.format(sub=line[5]), 'permalink': line[6],
                             'upvotes_author': line_7, 'upvotes_plugin': line_8, 'upvotes_difference': result})

        with open(self.path + '_data/overview_rows.json', 'w') as f:
            f.write(json.dumps(carelist))

    def _plugin_activity(self):
        dataset = self.db.get_all_stats()
        chart_data = {}
        for line in dataset:
            if line[1] in chart_data:
                chart_data[line[1]] += 1
            else:
                chart_data[line[1]] = 1
        carelist = []
        for k, v in chart_data.items():
            carelist.append({'name': k, 'data': v})
        with open(self.path + '_data/post_list.json', 'w') as f:
            f.write(json.dumps(carelist))

    def _subreddit_activity(self):
        def tighten_filter(list, min_submissions):
            return [dict for dict in list if dict['data'] > min_submissions]
        dataset = self.db.get_all_stats()
        carelist = []
        subreddit_data = {}
        for line in dataset:
            if line[5] in subreddit_data:
                subreddit_data[line[5]] += 1
            else:
                subreddit_data[line[5]] = 1
        for k, v in subreddit_data.items():
            carelist.append({'name': k, 'data': v})
        carelist = sorted(carelist, key=lambda x: x['data'])
        i = 0
        while(len(carelist) > 16):
            carelist = tighten_filter(carelist, i)
            i += 1
        with open(self.path + '_data/subreddit_data.json', 'w') as f:
            f.write(json.dumps(carelist))

    def _post_histogram(self):
        dataset = self.db.get_all_stats()
        carelist = []
        date_change_dataset = [[line[1], datetime.datetime.strptime(line[2], "%Y-%m-%d %H:%M:%S")] for line in dataset]
        post_history = {}
        # Insert all data in hourly ticks
        for line in date_change_dataset:
            # Yay, <= py3.2 doesn't have datetime.timestamp()
            timestamp = int((line[1] - datetime.datetime.utcfromtimestamp(0)).total_seconds()) // 3600
            if line[0] in post_history:
                if timestamp in post_history[line[0]]:
                    post_history[line[0]][timestamp] += 1
                else:
                    post_history[line[0]][timestamp] = 1
            else:
                post_history[line[0]] = {timestamp: 1}
        # Sort values and insert nil-values so the graphs are accurate per tick
        for key, value in post_history.items():
            all_values = sorted(value.items())
            start, end = all_values[0][0], all_values[-1][0]
            for x in range(start, end + 1):
                if x not in value:
                    value[x] = 0
        # transform the data again to get simple json for js - also transform timestamp to js readable
        for k, v in post_history.items():
            some_list = []
            for key, value in sorted(v.items()):
                some_list.append([key * 3600 * 1000, value])
            carelist.append({'name': k, 'data': some_list})
        # write out
        with open(self.path + '_data/post_history.json', 'w') as f:
            f.write(json.dumps(carelist))

    def render_karma(self):
        self._total_karma()
        self._average_karma()

    def _total_karma(self):
        dataset = self.db.get_all_stats()
        caredict = {}
        carelist = []
        for line in dataset:
            if not line[8]:
                karma = 0
            else:
                karma = line[8]
            if line[1] in caredict:
                caredict[line[1]] += karma
            else:
                caredict[line[1]] = karma
        for key, value in caredict.items():
            carelist.append({'name': key, 'data': value})
        with open(self.path + '_data/total_karma.json', 'w+') as f:
            f.write(json.dumps(carelist))

    def _average_karma(self):
        dataset = self.db.get_all_stats()
        caredict = {}
        carelist = []
        for line in dataset:
            if not line[8]:
                karma = 0
            else:
                karma = line[8]
            if line[1] in caredict:
                caredict[line[1]] = [caredict[line[1]][0] + karma, caredict[line[1]][1] + 1]
            else:
                caredict[line[1]] = [karma, 1]
        for key, value in caredict.items():
            carelist.append({'name': key, 'data': value[0] / value[1]})
        with open(self.path + '_data/average_karma.json', 'w+') as f:
            f.write(json.dumps(carelist))

    def render_messages(self):
        self._message_rows()

    def _message_rows(self):
        carelist = []
        messages = self.db.get_all_messages()
        message_template = 'You\'ve mailed my bot here: http://reddit.com/message/messages/{msg_id}%0A%0A---%0A%0A'
        url_template = 'http://reddit.com/message/compose/?to={author}&subject={subject}&message={msg_template}'
        reply_template = '<a href="{answer_url}" target="_blank"> {body} </a>'
        for line in messages:
            msg = message_template.format(msg_id=line[0])
            url = url_template.format(author=line[4], subject=line[3], msg_template=msg)
            reply = reply_template.format(answer_url=url, body=line[5])
            carelist.append({'id': line[0], 'plugin': line[1], 'time': line[2], 'title': line[3],
                             'username': line[4], 'body': reply})
        with open(self.path + '_data/message_rows.json', 'w') as f:
            f.write(json.dumps(carelist))
Example #10
0
class OAuth2RedditTest(PRAWTest):
    def setUp(self):
        self.configure()
        self.r = Reddit(USER_AGENT, site_name="reddit_oauth_test", disable_update_check=True)

    def test_authorize_url(self):
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired, self.r.get_authorize_url, "dummy_state")
        self.r.set_oauth_app_info(self.r.config.client_id, self.r.config.client_secret, self.r.config.redirect_uri)
        url, params = self.r.get_authorize_url("...").split("?", 1)
        self.assertTrue("api/v1/authorize/" in url)
        params = dict(x.split("=", 1) for x in params.split("&"))
        expected = {
            "client_id": self.r.config.client_id,
            "duration": "temporary",
            "redirect_uri": ("https%3A%2F%2F127.0.0.1%3A65010%2F" "authorize_callback"),
            "response_type": "code",
            "scope": "identity",
            "state": "...",
        }
        self.assertEqual(expected, params)

    # @betamax() is currently broken for this test
    def test_auto_refresh_token(self):
        self.r.refresh_access_information(self.refresh_token["identity"])
        old_token = self.r.access_token

        self.r.access_token += "x"  # break the token
        self.r.user.refresh()
        current_token = self.r.access_token
        self.assertNotEqual(old_token, current_token)

        self.r.user.refresh()
        self.assertEqual(current_token, self.r.access_token)

    @betamax()
    def test_get_access_information(self):
        # If this test fails, the following URL will need to be visted in order
        # to obtain a new code to pass to `get_access_information`:
        # self.r.get_authorize_url('...')
        token = self.r.get_access_information("MQALrr1di8GzcnT8szbTWhLcBUQ")
        expected = {"access_token": self.r.access_token, "refresh_token": None, "scope": set(("identity",))}
        self.assertEqual(expected, token)
        self.assertEqual("PyAPITestUser2", text_type(self.r.user))

    @betamax()
    def test_get_access_information_with_invalid_code(self):
        self.assertRaises(errors.OAuthInvalidGrant, self.r.get_access_information, "invalid_code")

    def test_invalid_app_access_token(self):
        self.r.clear_authentication()
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired, self.r.get_access_information, "dummy_code")

    def test_invalid_app_authorize_url(self):
        self.r.clear_authentication()
        self.r.set_oauth_app_info(None, None, None)
        self.assertRaises(errors.OAuthAppRequired, self.r.get_authorize_url, "dummy_state")

    @betamax()
    def test_invalid_set_access_credentials(self):
        self.assertRaises(
            errors.OAuthInvalidToken, self.r.set_access_credentials, set(("identity",)), "dummy_access_token"
        )

    def test_oauth_scope_required(self):
        self.r.set_oauth_app_info("dummy_client", "dummy_secret", "dummy_url")
        self.r.set_access_credentials(set("dummy_scope"), "dummy_token")
        self.assertRaises(errors.OAuthScopeRequired, self.r.get_me)

    @betamax()
    def test_scope_edit(self):
        self.r.refresh_access_information(self.refresh_token["edit"])
        submission = Submission.from_id(self.r, self.submission_edit_id)
        self.assertEqual(submission, submission.edit("Edited text"))

    @betamax()
    def test_scope_history(self):
        self.r.refresh_access_information(self.refresh_token["history"])
        self.assertTrue(list(self.r.get_redditor(self.un).get_upvoted()))

    @betamax()
    def test_scope_identity(self):
        self.r.refresh_access_information(self.refresh_token["identity"])
        self.assertEqual(self.un, self.r.get_me().name)

    @betamax()
    def test_scope_modconfig(self):
        self.r.refresh_access_information(self.refresh_token["modconfig"])
        self.r.get_subreddit(self.sr).set_settings("foobar")
        retval = self.r.get_subreddit(self.sr).get_stylesheet()
        self.assertTrue("images" in retval)

    @betamax()
    def test_scope_modflair(self):
        self.r.refresh_access_information(self.refresh_token["modflair"])
        self.r.get_subreddit(self.sr).set_flair(self.un, "foobar")

    @betamax()
    def test_scope_modlog(self):
        num = 50
        self.r.refresh_access_information(self.refresh_token["modlog"])
        result = self.r.get_subreddit(self.sr).get_mod_log(limit=num)
        self.assertEqual(num, len(list(result)))

    @betamax()
    def test_scope_modothers_modself(self):
        subreddit = self.r.get_subreddit(self.sr)
        self.r.refresh_access_information(self.refresh_token["modothers"])
        subreddit.add_moderator(self.other_user_name)

        # log in as other user
        self.r.refresh_access_information(self.other_refresh_token["modself"])
        self.r.accept_moderator_invite(self.sr)

        # now return to original user.
        self.r.refresh_access_information(self.refresh_token["modothers"])
        subreddit.remove_moderator(self.other_user_name)

    @betamax()
    def test_scope_modposts(self):
        self.r.refresh_access_information(self.refresh_token["modposts"])
        Submission.from_id(self.r, self.submission_edit_id).remove()

    @betamax()
    def test_scope_modself(self):
        subreddit = self.r.get_subreddit(self.sr)
        self.r.refresh_access_information(self.refresh_token["modothers"])
        subreddit.add_moderator(self.other_user_name)
        self.r.refresh_access_information(self.refresh_token["modcontributors"])
        subreddit.add_contributor(self.other_user_name)

        # log in as other user
        self.r.refresh_access_information(self.other_refresh_token["modself"])
        self.r.accept_moderator_invite(self.sr)

        self.r.leave_moderator(subreddit)
        subreddit.leave_contributor()

        subreddit.refresh()
        self.assertFalse(subreddit.user_is_moderator)
        self.assertFalse(subreddit.user_is_contributor)

    @betamax()
    def test_scope_mysubreddits(self):
        self.r.refresh_access_information(self.refresh_token["mysubreddits"])
        self.assertTrue(list(self.r.get_my_moderation()))

    @betamax()
    def test_scope_modwiki(self):
        self.r.refresh_access_information(self.refresh_token["modwiki"])
        subreddit = self.r.get_subreddit(self.sr)
        page = subreddit.get_wiki_page("index")
        page.add_editor(self.other_user_name)
        page.remove_editor(self.other_user_name)

    @betamax()
    def test_scope_modwiki_modcontributors(self):
        self.r.refresh_access_information(self.refresh_token["modwiki+contr"])
        subreddit = self.r.get_subreddit(self.sr)

        subreddit.add_wiki_ban(self.other_user_name)
        subreddit.remove_wiki_ban(self.other_user_name)

        subreddit.add_wiki_contributor(self.other_user_name)
        subreddit.remove_wiki_contributor(self.other_user_name)

    @betamax()
    def test_scope_creddits(self):
        # Assume there are insufficient creddits.
        self.r.refresh_access_information(self.refresh_token["creddits"])
        redditor = self.r.get_redditor("bboe")
        sub = self.r.get_submission(url=self.comment_url)

        # Test error conditions
        self.assertRaises(TypeError, sub.gild, months=1)
        for value in (False, 0, -1, "0", "-1"):
            self.assertRaises(TypeError, redditor.gild, value)

        # Test object gilding
        self.assertRaises(errors.InsufficientCreddits, redditor.gild)
        self.assertRaises(errors.InsufficientCreddits, sub.gild)
        self.assertRaises(errors.InsufficientCreddits, sub.comments[0].gild)

    @betamax()
    def test_scope_privatemessages(self):
        self.r.refresh_access_information(self.refresh_token["privatemessages"])
        self.assertTrue(list(self.r.get_inbox()))

    @betamax()
    def test_scope_read(self):
        self.r.refresh_access_information(self.refresh_token["read"])
        self.assertTrue(self.r.get_subreddit(self.priv_sr).subscribers > 0)
        fullname = "{0}_{1}".format(self.r.config.by_object[Submission], self.priv_submission_id)
        method1 = self.r.get_info(thing_id=fullname)
        method2 = self.r.get_submission(submission_id=self.priv_submission_id)
        self.assertEqual(method1, method2)

    @betamax()
    def test_scope_read_get_front_page(self):
        self.r.refresh_access_information(self.refresh_token["mysubreddits"])
        subscribed = list(self.r.get_my_subreddits(limit=None))
        self.r.refresh_access_information(self.refresh_token["read"])
        for post in self.r.get_front_page():
            self.assertTrue(post.subreddit in subscribed)

    @betamax()
    def test_scope_read_get_sub_listingr(self):
        self.r.refresh_access_information(self.refresh_token["read"])
        subreddit = self.r.get_subreddit(self.priv_sr)
        self.assertTrue(list(subreddit.get_top()))

    @betamax()
    def test_scope_read_get_submission_by_url(self):
        url = "https://www.reddit.com/r/reddit_api_test_priv/comments/16kbb7/" "google/"
        self.r.refresh_access_information(self.refresh_token["read"])
        submission = Submission.from_url(self.r, url)
        self.assertTrue(submission.num_comments != 0)

    @betamax()
    def test_scope_read_priv_sr_comments(self):
        self.r.refresh_access_information(self.refresh_token["read"])
        self.assertTrue(list(self.r.get_comments(self.priv_sr)))

    @betamax()
    def test_scope_wikiread_wiki_page(self):
        self.r.refresh_access_information(self.refresh_token["wikiread"])
        self.assertTrue(self.r.get_wiki_page(self.sr, "index"))

    @betamax()
    def test_scope_read_priv_sub_comments(self):
        self.r.refresh_access_information(self.refresh_token["read"])
        submission = Submission.from_id(self.r, self.priv_submission_id)
        self.assertTrue(submission.comments)

    @betamax()
    def test_scope_submit(self):
        self.r.refresh_access_information(self.refresh_token["submit"])
        result = self.r.submit(self.sr, "OAuth Submit", text="Foo")
        self.assertTrue(isinstance(result, Submission))

    @betamax()
    def test_scope_subscribe(self):
        self.r.refresh_access_information(self.refresh_token["subscribe"])
        self.r.get_subreddit(self.sr).subscribe()

    @betamax()
    def test_scope_vote(self):
        self.r.refresh_access_information(self.refresh_token["vote"])
        submission = Submission.from_id(self.r, self.submission_edit_id)
        submission.clear_vote()

    @betamax()
    def test_set_access_credentials(self):
        self.assertTrue(self.r.user is None)
        result = self.r.refresh_access_information(self.refresh_token["identity"], update_session=False)
        self.assertTrue(self.r.user is None)
        self.r.set_access_credentials(**result)
        self.assertFalse(self.r.user is None)

    @betamax()
    def test_oauth_without_identy_doesnt_set_user(self):
        self.assertTrue(self.r.user is None)
        self.r.refresh_access_information(self.refresh_token["edit"])
        self.assertTrue(self.r.user is None)
Example #11
0
class StatisticsFeeder:
    """
    :type db: Database
    :type session: Reddit
    """
    def __init__(self, database, handler, path='../html/'):
        self.db = database
        self.path = path
        self.session = Reddit(user_agent='Statistics poller for RedditRover', handler=handler)
        self.config = ConfigParser()
        self.config.read(resource_filename('config', 'bot_config.ini'))
        self.authors = self.get_authors()
        self.status_online()
        atexit.register(self.status_offline)

    def _set_status(self, state, message):
        template_info = '''<span class="label label-{type}">Status: {title}</span>'''
        if state == 'online':
            info = template_info.format(type='success', title='Online', content=message)
        elif state == 'offline':
            info = template_info.format(type='danger', title='Offline', content=message)
        elif state == 'warning':
            info = template_info.format(type='warn', title='Warning', content=message)
        else:
            info = ''
        self._write_meta(info=info)

    def _write_meta(self, info):
        meta_stats = self.db.select_day_from_meta(time())
        if meta_stats:
            date, subm, comments, cycles = meta_stats
            reacted = self.db.get_total_responses_per_day(time())[0]
            rate = reacted * 100 / (comments + subm)
        else:
            subm, comments, cycles, rate = 0, 0, 0, 0
        with open(self.path + '_data/_meta.json', 'w') as f:
            f.write(json.dumps(
                {'status': info, 'submissions': subm, 'comments': comments, 'cycles': cycles,
                 'rate': '{:.5f}'.format(rate)}
            ))

    def status_online(self):
        self._set_status('online', 'The bot is currently running, last update was {}'.format(time()))

    def status_offline(self):
        self._set_status('offline', 'The bot is currently offline.')

    def status_warning(self, traceback=None):
        if traceback:
            self._set_status('warning', 'Here is the latest traceback: <br /><pre>{}</pre>'.format(traceback))
        else:
            self._set_status('warning', 'Check the console, there is maybe an error. (no traceback given)')

    def get_authors(self):
        carelist = []
        for section in self.config.sections():
            for option in self.config.options(section):
                if option == 'username':
                    carelist.append(self.config.get(section, option).lower())
        return carelist

    def get_old_comment_karma(self):
        threads = self.db.get_karma_loads()
        for thread in threads:  # tuple of tuple
            thing_id = thread[0]
            thing = self.session.get_info(thing_id=thing_id)
            author_votes = thing.score
            if type(thing) is Comment:
                replies = thing.replies
            elif type(thing) is Submission:
                thing.replace_more_comments(limit=None, threshold=1)
                replies = thing.comments
            elif type(thing) is MoreComments:
                replies = thing.comments(update=True)
            for comment in replies:
                if comment.author and comment.author.name.lower() in self.authors:
                    self.db.update_karma_count(thing_id, author_votes, comment.score)
                    break
            else:
                self.db.update_karma_count_with_null(thing_id, author_votes)

    def _write_filler_karma(self):
        from random import randint
        threads = self.db.get_karma_loads()
        for thread in threads:
            thread_id = thread[0]
            self.db.update_karma_count(thread_id, randint(-50, 350), randint(-50, 350))

    def render_overview(self):
        self.status_online()
        self._table_rows()
        self._plugin_activity()
        self._subreddit_activity()
        self._post_histogram()

    def _table_rows(self):
        dataset = self.db.get_all_stats()
        carelist = []
        title = '<a href="{url}" target="_blank" class="text-primary"> {text} </a>'
        subreddit = '<a href="http://reddit.com/r/{sub}" target="_blank" class="text-warning"> {sub} </a>'
        author = '<a href="http://reddit.com/u/{usr}" target="_blank"> {usr} </a>'
        for line in dataset:
            if line[8] and line[7]:
                result = line[8] - line[7]
                line_7 = line[7]
                line_8 = line[8]  # @TODO: Better variable assignment
            else:
                line_7 = '-'
                line_8 = '-'
                result = '-'
            carelist.append({'id': line[0], 'plugin': line[1], 'time': line[2],
                             'title': title.format(url=line[6], text=line[3]), 'username': author.format(usr=line[4]),
                             'subreddit': subreddit.format(sub=line[5]), 'permalink': line[6],
                             'upvotes_author': line_7, 'upvotes_plugin': line_8, 'upvotes_difference': result})

        with open(self.path + '_data/overview_rows.json', 'w') as f:
            f.write(json.dumps(carelist))

    def _plugin_activity(self):
        dataset = self.db.get_all_stats()
        chart_data = {}
        for line in dataset:
            if line[1] in chart_data:
                chart_data[line[1]] += 1
            else:
                chart_data[line[1]] = 1
        carelist = []
        for k, v in chart_data.items():
            carelist.append({'name': k, 'data': v})
        with open(self.path + '_data/post_list.json', 'w') as f:
            f.write(json.dumps(carelist))

    def _subreddit_activity(self):
        def tighten_filter(list, min_submissions):
            return [dict for dict in list if dict['data'] > min_submissions]
        dataset = self.db.get_all_stats()
        carelist = []
        subreddit_data = {}
        for line in dataset:
            if line[5] in subreddit_data:
                subreddit_data[line[5]] += 1
            else:
                subreddit_data[line[5]] = 1
        for k, v in subreddit_data.items():
            carelist.append({'name': k, 'data': v})
        carelist = sorted(carelist, key=lambda x: x['data'])
        i = 0
        while(len(carelist) > 16):
            carelist = tighten_filter(carelist, i)
            i += 1
        with open(self.path + '_data/subreddit_data.json', 'w') as f:
            f.write(json.dumps(carelist))

    def _post_histogram(self):
        dataset = self.db.get_all_stats()
        carelist = []
        date_change_dataset = [[line[1], datetime.datetime.strptime(line[2], "%Y-%m-%d %H:%M:%S")] for line in dataset]
        post_history = {}
        # Insert all data in hourly ticks
        for line in date_change_dataset:
            # Yay, <= py3.2 doesn't have datetime.timestamp()
            timestamp = int((line[1] - datetime.datetime.utcfromtimestamp(0)).total_seconds()) // 3600
            if line[0] in post_history:
                if timestamp in post_history[line[0]]:
                    post_history[line[0]][timestamp] += 1
                else:
                    post_history[line[0]][timestamp] = 1
            else:
                post_history[line[0]] = {timestamp: 1}
        # Sort values and insert nil-values so the graphs are accurate per tick
        for key, value in post_history.items():
            all_values = sorted(value.items())
            start, end = all_values[0][0], all_values[-1][0]
            for x in range(start, end + 1):
                if x not in value:
                    value[x] = 0
        # transform the data again to get simple json for js - also transform timestamp to js readable
        for k, v in post_history.items():
            some_list = []
            for key, value in sorted(v.items()):
                some_list.append([key * 3600 * 1000, value])
            carelist.append({'name': k, 'data': some_list})
        # write out
        with open(self.path + '_data/post_history.json', 'w') as f:
            f.write(json.dumps(carelist))

    def render_karma(self):
        self._total_karma()
        self._average_karma()

    def _total_karma(self):
        dataset = self.db.get_all_stats()
        caredict = {}
        carelist = []
        for line in dataset:
            if not line[8]:
                karma = 0
            else:
                karma = line[8]
            if line[1] in caredict:
                caredict[line[1]] += karma
            else:
                caredict[line[1]] = karma
        for key, value in caredict.items():
            carelist.append({'name': key, 'data': value})
        with open(self.path + '_data/total_karma.json', 'w+') as f:
            f.write(json.dumps(carelist))

    def _average_karma(self):
        dataset = self.db.get_all_stats()
        caredict = {}
        carelist = []
        for line in dataset:
            if not line[8]:
                karma = 0
            else:
                karma = line[8]
            if line[1] in caredict:
                caredict[line[1]] = [caredict[line[1]][0] + karma, caredict[line[1]][1] + 1]
            else:
                caredict[line[1]] = [karma, 1]
        for key, value in caredict.items():
            carelist.append({'name': key, 'data': value[0] / value[1]})
        with open(self.path + '_data/average_karma.json', 'w+') as f:
            f.write(json.dumps(carelist))

    def render_messages(self):
        self._message_rows()

    def _message_rows(self):
        carelist = []
        messages = self.db.get_all_messages()
        message_template = 'You\'ve mailed my bot here: http://reddit.com/message/messages/{msg_id}%0A%0A---%0A%0A'
        url_template = 'http://reddit.com/message/compose/?to={author}&subject={subject}&message={msg_template}'
        reply_template = '<a href="{answer_url}" target="_blank"> {body} </a>'
        for line in messages:
            msg = message_template.format(msg_id=line[0])
            url = url_template.format(author=line[4], subject=line[3], msg_template=msg)
            reply = reply_template.format(answer_url=url, body=line[5])
            carelist.append({'id': line[0], 'plugin': line[1], 'time': line[2], 'title': line[3],
                             'username': line[4], 'body': reply})
        with open(self.path + '_data/message_rows.json', 'w') as f:
            f.write(json.dumps(carelist))