CSE 30332 - HW4
                    Programming Paradigms
                    
                    
                        In this assignment you will be using HTML and CSS to build flask templates
                        for your API. Building on top of HW3 you will be using these
                        tools to wrap your Reddit data and display them nicely on the front-end
                    
                 
                
                    
Modifying your classes
                    reddit_classes.py
                    
                    Your classes will remain largely similar to HW3, with a few small tweaks. As we now need
                    to pass many variables to the template that we return to the user, your display methods should
                    now return a list of objects that you want to pass forward to the jinja2 template. For subreddits
                    and posts this is simple as we already have the classes set up, we just need to slightly modify the
                    display methods. However this becomes more difficulty when it comes to the comments. To help with this
                    make a simple Comment class that can hold information for each comment: user, time, attr, body, and children.
                    This will mean that when you want to display a comment chain we can simply pass a list of the top level
                    comments to the template and can do the rest using jinja2 features.
                
                
                    
Setting up the API
                    reddit_api.py
                    
                    Your API will have 4 endpoints:
                    
                     The landing page will display the subreddit links.
                    The second endpoint will allow the user to add a single number to the URL to see
                    the post titles for the subreddit associated with the number they added to the URL.
                    The third endpoint will allow the user to add another number to the URL in addition
                    to the first. This second number will be associated with a post title from the subreddit
                    associated with the first number. This endpoint will display the comments for the post.
                    Finally, the fourth endpoint will be one accepting both GET and POST requests that will
                    allow the requester to change attributes of the Settings object during runtime.
                    using the HTML forms we saw during lecture.
                    
                    Note that now instead of expecting your user to modify the URL directly, they will have links that
                    they can click to take them forward in the "levels" of our webpage. For now, we can simply rely on
                    the user's web browser's back button to take them back to the previous page. We can keep the endpoint
                    URL scheme the same, but now we will need to pass a URL for each button to the template that we
                    can insert.
                
                
                    
Running a Flask server
                    
                    To run a flask server you first need to set the environmental variable FLASK_APP
                    for your shell. After doing so you can run your server using the command: 
                    python3 -m flask run -p [PORT]
                    where [PORT] is a number between 9000 and 9999. You could also add a main function
                    to your API file to run your code as we've seen in class 4-5 times now.
                
                
                    
Code Overview and Scaffold
                    
                    To help you get some sense of the approximate length of each part of the code, I have
                    included the number of lines used in each section in my solution. I will of course
                    probably implement my code slightly differently than you may. Therefore you should take
                    these as a relative reference only, it is completely reasonable that your code may be
                    several lines shorter or longer. You should only start to worry if yours is significantly
                    different than what I have.
                
                
                
                    reddit_api.py
                    
                        
from flask import Flask, request, render_template
from flask_sqlalchemy import SQLAlchemy
from db_manager import db_session
from reddit_classes import Settings, Subreddit, Post
from flask_bootstrap import Bootstrap
from flaskext.markdown import Markdown
app = Flask(__name__)
Bootstrap(app)
Markdown(app)
setr = None
subs = None
def check_globals() -> None: # 8 LOC
    global setr
    global subs
    # create the settings object if it doesn't exist
    # get the subreddit objects from the database and add the settings object
    # if the subreddit objects don't already exist
@app.route('/')
def display_subreddits() -> str: # 6 LOC
    check_globals()
    # return a template displaying all of the subreddits and links to their posts
@app.route('/<int:sub_id>/')
def display_post_titles(sub_id: int) -> str: # 2 LOC
    check_globals()
    # return a template displaying all of the posts and links to their comments
@app.route('/<int:sub_id>/<int:post_id>/')
def display_post_comments(sub_id: int, post_id: int) -> str: # 6 LOC
    check_globals()
    # return a template displaying all of the comments
@app.route('/settings/', methods=['GET', 'POST'])
def settings() -> None: # 12 LOC
    check_globals()
    # if there is a POST request update the Settings object with the new items
    # if there is a GET request, display the current settings using a settings template
    # return a status code for a successful request
@app.teardown_appcontext
def shutdown_session(exception=None):
    db_session.remove()
if __name__ == '__main__':
    # run your app
                        
                    
                 
                
                    reddit_classes.py
                    
                        
import re
import os
import requests
from db_manager import Base
from sqlalchemy import Column, Integer, String, Boolean
class Settings(Base):
    __tablename__ = 'settings'
    user_id = Column(Integer, primary_key=True)
    # add all of the Columns for the settings the program will have
    # 11 LOC
    def __init__(self, sub_regex='.*', title_regex='.*', comment_regex='.*',
                        sub_num=25, title_num=25, comment_num=25,
                        sub_reverse=False, title_reverse=False, comment_reverse=False,
                        title_attr='score', comment_attr='score'):
       # set all of the attributes for the Settings object 
       # 11 LOC
    def __repr__(self) -> str:
        return super().__repr__()
class Subreddit(Base):
    __tablename__ = 'subreddits'
    id = Column(Integer, primary_key=True)
    # add a column for the subreddit URL
    # 1 LOC
    def __init__(self, url: str, settings: Settings) -> None: # 2 LOC
        # set the two Subreddit attributes
    def scrape(self) -> None: # 4 LOC
        # scrape the Subreddit URL and instantiate a list of Post objects
    def display(self, loc: int, titles: bool = False) -> tuple: # 8 LOC
        # return a tuple with the subreddits URL and a list of Posts you want to
        # display (it's possible this may be an empty list)
        # if titles is True, then scrape the subreddit
        
    def filter(self) -> bool: # 3 LOC
        # Check if the URL of the subreddit matches the regex for subreddits
    def __repr__(self) -> str:
        return super().__repr__()
class Post(Base):
    __tablename__ = 'posts'
    id = Column(Integer, primary_key=True)
    # add a column for the post URL
    # 1 LOC
    def __init__(self, data, settings) -> None: # 6 LOC
        # set the Posts attributes from the passed in data
        # such as title, selftext, and name
    def scrape(self) -> None: # 3 LOC
        # scrape the Post's URL
    def display(self, loc: int, comments: bool = False) -> tuple: # 10 LOC
        # return a tuple containing the posts title and a list of all Comments to display
        # it's possible the comment list may be empty
        # if comments is true, then scrape the post
    def display_comment_tree(self, reply_dict: dict, depth: int) -> str: 12 LOC
        # return a single comment object, whose children attribute contains the comments children
    def filter(self, item, comments: bool = False) -> bool: # 6 LOC
        # return true or false depending on whether or not the item matches its regex
    def __repr__(self) -> str:
        return super().__repr__()
class Comment():
    def __init__(self, user, time, body, attr):
        # initialize the attributes of the comment class
        # additionally add a list of child comments as well
                        
                    
                 
                
                    subreddits.html
                    
                        
{% extends 'bootstrap/base.html' %}
{% block content %}
<div class="container">
    {% for sub in subs %}
    <!-- Add each subreddit to a panel container and add a link to view the subreddits posts -->
    <!-- 6 LoC -->
    {% endfor %}
</div>
{% endblock %}
                        
                    
                 
                
                    posts.html
                    
                        
{% extends 'bootstrap/base.html' %}
{% block content %}
<div class="container">
    {% for post in posts %}
    <!-- Add each post to a panel container and add a link to view the posts comments -->
    <!-- Use a flask filter to correctly render the markdown -->
    <!-- 9 LoC -->
    {% endfor %}
</div>
{% endblock %}
                        
                    
                 
                
                    comments.html
                    
                        
{% extends 'bootstrap/base.html' %}
{% block content %}
<style>
    /*
    Add styling to your comments using CSS
    101 LoC
    */
</style>
<h4 class="text-center mb-4 pb-2">{{ title }}</h4>
<div class="container">
{% for comment in comments recursive %}
    <div class="comment">
<!-- Add each comment to a container recursively including the user, attr, post-time, and body -->
<!-- 40 LoC -->
    </div>
{%- endfor %}
</div>
{% endblock %}
                        
                    
                 
                
                    settings.html
                    
                        
{% extends 'bootstrap/base.html' %}
{% block content %}
<style>
    /* add some style to your settings page using CSS */
    /* 30 LoC */
</style>
<div class="container">
    <!-- Add a form entry area for each attribute in your settings object -->
    <!-- When the page is accessed show the current settings in the entry areas -->
    <!-- Have a single submission button to send the new settings to the backend -->
    <!-- You can assume that the entries for the settings will be nicely entered for this assignment -->
    <!-- 55 LoC -->
</div>
{% endblock %}
                        
                    
                 
                
                
                     We'll do it live
                    Note, since we are pulling data from an active website, the articles may
                    change between runs.
                 
                
                    
Reddit API Oddities
                    
                
                
                    
                        
                            There have been several oddities in the reddit API that have been brought to my attention.
                            Firstly, image posts are causing lots of problems for students and secondly, every once in
                            a while you'll get a replies dictionary that is not empty but also not formatted
                            in the standard manner. To handle these I recommend you make use of try/except blocks.
                            The cats subreddit especially has proven problematic and as such we will be lenient when grading in
                            relation to this specific subreddit.
                        
                     
                 
                
                    
Submission Instructions
                    
                
                
                    
                        
                            This assignment is due by 11:59 PM on Monday, April 17th (04/17).
                            To submit, please create a folder named HW4 in your dropbox. Then
                            put your python files, named reddit_api.py, reddit_classes.py,
                            db_manager.py, and reddit_setter.py into this folder.
                            Create a sub-directory named templates as seen in class in which to
                            place your four html files: subreddits.html, posts.html,
                            comments.html, and settings.html.
                            Assignments are programmatically collected at the due date.
                        
                     
                 
                
                    
Extension Policy
                    
                        The course's late work policy is that late work recieves no credit.
                        However, we all live busy and active lives and should you feel like you
                        cannot finish the assignment by the due date, please email me and ask
                        for an extension. Given that the email is polite, I will almost certainly
                        grant the extension. 
                
                
                    
Grading Rubric
                    
                
                
                    
                        
                            
                                
                                    | Component | 
                                    Points | 
                                
                            
                            
                                
                                    
                                        Index, Post, Comment endpoints follow guidelines:
                                         
                                            - return a template for each level 
                                     | 
                                    10
                                         
                                        10 
                                     | 
                                
                                
                                    Subreddit class follows guidelines:
                                         
                                            - Display properly returns tuple 
                                            - Instantiates Posts with full data from subreddit scrape 
                                     | 
                                    10
                                         
                                        5 
                                        5 
                                     | 
                                
                                
                                    Post class follows guidelines:
                                         
                                            - Only scrapes when comments are needed 
                                            - Uses Comments class to create a tree of nested objects 
                                            - Properly returns tuple 
                                     | 
                                    10
                                         
                                        2 
                                        5 
                                        3 
                                     | 
                                
                                
                                    Comments class follows guidelines:
                                         
                                            - Correctly instantiates attributes 
                                            - Children attribute implemented as list of Comment objects 
                                     | 
                                    5
                                         
                                        2 
                                        3 
                                     | 
                                
                                
                                    Settings endpoint follows guidelines:
                                         
                                            - Correctly handles both GET and POST requests 
                                     | 
                                    5
                                         
                                        5 
                                 | 
                                
                                    Templates correctly follow guidelines:
                                         
                                            - Use jinja2 to add data to the template 
                                            - Uses a markdown filter to render the bodies correctly 
                                            - Properly nests comments 
                                     | 
                                    10
                                         
                                        2 
                                        3 
                                        5 
                                 | 
                                
                                    | Templates work correctly (Looks nice, buttons work, settings reflected, etc...): | 
                                    20 | 
                                
                                
                                    | Code style | 
                                    5 | 
                                
                                
                                    | Total | 
                                    75 |