Skip to content

Commit 099da4a

Browse files
authored
Implemented Tags (#29)
* 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
1 parent c6ac0f0 commit 099da4a

File tree

9 files changed

+295
-3
lines changed

9 files changed

+295
-3
lines changed

api/backend/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
app = Flask(__name__)
1111

12+
1213
app.config['GITHUB_CLIENT_ID'] = GITHUB_CLIENT_ID
1314
app.config['GITHUB_CLIENT_SECRET'] = GITHUB_CLIENT_SECRET
1415
app.config["PROPAGATE_EXCEPTIONS"] = True
@@ -27,8 +28,10 @@
2728
from ..backend.home.routes import home_bp
2829
from ..backend.meta.routes import meta_bp
2930
from ..backend.users.routes import user_bp
31+
from ..backend.tags.routes import tag_bp
3032

3133
app.register_blueprint(authentication_bp)
3234
app.register_blueprint(home_bp)
3335
app.register_blueprint(meta_bp)
3436
app.register_blueprint(user_bp)
37+
app.register_blueprint(tag_bp)

api/backend/models.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
from api.backend import db
22

33

4+
# A many to many relationship to keep track of tags and users
5+
user_tag_rel = db.Table("user_tag_rel",
6+
db.Column("user_id", db.Integer, db.ForeignKey("user.id"), primary_key=True),
7+
db.Column("tag_id", db.Integer, db.ForeignKey("tag.id"), primary_key=True)
8+
)
9+
10+
411
class Meta(db.Model):
512
id = db.Column(db.Integer, primary_key=True)
613
roles = db.Column(db.Text, nullable=True)
@@ -9,6 +16,7 @@ class Meta(db.Model):
916
student = db.relationship("Student", uselist=False, cascade="all,delete", back_populates="meta")
1017
teacher = db.relationship("Teacher", uselist=False, cascade="all,delete", back_populates="meta")
1118

19+
1220
def __repr__(self):
1321
return f"Meta('{self.id}')"
1422

@@ -24,7 +32,9 @@ class User(db.Model):
2432
image = db.Column(db.Text, nullable=True)
2533
meta_id = db.Column(db.Integer, db.ForeignKey('meta.id'))
2634
meta = db.relationship("Meta", back_populates="user")
27-
35+
tags = db.relationship("Tag", secondary="user_tag_rel",
36+
back_populates="users")
37+
2838
def __repr__(self):
2939
return f"User('{self.email}')"
3040

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

5565
def __repr__(self):
5666
return f"Teacher('{self.id}')"
67+
68+
69+
class Tag(db.Model):
70+
id = db.Column(db.Integer, primary_key=True, nullable=False)
71+
name = db.Column(db.Text, nullable=False)
72+
summary = db.Column(db.Text, nullable=False)
73+
submission_guideline = db.Column(db.Text, nullable=False)
74+
about = db.Column(db.Text, nullable=False)
75+
emoji = db.Column(db.Text, nullable=False)
76+
users = db.relationship("User", secondary="user_tag_rel",
77+
back_populates="tags")
78+
79+
def __repr__(self):
80+
return f"Tag('{self.id} , {self.name}')"

api/backend/tags/decorators.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from ..models import Tag
2+
from functools import wraps
3+
from ..tags.schemas import tag_form_schema
4+
from flask import request
5+
6+
7+
# Decorator to check if a tag exists
8+
def tag_exists(f):
9+
10+
@wraps(f)
11+
def wrap(*args, **kwargs):
12+
tag = Tag.query.get(kwargs['tag_id'])
13+
14+
if tag:
15+
return f(*args, **kwargs)
16+
else:
17+
return {
18+
"message": "Tag does not exist"
19+
}, 404
20+
21+
return wrap
22+
23+
24+
# Decorator to check if data in form is valid
25+
def validate_tag_form(f):
26+
27+
@wraps(f)
28+
def wrap(*args, **kwargs):
29+
form_data = request.get_json()
30+
errors = tag_form_schema.validate(form_data)
31+
32+
if errors:
33+
return {
34+
"message": "Unable to create tag. Please enter all required form inputs."
35+
}, 422
36+
else:
37+
return f(*args, **kwargs)
38+
39+
return wrap

api/backend/tags/routes.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
from .. import api, db
2+
from ..models import Tag, User
3+
from ..tags.decorators import tag_exists, validate_tag_form
4+
from ..tags.schemas import tag_schema, tags_schema, tag_form_schema
5+
from ..tags.utils import create_tag, update_tag
6+
from flask import Blueprint, request, session
7+
from flask_restful import Resource
8+
9+
# Blueprint for tags
10+
tag_bp = Blueprint("tags", __name__)
11+
12+
13+
# Class to fetch and create tag
14+
class Tags(Resource):
15+
# Create Tag
16+
@validate_tag_form
17+
def post(self):
18+
form_data = request.get_json()
19+
tag = create_tag(form_data)
20+
21+
db.session.add(tag)
22+
db.session.commit()
23+
24+
return {
25+
"message": "Tag sucessfully created"
26+
}, 201
27+
28+
29+
# Fetch Tags
30+
def get(self):
31+
tag = Tag.query.limit(15).all()
32+
33+
if len(tag) != 0:
34+
return tags_schema.dump(tag)
35+
else:
36+
return {
37+
"message": "No Tags"
38+
}, 404
39+
40+
41+
# Class for updating, deleting & fetching tags
42+
class TagCRUD(Resource):
43+
# Update specific tag
44+
@validate_tag_form
45+
@tag_exists
46+
def put(self, tag_id):
47+
tag = Tag.query.get(tag_id)
48+
form_data = request.get_json()
49+
update_tag(tag, form_data)
50+
51+
db.session.commit()
52+
53+
return {
54+
"message": "Tag successfully updated"
55+
}, 200
56+
57+
# Fetch specific tag
58+
@tag_exists
59+
def get(self, tag_id):
60+
tag = Tag.query.get(tag_id)
61+
62+
return tag_schema.dump(tag)
63+
64+
# Delete specific tag
65+
@tag_exists
66+
def delete(self, tag_id):
67+
tag = Tag.query.get(tag_id)
68+
69+
db.session.delete(tag)
70+
db.session.commit()
71+
72+
return {
73+
"message": "Tag successfully deleted"
74+
}, 200
75+
76+
77+
# Class to update followers
78+
class TagFollowers(Resource):
79+
def put(self, tag_id):
80+
user_data = session["profile"]
81+
user = User.query.get(user_data["user_id"])
82+
tag = Tag.query.get(tag_id)
83+
84+
tag.users.append(user)
85+
db.session.commit()
86+
87+
return {
88+
"message": user.name + "is now following" + tag.name
89+
}, 200
90+
91+
92+
# # Creates the routes for the classes
93+
api.add_resource(Tags, "/api/tags")
94+
api.add_resource(TagCRUD, "/api/tags/<int:tag_id>")
95+
api.add_resource(TagFollowers, "/api/tags/<int:tag_id>/followers")

api/backend/tags/schemas.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from marshmallow import Schema, fields
2+
import toastedmarshmallow
3+
4+
5+
# Validates tag form
6+
class TagFormSchema(Schema):
7+
name = fields.Str(required=True)
8+
summary = fields.Str(required=True)
9+
submission_guideline = fields.Str(required=True)
10+
about = fields.Str(required=True)
11+
emoji = fields.Str(required=True)
12+
13+
class Meta:
14+
# Fields to show when sending data
15+
fields = ("name", "summary", "submission_guideline", "about", "emoji")
16+
ordered = True
17+
18+
19+
class TagSchema(Schema):
20+
id = fields.Int(required=True)
21+
22+
23+
tag_form_schema = TagFormSchema()
24+
tag_schema = TagSchema()
25+
tags_schema = TagSchema(many=True)
26+
tag_form_schema.jit = toastedmarshmallow.Jit
27+
tag_schema.jit = toastedmarshmallow.Jit
28+
tags_schema.jit = toastedmarshmallow.Jit

api/backend/tags/utils.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from ..models import Tag
2+
3+
4+
# Function to create a tag
5+
def create_tag(form_data):
6+
tag = Tag(name=form_data["name"],
7+
summary=form_data["summary"],
8+
submission_guideline=form_data["submission_guideline"],
9+
about=form_data["about"],
10+
emoji=form_data["emoji"]
11+
)
12+
13+
return tag
14+
15+
16+
# Function to update a tag
17+
def update_tag(tag, form_data):
18+
tag.name = form_data["name"]
19+
tag.summary = form_data["summary"]
20+
tag.submission_guideline = form_data["submission_guideline"]
21+
tag.about = form_data["about"]
22+
tag.emoji = form_data["emoji"]
23+
24+
return
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Meeting Purpose
2+
Weekly meeting
3+
4+
**Lead**
5+
Bryan
6+
7+
**Attendees**
8+
* Anurag
9+
10+
## Updates:
11+
*What has been completed and can be checked off*
12+
13+
*
14+
15+
## Discussion Points:
16+
*Ideas, feedback, concerns, plans*
17+
* Understand the overview of the onboarding procedure
18+
* Breakdown of tasks and expectations for the first week
19+
* Understand what Engineering team does
20+
Practice taking notes on Github during the 1:1
21+
* Please give your overview feedback and express what position you are within the Engineering team!
22+
* Give onboarding feedback
23+
*
24+
25+
## Action Plan:
26+
*Where to go next, dependencies, all deadlines*
27+
*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.
28+
*Watch the remaining webinars and close this issue.
29+
30+
## Deliverables:
31+
*Within the next (timeframe)*
32+
*Anurag will watch the webinars by Thursday and finish the onboarding checklist.
33+
34+
Name | Assigned To | Deadline | Notes
35+
------|-------------|----------|------
36+
Name | @ | May 20th | Explanation
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Meeting Purpose
2+
3+
**Lead**
4+
Bryan Wong
5+
6+
**Attendees**
7+
* Zexing(Jason) Fang
8+
9+
## Updates:
10+
*What has been completed and can be checked off*
11+
12+
* Jason is almost done with onboarding checklist
13+
14+
## Discussion Points:
15+
*Ideas, feedback, concerns, plans*
16+
* Understand the overview of the onboarding procedure
17+
* Breakdown of tasks and expectations for the first week
18+
* Understand what Engineering team does
19+
* Practice taking notes on Github during the 1:1
20+
* Please give your overview feedback and express what position you are interested within the Engineering team!
21+
* Give onboarding feedback
22+
* Clear up the onboarding issue
23+
24+
25+
## Action Plan:
26+
*Where to go next, dependencies, all deadlines*
27+
* None. Jason finished his onboarding checklist!
28+
29+
## Deliverables:
30+
*Within the next (timeframe)*
31+
32+
Name | Assigned To | Deadline | Notes
33+
------|-------------|----------|------
34+
Example 1 | @studentusername2 | Feb 30th | Explanation

meetings/weekly/frontend/5-11-20.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ Bryan
1414
* Alex
1515
* Tom
1616

17+
**Video Link**
18+
https://ucdavis.zoom.us/rec/share/5uBtLOnM93JLe8_J4Wfaeb4zO9jYeaa80HQcrPEPmB1VRx1WiBf18WdHLAjTfhvv
19+
1720
## Updates:
1821
*What has been completed and can be checked off*
1922

@@ -30,11 +33,17 @@ Bryan
3033

3134
## Action Plan:
3235
*Where to go next, dependencies, all deadlines*
33-
* Plan1
36+
* Mark will work on the Explore page
37+
* Jason will work on User Dashboard
38+
* Yuan will work on the Home page
3439

3540
## Deliverables:
3641
*Within the next (timeframe)*
3742

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

0 commit comments

Comments
 (0)