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.
Picture of me and my group at N@tM