Example #1
0
class goose_bot:
    """Goose bot class, performs actions for a reddit helper bot."""
    def __init__(self, bot_name, api_key):
        print("Logging in to reddit as " + bot_name + "...")
        self.bot = praw.Reddit(bot_name)
        print("Logged in as " + bot_name + "!")
        self.uw_key = api_key
        self.uw_api = UWaterlooAPI(api_key)

        self.sub_reply_txt = f'./modules/submission_replies_u_{bot_name}.txt'

##############################################################################
#                        UW COURSE COMMENTING METHODS                        #
##############################################################################

    def _parse_uw_course_text(self, text):
        """Private method that parses specified text for a course code \n
           i.e: CS 136"""
        match = re.compile('[A-Za-z]{2,}\s?[0-9]{3}')
        course_tuple = re.findall(match, text)
        courses = []

        # Transfer tuple elements into array, removing any possible middle spacing
        for course in course_tuple:
            course = course.replace(" ", "")
            courses.append(course)
        # Converting to dictionaries removes duplicate courses
        courses = list(dict.fromkeys(courses))
        return courses

    def _gen_uw_course_comment(self, text):
        """Generates a bot reply containing links to courses mentioned
           in a submission and its full title for context."""
        courses = self._parse_uw_course_text(text)
        reply_string = 'Honk! It looks like you mentioned a few university courses in your post!\n\n'
        matching = re.compile('[A-Za-z]{2,}|[0-9]{3}')

        # print url and a short course name descrip.
        for course in courses:
            program_course_array = re.findall(matching, course)
            program_name = program_course_array[0].upper()
            course_code = program_course_array[1]
            if self.uw_api.course(program_name, course_code):
                course = self.uw_api.course(program_name, course_code)
                reply_string += f'\n\n[{program_name} {course_code}]({course["url"]}): {course["title"]} \n\n'
            elif len(courses) == 1:
                # If one element exists but does not match any course code,
                # no reply should be generated.
                return ""
        reply_string += "\n\n---\n\n"
        reply_string += f"\n\nI am an automated goose 🦢 - you can contact my creators [here](https://www.reddit.com/message/compose/?to=/u/{self.bot.user.me().name})"
        return reply_string

##############################################################################
#                          SUBMISSION REPLY METHODS                          #
##############################################################################

    def check_match(self, submission):
        """Checks if reddit submission title or text contains given content type,
           and if bot has already responded to post.\n
           Returns true if post matches content_type regex,
           and if no bot comment exists on post."""
        if re.search(r'[A-Za-z]{2,4}\s?[0-9]{3}', submission.title) or \
            re.search(r'[A-Za-z]{2,4}\s?[0-9]{3}', submission.selftext):
            if self._post_id_check(
                    submission.id):  # bot comment exists, and content match
                return False
            else:
                return True  # no bot comment exists, and matches specific content
        # Insert any other string matches here...
        else:
            return False  # no content match

    def submission_reply(self, submission, content_type="courses"):
        """Replies to the submission, and adds the submission id to a txt document."""
        comment = ""
        # To check for both submission text and body for content,
        # just concatenate them into the same string, separated by a space.
        if content_type == "courses":  # for course replies
            comment = self._gen_uw_course_comment(submission.title + " " +
                                                  submission.selftext)
        # Insert other content_type flagging here...

        if comment:  # If generated comment is non-empty
            print(
                f'Replying to post \"{submission.title}\" with id {submission.id}'
            )
            submission.reply(comment)
            self._save_submission_id(submission.id)

    def _post_id_check(self, submission_id):
        """Private method to check if submission id exists in txt file"""
        try:
            read_comment_id = open(self.sub_reply_txt)
        except IOError:
            read_comment_id = open(self.sub_reply_txt, 'w+')
            read_comment_id.close()
            read_comment_id = open(self.sub_reply_txt, "r")
        readline_comment_id = read_comment_id.readlines()
        for line in readline_comment_id:
            if submission_id + "\n" == str(line):
                read_comment_id.close()
                return True
        read_comment_id.close()
        return False  # empty txt file or bot did not comment.

    def _save_submission_id(self, submission_id):
        """Private method that adds submission id of which a reply 
           was made to into a txt document."""
        with open(self.sub_reply_txt, "a+") as write_comment_id:
            print(f'Saving {submission_id} to {self.sub_reply_txt}')
            write_comment_id.write(f'{submission_id}\n')

##############################################################################
#                              MENTION REPLIES                               #
##############################################################################

    def inbox_reply(self, comment):
        """Replies to inbox mentions or comments replies on posts, when they match specific 
           words or phrases below."""
        if "good bot" in comment.body.lower():
            comment.reply(self._good_bot())
            comment.mark_read()
        elif "bad bot" in comment.body.lower():
            comment.reply(self._bad_bot())
            # add the user to a filter list
            comment.mark_read()
        elif "thank mr. goose" in comment.body.lower():
            comment.reply(self._thank_mr_goose())
            comment.mark_read()
        elif "bruh moment" == comment.body.lower() \
            or "bruh"== comment.body.lower():
            comment.reply(self._bruh_moment())
            comment.mark_read()
        else:
            return
        print(
            f'Replying to comment {comment.id}, found on the post ' +
            f'\"{comment.submission.title}\", with id {comment.submission.id}')

    def _good_bot(self):
        return 'honk honk! 🦢'

    def _bad_bot(self):
        # put user on removal list
        return 'sad honk :('

    def _thank_mr_goose(self):
        return 'thank mr. goose <3'

    def _bruh_moment(self):
        return 'bruh moment'

##############################################################################
#                           String overload functions                        #
##############################################################################

    def __repr__(self):
        return str({
            "Bot name": self.bot.user.me().name,
            "Bot ID": self.bot.user.me().id,
            "UW key": self.uw_key,
            "Bot karma": self.bot.user.me().comment_karma,
            "Bot creation": self.bot.user.me().created_utc
        })

    def __str__(self):
        return  f'Bot name:     {self.bot.user.me().name} \n' + \
                f'Bot ID:       {self.bot.user.me().id} \n' + \
                f'UW key:       {self.uw_key} \n' + \
                f'Bot karma:    {self.bot.user.me().comment_karma} \n' + \
                f'Bot creation: {self.bot.user.me().created_utc}'
Example #2
0
 logging.debug(comment)
 logging.debug(comment.id)
 cursor.execute("SELECT comment_id FROM comments")
 already_done = [r[0] for r in cursor]
 # Check comments that have not already been replied to
 if comment.id not in already_done:
     reply = ""
     # Find all comments with [[]]
     result = re.findall(r'\[\[(.+?)\]\]', comment.body)
     for code in result:
         code_list = code.split()
         logging.debug(code_list)
         # Check if comment is a valid course
         if code_list[0].upper() in uw_subjects:
             try:
                 course = uw.course(code_list[0].upper(), code_list[1])
                 if course:
                     online = "Yes" if course.get("offerings").get("online") else "No"
                     reply += \
                     "[{} {} {} {} | {} | Course ID: {}](https://uwflow.com/course/{}{})\
                     \n\n{}\
                     \n\n*Prerequisites: {}*\n\n*Antirequisites: {}*\
                     \n\n*Available Online: {}*\n\n"\
                     .format(course.get("subject"),\
                     course.get("catalog_number"),\
                     ','.join(course.get("instructions")),\
                     course.get("units"),\
                     course.get("title"),\
                     course.get("course_id"),\
                     course.get("subject").lower(),\
                     course.get("catalog_number"),\