Skip to content

Commit

Permalink
Implemented Tags (#29)
Browse files Browse the repository at this point in the history
* Added Anurag 1:1 meeting

* Meeting notes for 1:1 05-12-2020

* Updated frontend notes

* Create 5-13-20-Jason-onboarding.md

* 5-13-20-Jason-onboarding

* Delete 5-13-20-Jason-onboarding.md

* Update 5-13-20-Jason-onboarding.md

* Update 5-13-20-Jason-onboarding.md

* Updated folders to not break windows laptops

* Initial commit

* Added Tag model

* Added emoji field

* Added emoji field to Meta class

* Implemented create_tag function

* Implemented CreateTag

* Implemented Update Tag function

* Implemented FetchTags

* Implemented TagFollowers

* Removed comment

* Added tag

* Implemented Tag Routes, Models, Schemas, Decorators & Utils

* Fixed typo for submission_guidelines --> submission_guideline

* Updated comments

* Added comment

Detailed comment that explains many to many relationship to keep track of user id and tag id

* Modified backref to back_populates for user and tag models

* Added validate_form_data decorator to ensure sanitized data

* Removed unused code

* Updated relationships in Tag and User model

* updated

* Fixed name of typo in validate_tag_form decorator

* Updated

* Updated

* Added toasted marshmallow.jit
  • Loading branch information
grchng authored May 16, 2020
1 parent c6ac0f0 commit 099da4a
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 3 deletions.
3 changes: 3 additions & 0 deletions api/backend/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

app = Flask(__name__)


app.config['GITHUB_CLIENT_ID'] = GITHUB_CLIENT_ID
app.config['GITHUB_CLIENT_SECRET'] = GITHUB_CLIENT_SECRET
app.config["PROPAGATE_EXCEPTIONS"] = True
Expand All @@ -27,8 +28,10 @@
from ..backend.home.routes import home_bp
from ..backend.meta.routes import meta_bp
from ..backend.users.routes import user_bp
from ..backend.tags.routes import tag_bp

app.register_blueprint(authentication_bp)
app.register_blueprint(home_bp)
app.register_blueprint(meta_bp)
app.register_blueprint(user_bp)
app.register_blueprint(tag_bp)
26 changes: 25 additions & 1 deletion api/backend/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
from api.backend import db


# A many to many relationship to keep track of tags and users
user_tag_rel = db.Table("user_tag_rel",
db.Column("user_id", db.Integer, db.ForeignKey("user.id"), primary_key=True),
db.Column("tag_id", db.Integer, db.ForeignKey("tag.id"), primary_key=True)
)


class Meta(db.Model):
id = db.Column(db.Integer, primary_key=True)
roles = db.Column(db.Text, nullable=True)
Expand All @@ -9,6 +16,7 @@ class Meta(db.Model):
student = db.relationship("Student", uselist=False, cascade="all,delete", back_populates="meta")
teacher = db.relationship("Teacher", uselist=False, cascade="all,delete", back_populates="meta")


def __repr__(self):
return f"Meta('{self.id}')"

Expand All @@ -24,7 +32,9 @@ class User(db.Model):
image = db.Column(db.Text, nullable=True)
meta_id = db.Column(db.Integer, db.ForeignKey('meta.id'))
meta = db.relationship("Meta", back_populates="user")

tags = db.relationship("Tag", secondary="user_tag_rel",
back_populates="users")

def __repr__(self):
return f"User('{self.email}')"

Expand Down Expand Up @@ -54,3 +64,17 @@ class Teacher(db.Model):

def __repr__(self):
return f"Teacher('{self.id}')"


class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True, nullable=False)
name = db.Column(db.Text, nullable=False)
summary = db.Column(db.Text, nullable=False)
submission_guideline = db.Column(db.Text, nullable=False)
about = db.Column(db.Text, nullable=False)
emoji = db.Column(db.Text, nullable=False)
users = db.relationship("User", secondary="user_tag_rel",
back_populates="tags")

def __repr__(self):
return f"Tag('{self.id} , {self.name}')"
39 changes: 39 additions & 0 deletions api/backend/tags/decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from ..models import Tag
from functools import wraps
from ..tags.schemas import tag_form_schema
from flask import request


# Decorator to check if a tag exists
def tag_exists(f):

@wraps(f)
def wrap(*args, **kwargs):
tag = Tag.query.get(kwargs['tag_id'])

if tag:
return f(*args, **kwargs)
else:
return {
"message": "Tag does not exist"
}, 404

return wrap


# Decorator to check if data in form is valid
def validate_tag_form(f):

@wraps(f)
def wrap(*args, **kwargs):
form_data = request.get_json()
errors = tag_form_schema.validate(form_data)

if errors:
return {
"message": "Unable to create tag. Please enter all required form inputs."
}, 422
else:
return f(*args, **kwargs)

return wrap
95 changes: 95 additions & 0 deletions api/backend/tags/routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from .. import api, db
from ..models import Tag, User
from ..tags.decorators import tag_exists, validate_tag_form
from ..tags.schemas import tag_schema, tags_schema, tag_form_schema
from ..tags.utils import create_tag, update_tag
from flask import Blueprint, request, session
from flask_restful import Resource

# Blueprint for tags
tag_bp = Blueprint("tags", __name__)


# Class to fetch and create tag
class Tags(Resource):
# Create Tag
@validate_tag_form
def post(self):
form_data = request.get_json()
tag = create_tag(form_data)

db.session.add(tag)
db.session.commit()

return {
"message": "Tag sucessfully created"
}, 201


# Fetch Tags
def get(self):
tag = Tag.query.limit(15).all()

if len(tag) != 0:
return tags_schema.dump(tag)
else:
return {
"message": "No Tags"
}, 404


# Class for updating, deleting & fetching tags
class TagCRUD(Resource):
# Update specific tag
@validate_tag_form
@tag_exists
def put(self, tag_id):
tag = Tag.query.get(tag_id)
form_data = request.get_json()
update_tag(tag, form_data)

db.session.commit()

return {
"message": "Tag successfully updated"
}, 200

# Fetch specific tag
@tag_exists
def get(self, tag_id):
tag = Tag.query.get(tag_id)

return tag_schema.dump(tag)

# Delete specific tag
@tag_exists
def delete(self, tag_id):
tag = Tag.query.get(tag_id)

db.session.delete(tag)
db.session.commit()

return {
"message": "Tag successfully deleted"
}, 200


# Class to update followers
class TagFollowers(Resource):
def put(self, tag_id):
user_data = session["profile"]
user = User.query.get(user_data["user_id"])
tag = Tag.query.get(tag_id)

tag.users.append(user)
db.session.commit()

return {
"message": user.name + "is now following" + tag.name
}, 200


# # Creates the routes for the classes
api.add_resource(Tags, "/api/tags")
api.add_resource(TagCRUD, "/api/tags/<int:tag_id>")
api.add_resource(TagFollowers, "/api/tags/<int:tag_id>/followers")
28 changes: 28 additions & 0 deletions api/backend/tags/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from marshmallow import Schema, fields
import toastedmarshmallow


# Validates tag form
class TagFormSchema(Schema):
name = fields.Str(required=True)
summary = fields.Str(required=True)
submission_guideline = fields.Str(required=True)
about = fields.Str(required=True)
emoji = fields.Str(required=True)

class Meta:
# Fields to show when sending data
fields = ("name", "summary", "submission_guideline", "about", "emoji")
ordered = True


class TagSchema(Schema):
id = fields.Int(required=True)


tag_form_schema = TagFormSchema()
tag_schema = TagSchema()
tags_schema = TagSchema(many=True)
tag_form_schema.jit = toastedmarshmallow.Jit
tag_schema.jit = toastedmarshmallow.Jit
tags_schema.jit = toastedmarshmallow.Jit
24 changes: 24 additions & 0 deletions api/backend/tags/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from ..models import Tag


# Function to create a tag
def create_tag(form_data):
tag = Tag(name=form_data["name"],
summary=form_data["summary"],
submission_guideline=form_data["submission_guideline"],
about=form_data["about"],
emoji=form_data["emoji"]
)

return tag


# Function to update a tag
def update_tag(tag, form_data):
tag.name = form_data["name"]
tag.summary = form_data["summary"]
tag.submission_guideline = form_data["submission_guideline"]
tag.about = form_data["about"]
tag.emoji = form_data["emoji"]

return
36 changes: 36 additions & 0 deletions meetings/one-on-ones/5-12-20-Anurag-onboarding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Meeting Purpose
Weekly meeting

**Lead**
Bryan

**Attendees**
* Anurag

## Updates:
*What has been completed and can be checked off*

*

## Discussion Points:
*Ideas, feedback, concerns, plans*
* Understand the overview of the onboarding procedure
* Breakdown of tasks and expectations for the first week
* Understand what Engineering team does
Practice taking notes on Github during the 1:1
* Please give your overview feedback and express what position you are within the Engineering team!
* Give onboarding feedback
*

## Action Plan:
*Where to go next, dependencies, all deadlines*
*Bryan will talk to the People team to improve the onboarding process and have them delve more into what BitProject actually represents as an organization.
*Watch the remaining webinars and close this issue.

## Deliverables:
*Within the next (timeframe)*
*Anurag will watch the webinars by Thursday and finish the onboarding checklist.

Name | Assigned To | Deadline | Notes
------|-------------|----------|------
Name | @ | May 20th | Explanation
34 changes: 34 additions & 0 deletions meetings/one-on-ones/5-13-20-Jason-onboarding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Meeting Purpose

**Lead**
Bryan Wong

**Attendees**
* Zexing(Jason) Fang

## Updates:
*What has been completed and can be checked off*

* Jason is almost done with onboarding checklist

## Discussion Points:
*Ideas, feedback, concerns, plans*
* Understand the overview of the onboarding procedure
* Breakdown of tasks and expectations for the first week
* Understand what Engineering team does
* Practice taking notes on Github during the 1:1
* Please give your overview feedback and express what position you are interested within the Engineering team!
* Give onboarding feedback
* Clear up the onboarding issue


## Action Plan:
*Where to go next, dependencies, all deadlines*
* None. Jason finished his onboarding checklist!

## Deliverables:
*Within the next (timeframe)*

Name | Assigned To | Deadline | Notes
------|-------------|----------|------
Example 1 | @studentusername2 | Feb 30th | Explanation
13 changes: 11 additions & 2 deletions meetings/weekly/frontend/5-11-20.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ Bryan
* Alex
* Tom

**Video Link**
https://ucdavis.zoom.us/rec/share/5uBtLOnM93JLe8_J4Wfaeb4zO9jYeaa80HQcrPEPmB1VRx1WiBf18WdHLAjTfhvv

## Updates:
*What has been completed and can be checked off*

Expand All @@ -30,11 +33,17 @@ Bryan

## Action Plan:
*Where to go next, dependencies, all deadlines*
* Plan1
* Mark will work on the Explore page
* Jason will work on User Dashboard
* Yuan will work on the Home page

## Deliverables:
*Within the next (timeframe)*

Name | Assigned To | Deadline | Notes
------|-------------|----------|------
Example 1 | @studentusername2 | Feb 30th | Explanation
Mark | @mzp0625 | May 20th | Integrate the explore page
Jason | @JersinFong | May 20th | Integrate the User Dashboard page
Yuan | @VelForce | May 20th | Integrate the Home page
Ayush | @ayushbha | May 20th | Integrate the Markdown Editor
Aishwarya | @aishwarya-mustoori | May 20th | Integrate Article viewer page

0 comments on commit 099da4a

Please sign in to comment.