Esempio n. 1
0
    def post(self):
        """
			New Subscription
			@param username: str
			@param subreddit: str
			#return {}
		"""
        a = parser.parse_args()
        s_username, s_subreddit = \
         a['username'], a['subreddit']
        if not s_username \
         or not s_subreddit:
            return {'message': 'all fields required'}, 400, cors

        try:
            s_user = User.objects(username=s_username).get()
        except DoesNotExist:
            return {'message': 'user does not exist'}, 400, cors

        try:
            s_subreddit = Subreddit.objects(name=s_subreddit).get()
        except DoesNotExist:
            return {'message': 'user does not exist'}, 400, cors

        try:
            Subscription.objects(Q(user=s_user)
                                 & Q(subreddit=s_subreddit)).get()
        except DoesNotExist:
            pass
        else:
            return {'message': 'already subscribed'}, 400, cors

        Subscription(user=s_user, subreddit=s_subreddit).save()

        return {}, 200, cors
Esempio n. 2
0
    def get(self):
        """
			Subreddit Details
			@param subreddit: (str)
			@returns {name, profilePic, title, description, rules}
		"""
        a = request.args
        s_name = a.get('name', None)

        if not s_name:
            return {'message': 'all fields required'}, 400, cors

        try:
            sub = Subreddit.objects(name=s_name).get()
        except DoesNotExist:
            return {'message': 'subreddit already exists'}, 400, cors

        return {
            'name': sub.name,
            'profilePic': "temp1.jpg",
            'title': sub.title,
            'description': sub.desc,
            'rules': sub.rules,
            'topic': sub.topic
        }, 200, cors
Esempio n. 3
0
    def get(self):
        """
			List of all subreddits
			@returns list({'name'})
		"""
        r = [loads(i.json()) for i in Subreddit.objects()]
        return [{'name': i['name']} for i in r], 200, cors
Esempio n. 4
0
def get_list(subreddits: list):
    """
    Returns a list of subreddit objects
    :param subreddits:
    :return: list
    """
    return [Subreddit(subreddit) for subreddit in subreddits]
Esempio n. 5
0
    def put(self):
        """
			New Subreddit
			@param name: (str)
			@param title: (str)
			@param username: creator (str)
			@param desc: (str)
			@optional @param rules: (str)
			@optional @param topic: (str)
			@returns {'name'}
		"""
        a = parser.parse_args()
        s_name, s_title, s_username, s_desc, s_rules, s_topic = \
         a['name'], a['title'], a['username'], a['desc'], a['rules'], a['topic']

        if not s_name or \
         not s_title or \
         not s_desc or \
         not s_username:
            return {'message': 'all fields required'}, 400, cors

        try:
            s_user = User.objects(username=s_username).get()
        except DoesNotExist:
            return {'message': 'user does not exist'}, 400, cors

        try:
            Subreddit.objects(name=s_name).get()
        except DoesNotExist:
            pass
        else:
            return {'message': 'subreddit already exists'}, 400, cors

        Subreddit(name=s_name,
                  title=s_title,
                  createdby=s_user,
                  desc=s_desc,
                  rules=(s_rules or ''),
                  topic=(s_topic or '')).save()

        s_user.karma += 5
        s_user.save()

        return {'name': s_name}, 200, cors
Esempio n. 6
0
    def get(self):
        a = request.args
        q = a.get('q', None)

        if not q:
            return {'message': 'all fields required'}, 400, cors

        posts = Post.objects(
            Q(title__icontains=q) | Q(body__icontains=q)
            | Q(flair__icontains=q))
        users = User.objects(Q(username__icontains=q) | Q(bio__icontains=q))
        subs = Subreddit.objects(
            Q(name__icontains=q) | Q(title__icontains=q)
            | Q(desc__icontains=q))

        return {
            'posts': list(map(lambda x: loads(x.json()), posts)),
            'users': list(map(lambda x: loads(x.json()), users)),
            'subreddits': list(map(lambda x: loads(x.json()), subs))
        }, 200, cors
Esempio n. 7
0
    def post(self):
        """
			New Post
			@param username: (str)
			@param title: (str)
			@param subreddit: (str)
			@optional @param body: (str)
			@optional @param flair: (str)
			@returns {}
		"""
        a = parser.parse_args()
        print(a)
        p_username, p_title, p_subreddit, p_flair, p_body = \
         a['username'], a['title'], a['subreddit'], a['flair'], a['body']
        if not p_username \
         or not p_title \
         or not p_subreddit:
            return {'message': 'all fields required'}, 400, cors

        try:
            p_user = User.objects(username=p_username).get()
        except DoesNotExist:
            return {'message': 'user does not exist'}, 400, cors

        try:
            p_subreddit = Subreddit.objects(name=p_subreddit).get()
        except DoesNotExist:
            return {'message': 'user does not exist'}, 400, cors

        new_post = Post(author=p_user,
                        title=p_title,
                        subreddit=p_subreddit,
                        flair=(p_flair or ''),
                        body=(p_body or '')).save()

        p_user.karma += 4
        p_user.save()

        return {'_id': str(new_post._id)}, 200, cors
Esempio n. 8
0
    def get(self):
        """
			Get all posts or a subreddit's posts
			@optional @get_param subreddit: all posts if not given, else only of that subreddit
			@optional @get_param subreddit: all posts if not given, else only of that user
			@returns list({"author", "title", "subreddit", "posteddate", "votecount", "flair"})
		"""
        a = request.args
        p_subreddit = a.get('subreddit', None)
        p_username = a.get('username', None)

        if p_subreddit:
            try:
                p_subreddit = Subreddit.objects(name=p_subreddit).get()
            except DoesNotExist:
                return {'message': 'subreddit does not exist'}, 400, cors

        if p_username:
            try:
                p_user = User.objects(username=p_username).get()
            except DoesNotExist:
                return {'message': 'user does not exist'}, 400, cors

        if p_subreddit:
            if p_username:
                posts = Post.objects(
                    Q(author=p_user) & Q(subreddit=p_subreddit))
            else:
                posts = Post.objects(subreddit=p_subreddit)
        else:
            if p_username:
                posts = Post.objects(author=p_user)
            else:
                posts = Post.objects()

        posts = posts.order_by('-posteddate')

        return [loads(i.json()) for i in posts], 200, cors
Esempio n. 9
0
def update_from_wiki(subreddit, requester):
    """Updates conditions from the subreddit's wiki."""
    global r
    username = cfg_file.get('reddit', 'username')

    try:
        page = subreddit.get_wiki_page(cfg_file.get('reddit', 'wiki_page_name'))
    except Exception:
        send_error_message(requester, subreddit.display_name,
            'The wiki page could not be accessed. Please ensure the page '
            'http://www.reddit.com/r/{0}/wiki/{1} exists and that {2} '
            'has the "wiki" mod permission to be able to access it.'
            .format(subreddit.display_name,
                    cfg_file.get('reddit', 'wiki_page_name'),
                    username))
        return False

    html_parser = HTMLParser.HTMLParser()
    page_content = html_parser.unescape(page.content_md)

    # check that all the conditions are valid yaml
    condition_defs = yaml.safe_load_all(page_content)
    condition_num = 1
    try:
        for cond_def in condition_defs:
            condition_num += 1
    except Exception as e:
        indented = ''
        for line in str(e).split('\n'):
            indented += '    {0}\n'.format(line)
        send_error_message(requester, subreddit.display_name,
            'Error when reading conditions from wiki - '
            'Syntax invalid in section #{0}:\n\n{1}'
            .format(condition_num, indented))
        return False

    # reload and actually process the conditions
    condition_defs = yaml.safe_load_all(page_content)
    condition_num = 1
    kept_sections = []
    for cond_def in condition_defs:
        # ignore any non-dict sections (can be used as comments, etc.)
        if not isinstance(cond_def, dict):
            continue

        cond_def = lowercase_keys_recursively(cond_def)

        try:
            check_condition_valid(cond_def)
        except ValueError as e:
            send_error_message(requester, subreddit.display_name,
                'Invalid condition in section #{0} - {1}'
                .format(condition_num, e))
            return False

        # create a condition for final checks
        condition = Condition(cond_def)

        # test to make sure that the final regex(es) are valid
        for pattern in condition.match_patterns.values():
            try:
                re.compile(pattern)
            except Exception as e:
                send_error_message(requester, subreddit.display_name,
                    'Generated an invalid regex from section #{0} - {1}'
                    .format(condition_num, e))
                return False

        condition_num += 1
        kept_sections.append(cond_def)

    # Update the subreddit, or add it if necessary
    try:
        db_subreddit = (session.query(Subreddit)
                       .filter(Subreddit.name == subreddit.display_name.lower())
                       .one())
    except NoResultFound:
        db_subreddit = Subreddit()
        db_subreddit.name = subreddit.display_name.lower()
        db_subreddit.last_submission = datetime.utcnow() - timedelta(days=1)
        db_subreddit.last_spam = datetime.utcnow() - timedelta(days=1)
        db_subreddit.last_comment = datetime.utcnow() - timedelta(days=1)
        session.add(db_subreddit)

    db_subreddit.conditions_yaml = page_content
    session.commit()

    r.send_message(requester,
                   '{0} conditions updated'.format(username),
                   "{0}'s conditions were successfully updated for /r/{1}"
                   .format(username, subreddit.display_name))
    return True
Esempio n. 10
0
 def __init__(self, subreddits: list):
     self.subreddits_generator = (Subreddit(subreddit)
                                  for subreddit in subreddits)
Esempio n. 11
0
def update_from_wiki(subreddit, requester):
    """Updates conditions from the subreddit's wiki."""
    global r
    username = cfg_file.get('reddit', 'username')

    try:
        page = subreddit.get_wiki_page(cfg_file.get('reddit', 'wiki_page_name'))
    except Exception:
        send_error_message(requester, subreddit.display_name,
            'The wiki page could not be accessed. Please ensure the page '
            'http://www.reddit.com/r/{0}/wiki/{1} exists and that {2} '
            'has the "wiki" mod permission to be able to access it.'
            .format(subreddit.display_name,
                    cfg_file.get('reddit', 'wiki_page_name'),
                    username))
        return

    html_parser = HTMLParser.HTMLParser()
    page_content = html_parser.unescape(page.content_md)

    # check that all the conditions are valid yaml
    condition_defs = yaml.safe_load_all(page_content)
    condition_num = 1
    try:
        for cond_def in condition_defs:
            condition_num += 1
    except Exception as e:
        indented = ''
        for line in str(e).split('\n'):
            indented += '    {0}\n'.format(line)
        send_error_message(requester, subreddit.display_name,
            'Error when reading conditions from wiki - '
            'Syntax invalid in section #{0}:\n\n{1}'
            .format(condition_num, indented))
        return

    # reload and actually process the conditions
    condition_defs = yaml.safe_load_all(page_content)
    condition_num = 1
    kept_sections = []
    for cond_def in condition_defs:
        # ignore any non-dict sections (can be used as comments, etc.)
        if not isinstance(cond_def, dict):
            continue

        # lowercase all keys
        cond_def = {k.lower(): v for k, v in cond_def.iteritems()}

        try:
            check_condition_valid(cond_def)
        except ValueError as e:
            send_error_message(requester, subreddit.display_name,
                'Invalid condition in section #{0} - {1}'
                .format(condition_num, e))
            return

        # create a condition for final checks
        condition = Condition(cond_def)

        # test to make sure that the final regex(es) are valid
        for pattern in condition.match_patterns.values():
            try:
                re.compile(pattern)
            except Exception as e:
                send_error_message(requester, subreddit.display_name,
                    'Generated an invalid regex from section #{0} - {1}'
                    .format(condition_num, e))
                return

        condition_num += 1
        kept_sections.append(cond_def)

    # Update the subreddit, or add it if necessary
    try:
        db_subreddit = (session.query(Subreddit)
                       .filter(Subreddit.name == subreddit.display_name.lower())
                       .one())
    except NoResultFound:
        db_subreddit = Subreddit()
        db_subreddit.name = subreddit.display_name.lower()
        db_subreddit.last_submission = datetime.utcnow() - timedelta(days=1)
        db_subreddit.last_spam = datetime.utcnow() - timedelta(days=1)
        db_subreddit.last_comment = datetime.utcnow() - timedelta(days=1)
        session.add(db_subreddit)

    db_subreddit.conditions_yaml = page_content
    session.commit()

    r.send_message(requester,
                   '{0} conditions updated'.format(username),
                   "{0}'s conditions were successfully updated for /r/{1}"
                   .format(username, subreddit.display_name))
Esempio n. 12
0
def main():
    global r

    prawlogger = logging.getLogger('prawcore')
    prawlogger.setLevel(logging.WARN)

    while True:
        # Login retry loop
        try:
            logger.info('Logging in as {0}'
                        .format(cfg_file.get('reddit', 'username')))
            r = praw.Reddit(client_id     = cfg_file.get('reddit', 'client_id'),
                            client_secret = cfg_file.get('reddit', 'client_secret'),
                            user_agent    = cfg_file.get('reddit', 'user_agent'),
                            username      = cfg_file.get('reddit', 'username'),
                            password      = cfg_file.get('reddit', 'password'))
            # break
        except Exception as e:
            logger.error('ERROR: {0}'.format(e))
            logger.debug(traceback.format_exc())
        else:
            sr_dict = get_moderated_subreddits()

            # load conditions from wiki
            rule_dict = load_all_rules(sr_dict)

            pprint.pprint(rule_dict)

            break

    while True:
        # main execution loop

        sleep_after = True
        reload_mod_subs = False

        try:
            # First, process command messages
            for message in unread_messages():
                try:
                    command = message.body.strip().lower()
                    sr_name = clean_sr_name(message.subject).lower()
                    subreddit = r.subreddit(sr_name)
                    # TODO: validate user is moderator
                    if message.author not in subreddit.moderator():
                        message.reply('Error: You do not moderate /r/{0}'.format(subreddit.display_name))
                        continue
                    # OK, validated
                    if command == 'register':
                        # do we know this sub?
                        if sr_name in sr_dict.keys():
                            message.reply("I already moderate /r/{}.\n\n".format(sr_name))
                            continue

                        # otherwise... try to accept mod invite
                        try:
                            subreddit.mod.accept_invite()
                        except:
                            # should be APIException(error_type='NO_INVITE_FOUND')
                            message.reply("You must invite me to moderate /r/{} first."
                                          .format(sr_name))
                            raise
                        else:
                            # get sub from db if previously registered:
                            db_subreddit = None
                            try:
                                db_subreddit = (session.query(Subreddit)
                                               .filter(Subreddit.name == sr_name)
                                               .one())
                            except NoResultFound:
                                # add to DB
                                db_subreddit = Subreddit()
                                db_subreddit.name = subreddit.display_name.lower()
                                db_subreddit.last_submission = datetime.utcnow() - timedelta(days=1)
                                db_subreddit.last_spam = datetime.utcnow() - timedelta(days=1)
                                db_subreddit.last_comment = datetime.utcnow() - timedelta(days=1)
                                db_subreddit.conditions_yaml = ''
                                session.add(db_subreddit)
                            finally:
                                # now that it definitely exists: set enabled
                                # (should we clear old rules from the db?)
                                db_subreddit.enabled = True
                                session.commit()
                            message.reply("I have joined /r/{}".format(db_subreddit.name))
                    elif command in ['update', 'status', 'enable', 'disable', 'leave']:
                        # these require the same database query
                        db_subreddit = None
                        try:
                            db_subreddit = (session.query(Subreddit)
                                           .filter(Subreddit.name == sr_name)
                                           .one())
                        except NoResultFound:
                            message.reply("Subreddit /r/{} is not registered with me."
                                          .format(sr_name))
                        else:
                            # only proceed if we get a database hit.
                            if command == 'update':
                                # refresh configuration for a subreddit
                                # todo: cache duplicate requests from multiple mods
                                reload_mod_subs = True
                                update_from_wiki(db_subreddit, message)
                            elif command == 'status':
                                pass
                            elif command == 'enable':
                                db_subreddit.enabled = True
                                reload_mod_subs = True
                            elif command == 'disable':
                                db_subreddit.enabled = False
                                reload_mod_subs = True
                            elif command == 'leave':
                                # leave moderator of subreddit
                                if db_subreddit.enabled:
                                    message.reply("Please disable me on this subreddit first.")
                                else:
                                    # TODO not implemented yet
                                    reload_mod_subs = True
                                    raise NotImplementedError
                            # the following commands should respond with the enabled status
                            if command in ['status', 'enable', 'disable']:
                                message.reply("Subreddit /r/{} is currently {}abled."
                                              .format(db_subreddit.name,
                                                      'en' if db_subreddit.enabled else 'dis'))
                        finally:
                            session.commit()
                    elif command == 'help':
                        # should this just provide a link, or real command explanations?
                        raise NotImplementedError
                    else:
                        # invalid command
                        message.reply("Invalid command.")
                except NotImplementedError:
                    message.reply("Error: that feature is not yet implemented.")
                except KeyboardInterrupt:
                    raise
                except Exception as e:
                    logger.error('ERROR: {0}'.format(e))
                    logger.debug(traceback.format_exc())
                    message.reply("# ERROR:\n\n{}".format(indent_lines(str(e))))
                finally:
                    message.mark_read()

            # changed mod subs
            if reload_mod_subs:
                sr_dict = get_moderated_subreddits()
                rule_dict = load_all_rules(sr_dict)

            # Then process queues: submission, comment, spam, report, comment reply, username mention
            # TODO: queue for edited items...

            # Queue priority, in increasing specificity:
            # - reports: multi/about/reports?only=(links|comments)
            #   - comment
            #   - submission
            #   - any
            # - spam: multi/about/spam?only=(links|comments)
            #   - comment
            #   - submission
            #   - any
            # - edited: multi/about/edited?only=(links|comments)
            #   - comment
            #   - submission
            #   - any
            # - reply: inbox
            # - mention: inbox
            # - submission: multi/new
            # - comment: multi/comments

            multi_mod_queues = ['reports', 'spam', 'edited'] # r.subreddit().mod.<q>
            multi_queues = ['new', 'comments'] # r.subreddit().<q>
            user_queues = ['comment_replies', 'submission_replies', 'mentions'] # r.user.inbox.<q>

            # proof of concept
            for sr_name, subreddit in sr_dict.items():
                logger.debug("Checking items in /r/{}".format(sr_name))

                sr = r.subreddit(sr_name)

                # mod-only level queues
                for item in sr.mod.spam():
                    for rule in rule_dict[sr_name]:
                        rule.process(item)
                for item in sr.mod.reports():
                    for rule in rule_dict[sr_name]:
                        rule.process(item)
                for item in sr.mod.edited():
                    for rule in rule_dict[sr_name]:
                        rule.process(item)

                # sub-level queues
                for item in sr.mod.new():
                    for rule in rule_dict[sr_name]:
                        rule.process(item)
                for item in sr.mod.comments():
                    for rule in rule_dict[sr_name]:
                        rule.process(item)

                # user queues - not implemented


            # for queue in queue_funcs:
            #     subreddits = [s for s in sr_dict
            #                   if s in cond_dict and len(cond_dict[s][queue]) > 0]
            #     if len(subreddits) == 0:
            #         continue

            #     multireddits = build_multireddit_groups(subreddits)

            #     # fetch and process the items for each multireddit
            #     for multi in multireddits:
            #         if queue == 'report':
            #             limit = cfg_file.get('reddit', 'report_backlog_limit_hours')
            #             stop_time = datetime.utcnow() - timedelta(hours=int(limit))
            #         else:
            #             stop_time = max(getattr(sr, 'last_'+queue)
            #                              for sr in sr_dict.values()
            #                              if sr.name in multi)

            #         queue_subreddit = r.get_subreddit('+'.join(multi))
            #         if queue_subreddit:
            #             queue_func = getattr(queue_subreddit, queue_funcs[queue])
            #             items = queue_func(limit=None)
            #             check_items(queue, items, stop_time, sr_dict, cond_dict)



        except KeyboardInterrupt:
            raise
        except Exception as e:
            logger.error('ERROR: {0}'.format(e))
            logger.debug(traceback.format_exc())
            session.rollback()
        finally:
            if sleep_after:
                logger.info('Sleeping for 10 seconds')
                sleep(10)
                logger.info('Sleep ended, resuming')

        logging.info("Looping")