Skip to the content.

CPT Requirements and N@tM Review

An explanation of how I meet the CPT requirements along with how N@tM went.

CPT Requirements

This is where I’ll be going over the CPT requirements and how I fulfill them with my project.

An Input

My binaryOverflow API takes an input from an HTTPS request takes an input in a number of ways. I’ll go over each of the possible inputs here now.

The first input is for creating a new post on the Binary Overflow homepage. It listens for a POST HTTPS request and reads the body stored with the HTTPS request. The body is a bunch of data stored in JSON format. It takes this data to initialize a new binaryOverflow class to store using flask

    class fetch_frontend(Resource):
        @token_required()
        def post(self):
            current_user = g.current_user
            data = request.get_json()
            post = BinaryOverflowContent(data["title"], current_user.id, data["content"])
            post.create()
            return jsonify(post.read())

All of the inputs for my API use this method in order to receive data. There is one exception to this though, and that is one of the GET methods.

Another method of input I use is in my GET method for my HTTPS request. I check the URL for request parameters, looking for an ‘id’ parameter. Using this parameter I search the database for a class with the same ‘id’ and process the associated class into a readable format for the frontend to process.

    class POST_CRUD(Resource):
        def get(self):
            post_id = request.args.get('id')
            try:
                post = BinaryOverflowContent.query.get(post_id)
                post_json_ready = post.read()
                comments = post.comments
                comments_json_ready = [comment.read() for comment in comments]
                return {
                    'post': post_json_ready,
                    'comments': comments_json_ready
                }
            except Exception as e:
                return "There was an issue with fetching the post: " + str(e)

List or Other Collection Type

In Binary Overflow we use many data collection methods, but the most important one is our database that is developed using flask. It contains all the post data stored on the front page of the website. The database is created in our model, a class is defined along with a tablename. Whenever we initialize a new class it adds a new data point to the database and uses the data we initialized in the class to determine what to display in the database or .db file.

class BinaryOverflowContent(db.Model):
    __tablename__ = 'binaryPostContent'
        
    # Defined columns
    id = db.Column(db.Integer, primary_key=True)
    _title = db.Column(db.String(255), nullable=False)
    _author = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    _date_posted = db.Column(db.DateTime, nullable=False, default=datetime.now(timezone.utc))
    _content = db.Column(db.String(255), nullable=False)
    
    # Defined relationships
    comments = db.relationship('BinaryOverflowComments', backref='comments', cascade='all, delete-orphan')
    votes = db.relationship('BinaryOverflowContentVotes', backref='votes', cascade='all, delete-orphan')
    
    # Initial parameters to create the class
    def __init__(self, title, author, content):
        self._title = title
        self._author = author
        self._content = content
    
    # Called when repr(object) is called. I think
    def __repr__(self):
        return f'BinaryOverflowContent(id={self.id}, title={self._title}, author={self._author}, date_posted={self._date_posted}, content={self._content})'
    
    # Create a new post object
    def create(self):
        try:
            db.session.add(self)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            raise e
        
    # Reads the data and returns it in a dictionary, key-pair value format
    def read(self):
        user = User.query.get(self._author)
        votes = [vote.read() for vote in self.votes]
        upvotes = 0
        downvotes = 0
        # There's probably a more efficient way to do this but oh well
        if votes:
            for vote in votes:
                if vote['vote'] < 0:
                    downvotes += 1
                elif vote['vote'] > 0:
                    upvotes += 1
        return {
            'id': self.id,
            'title': self._title,
            'author': user.name if user else self._author, 
            'date_posted': self._date_posted.isoformat(),
            'content': self._content,
            'upvotes': upvotes,
            'downvotes': downvotes
        }
        
    # Updates the data inside. Only updates things that should be updated using a PUT statement
    def update(self, new_data):
        # Checks if the new_data is in a dictionary format
        if not isinstance(new_data, dict):
            return self
        
        # Gets the new data and sets it equal to these variables, these are the only things that should be changed using PUT
        title = new_data.get("title", "")
        content = new_data.get("content", "")
        
        if title:
            self._title = title
        if content: 
            self._content = content
        
        try:
            db.session.commit()
        except IntegrityError:
            db.session.rollback()
            return None
        return self
    
    # Deletes the data
    def delete(self):
        try:
            db.session.delete(self)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            raise e
    
    def vote(self, vote, user):
        return self.votes

Then we use the create method in order to save the data we created to the database. This is one of the ways we use a data collection in order to process and/or store data to fulfill this program’s purpose.

A Procedure

One of the procedures I created is the post method for my CONTENT_VOTE class. The method returns new vote created or updated when called. This is an important method as it allows users to vote in posts in order to see the most important posts on Binary Overflow.

    class CONTENT_VOTE(Resource):
        @token_required()
        def post(self):
            data = request.get_json()
            current_user = g.current_user
            vote = BinaryOverflowContentVotes.query.filter_by(_user=current_user.id, id=data['post_id']).first()
            if vote:
                vote.update(data)
            else:
                vote = BinaryOverflowContentVotes(data["post_id"], current_user.id, data["vote"])
                vote.create()
            return jsonify(vote.read())

The above code has an interesting return type but does not have any parameters. For a parameter we should look at the update method inside my model. This method takes in data and checks if it is in a dictionary format, Basically a Python object. Then it takes this and redefines the existing data to match the key pairs defined in the dictionary. It’ll then return the entire object for a person to see, this can be helpful for changing the frontend to match the data.

    def update(self, new_data):
        # Checks if the new_data is in a dictionary format
        if not isinstance(new_data, dict):
            return self
        
        # Gets the new data and sets it equal to these variables, these are the only things that should be changed using PUT
        title = new_data.get("title", "")
        content = new_data.get("content", "")
        
        if title:
            self._title = title
        if content: 
            self._content = content
        
        try:
            db.session.commit()
        except IntegrityError:
            db.session.rollback()
            return None
        return self

Sequencing, Selection, & Iteration

My code also contains the sequencing, selection and iteration in different parts. In the previous examples you can see all three. Sequencing is used in all the code above when the method is called it reads line by line executing each action. Selection is used for my voting API where I check the current user and if they have a vote for the post already, if they do we just update that post. However, if they don’t then we create a new post for the user under the post_id. Iteration is used when counting votes in the Binary Overflow Content model, where we take every vote and put it into a list, iterating over the list and adding a vote depending on the state of the variable.

    def read(self):
        user = User.query.get(self._author)
        votes = [vote.read() for vote in self.votes]
        upvotes = 0
        downvotes = 0
        # There's probably a more efficient way to do this but oh well
        if votes:
            for vote in votes:
                if vote['vote'] < 0:
                    downvotes += 1
                elif vote['vote'] > 0:
                    upvotes += 1
        return {
            'id': self.id,
            'title': self._title,
            'author': user.name if user else self._author, 
            'date_posted': self._date_posted.isoformat(),
            'content': self._content,
            'upvotes': upvotes,
            'downvote': downvotes
        }

The above code is both an example of sequencing and iteration. You can see a list being created for each vote in the votes list and then later looping over each vote checking what kind of vote it is to determine downvotes and upvotes.

We also use selection in this same code as well with an if statement. This if statement is used to check if the votes variable was defined with any data. Since we wouldn’t be able to iterate over an empty or non-existent list. If it does exist we iterate over the votes. If it doesn’t we don’t do anything.

Calls to Procedure

I call the CONTENT_VOTE, POST procedure whenever the API is called to the correlating url and the method defined is POST. This will happen on the frontend when a fetch is called it calls the method and runs it. This is an example of a call to the procedure. Typically this call would occur when a user wanted to vote on a post.

Instructions for output (tactile, audible, visual, or textual) based on input and program functionality

I don’t know what this means.

N@tM Feedback

We showed our website at Night at the Museum, this is it here. We had 3 main visitors that come to mind, my own parents and Shriya’s mother. We went over the website and after explaining how binary works let them try out Weston’s game. They seemed receptive to it and tried playing it, getting decently far before we cut it short in order to demo the next feature. We then showed them Binary Overflow and explained it’s purpose, we didn’t go too in-depth on it as we were running low on time due to the amount of time spent talking about Weston’s game. We then went over Shaurya and Rutvik’s game where they were meant to solve trivia. Unfortunately it was much too difficult and we didn’t see much progress in that area.

Photo of my group at N@tM

Picture of me and my group at N@tM