Skip to content

Commit cca99c8

Browse files
committed
friends added
1 parent 53700cc commit cca99c8

18 files changed

+239
-16
lines changed

__pycache__/app.cpython-312.pyc

2.64 KB
Binary file not shown.

__pycache__/models.cpython-312.pyc

1.67 KB
Binary file not shown.

app.py

+60-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from flask import request, redirect, session, render_template, url_for, flash
1+
from flask import request, redirect, session, render_template, url_for, flash, make_response, jsonify
22
import bcrypt
33
from config import db, app
4-
from models import Blog, User, EnumRole
4+
from models import Blog, User, Friend, EnumRole
55
from werkzeug.exceptions import NotFound, Unauthorized, BadRequest, Conflict, InternalServerError
66
import cloudinary.uploader
77
from helpers import inject_user_data
@@ -205,6 +205,7 @@ def user_settings_page(username):
205205
user.username = request.form["username"]
206206
user.email = request.form["email"]
207207
user.profile_img = request.files["profile_img"]
208+
user.bio = request.form["bio"]
208209
db.session.commit()
209210
return redirect(url_for("user_page", username=user.username))
210211
elif request.method == "GET":
@@ -215,18 +216,44 @@ def user_settings_page(username):
215216
@inject_user_data
216217
def user_friends_page(username):
217218
if "user_id" in session:
218-
user = User.query.filter_by(username=username).first()
219+
user = User.query.get(session["user_id"])
220+
friend = User.query.filter_by(username=username).first()
219221
else:
220222
return redirect(url_for("login"))
221223

222224
if request.method == "POST":
223-
friend_username = request.form["friend_username"]
224-
friend = User.query.filter_by(username=friend_username).first()
225-
user.friends.append(friend)
226-
db.session.commit()
225+
friends = Friend.query.filter_by(user_id=user.id, friend_id=friend.id).all()
226+
227+
if friends:
228+
return InternalServerError(description="Friendship already exists", response=redirect(url_for("user_friends_page", username=user.username)))
229+
else:
230+
new_friend = Friend(user_id=user.id, friend_id=friend.id)
231+
232+
try:
233+
db.session.add(new_friend)
234+
db.session.commit()
235+
except Exception as e:
236+
print(str(e))
237+
return InternalServerError(description="Something went wrong", response=redirect(url_for("user_friends_page", username=user.username)))
227238
return redirect(url_for("user_friends_page", username=user.username))
228239
elif request.method == "GET":
229-
return render_template("user_page/friends.html", user=user)
240+
friends = Friend.query.filter_by(user_id=user.id).all()
241+
users = [User.query.get(friend.friend_id) for friend in friends]
242+
friends_list = [user.serialize() for user in users]
243+
return render_template("user_page/friends.html", user=user, friends=friends_list)
244+
245+
246+
@app.route("/search/user/<string:username>", methods=["GET"])
247+
def search_page(username):
248+
if request.method == "GET":
249+
found_users = User.query.filter_by(username=username).first() # Fetch the user, if any
250+
251+
if found_users:
252+
return make_response(jsonify(found_users.serialize()), 200, {"Content-Type": "application/json"})
253+
else:
254+
return make_response(jsonify({"message": "User not found."}), 404) # Handle not found case
255+
else:
256+
return redirect(url_for("home_page"))
230257

231258

232259
@app.route("/not-found")
@@ -235,6 +262,31 @@ def not_found_page():
235262
return render_template("not_found_page/index.html")
236263

237264

265+
@app.errorhandler(NotFound)
266+
def page_not_found(e):
267+
return redirect(url_for("not_found_page"))
268+
269+
270+
@app.errorhandler(Unauthorized)
271+
def unauthorized(e):
272+
return redirect(url_for("login"))
273+
274+
275+
@app.errorhandler(BadRequest)
276+
def bad_request(e):
277+
return redirect(url_for("sign_up"))
278+
279+
280+
@app.errorhandler(Conflict)
281+
def conflict(e):
282+
return redirect(url_for("sign_up"))
283+
284+
285+
@app.errorhandler(InternalServerError)
286+
def internal_server_error(e):
287+
return redirect(url_for("home_page"))
288+
289+
238290
if __name__ == '__main__':
239291
with app.app_context():
240292
db.create_all()

instance/app.db

4 KB
Binary file not shown.
0 Bytes
Binary file not shown.

migrations/versions/288edd42bc6c_.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""empty message
2+
3+
Revision ID: 288edd42bc6c
4+
Revises: e09503250453
5+
Create Date: 2024-03-31 10:11:54.917785
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = '288edd42bc6c'
14+
down_revision = 'e09503250453'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
with op.batch_alter_table('users', schema=None) as batch_op:
22+
batch_op.add_column(sa.Column('bio', sa.Text(), nullable=True))
23+
24+
# ### end Alembic commands ###
25+
26+
27+
def downgrade():
28+
# ### commands auto generated by Alembic - please adjust! ###
29+
with op.batch_alter_table('users', schema=None) as batch_op:
30+
batch_op.drop_column('bio')
31+
32+
# ### end Alembic commands ###

migrations/versions/0219db2fb723_.py migrations/versions/558fe02535c6_.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
"""empty message
22
3-
Revision ID: 0219db2fb723
3+
Revision ID: 558fe02535c6
44
Revises:
5-
Create Date: 2024-03-30 22:28:22.422436
5+
Create Date: 2024-03-31 10:07:58.341777
66
77
"""
88
from alembic import op
99
import sqlalchemy as sa
1010

1111

1212
# revision identifiers, used by Alembic.
13-
revision = '0219db2fb723'
13+
revision = '558fe02535c6'
1414
down_revision = None
1515
branch_labels = None
1616
depends_on = None
@@ -41,11 +41,21 @@ def upgrade():
4141
sa.ForeignKeyConstraint(['user_id'], ['users.id'], name=op.f('fk_blogs_user_id_users')),
4242
sa.PrimaryKeyConstraint('id')
4343
)
44+
op.create_table('friends',
45+
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
46+
sa.Column('user_id', sa.Integer(), nullable=False),
47+
sa.Column('friend_id', sa.Integer(), nullable=False),
48+
sa.Column('created_at', sa.DateTime(), nullable=True),
49+
sa.ForeignKeyConstraint(['friend_id'], ['users.id'], name=op.f('fk_friends_friend_id_users')),
50+
sa.ForeignKeyConstraint(['user_id'], ['users.id'], name=op.f('fk_friends_user_id_users')),
51+
sa.PrimaryKeyConstraint('id')
52+
)
4453
# ### end Alembic commands ###
4554

4655

4756
def downgrade():
4857
# ### commands auto generated by Alembic - please adjust! ###
58+
op.drop_table('friends')
4959
op.drop_table('blogs')
5060
op.drop_table('users')
5161
# ### end Alembic commands ###
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

migrations/versions/e09503250453_.py

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""empty message
2+
3+
Revision ID: e09503250453
4+
Revises: 558fe02535c6
5+
Create Date: 2024-03-31 10:09:24.272860
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = 'e09503250453'
14+
down_revision = '558fe02535c6'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
pass
21+
22+
23+
def downgrade():
24+
pass

models.py

+47-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,26 @@ class EnumRole:
99
USER = "user"
1010

1111

12+
class Friend(db.Model):
13+
__tablename__ = "friends"
14+
15+
id = Column(Integer, primary_key=True, autoincrement=True)
16+
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
17+
friend_id = Column(Integer, ForeignKey("users.id"), nullable=False)
18+
created_at = Column(DateTime, default=datetime.utcnow)
19+
20+
def __repr__(self):
21+
return "<Friend %r>" % self.id
22+
23+
def serialize(self):
24+
return {
25+
"id": self.id,
26+
"user_id": self.user_id,
27+
"friend_id": self.friend_id,
28+
"created_at": self.created_at
29+
}
30+
31+
1232
class User(db.Model):
1333
__tablename__ = "users"
1434

@@ -20,11 +40,25 @@ class User(db.Model):
2040
created_at = Column(DateTime(timezone=True), server_default=func.now())
2141
role = Column(Enum(EnumRole.ADMIN, EnumRole.USER), default=EnumRole.USER)
2242
profile_img = Column(String(255), default="default.jpg")
23-
friends = db.relationship("User", secondary="friends", primaryjoin=id == "friends.c.user_id", secondaryjoin=id == "friends.c.friend_id")
43+
friends = db.relationship("Friend", backref="user", foreign_keys=[Friend.user_id])
44+
bio = Column(Text, nullable=True)
2445

2546
def __repr__(self):
2647
return "<User %r>" % self.id
2748

49+
def serialize(self):
50+
return {
51+
"id": self.id,
52+
"username": self.username,
53+
"email": self.email,
54+
"profile_img": self.profile_img,
55+
"role": self.role,
56+
"created_at": self.created_at,
57+
"bio": self.bio,
58+
"friends": self.friends,
59+
"blogs": self.blogs
60+
}
61+
2862

2963
class Blog(db.Model):
3064
__tablename__ = "blogs"
@@ -40,3 +74,15 @@ class Blog(db.Model):
4074

4175
def __repr__(self):
4276
return "<BlogPost %r>" % self.id
77+
78+
def serialize(self):
79+
return {
80+
"id": self.id,
81+
"title": self.title,
82+
"author_name": self.author_name,
83+
"subtitle": self.subtitle,
84+
"text": self.text,
85+
"created_at": self.created_at,
86+
"blog_img": self.blog_img,
87+
"user_id": self.user_id
88+
}

static/js/friend.js

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
let searchInput = document.getElementById("search-friend");
2+
const searchResults = document.getElementById("results");
3+
4+
document.addEventListener("keypress", async function (e) {
5+
if (e.key === "Enter") {
6+
const search = searchInput.value;
7+
if (search.length > 0) {
8+
try {
9+
const response = await fetch(
10+
`http://127.0.0.1:5000/search/user/${search}`,
11+
);
12+
const results = await response.json();
13+
searchResults.innerHTML = "";
14+
searchResults.innerHTML = "";
15+
searchResults.innerHTML += `
16+
<div class="search-result">
17+
<img src="${results.profile_img}" alt="avatar" />
18+
<p>${results.username}</p>
19+
<button class="button is-link" onclick="addFriends('${results.username}')">Add to friends</button>
20+
</div>
21+
`;
22+
} catch (error) {
23+
console.error(error);
24+
}
25+
}
26+
}
27+
});
28+
29+
async function addFriends(username) {
30+
console.log(username);
31+
try {
32+
const response = await fetch(
33+
`http://127.0.0.1:5000/user/${username}/friends`,
34+
{
35+
method: "POST",
36+
},
37+
);
38+
39+
if (response.status === 200) {
40+
window.location.assign("/friends");
41+
} else {
42+
window.location.assign("/");
43+
}
44+
} catch (error) {
45+
console.error(error);
46+
}
47+
}

static/js/main.js

Whitespace-only changes.

templates/layout/layout.html

-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@
9494

9595
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
9696
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
97-
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
9897
{% block js %} {% endblock %}
9998
</body>
10099
</html>

templates/user_page/friends.html

+5-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ <h1 class="title">Friends</h1>
77
<div class="column is-one-third">
88
<h3 class="title is-3">Your Friends</h3>
99
<ul class="friend-list">
10-
{% if user.friends|length > 0 %} {% for friend in user.friends %}
10+
{% if friends|length > 0 %} {% for friend in friends %}
1111
<li class="box">
1212
<figure class="image is-48x48">
1313
<img
@@ -16,7 +16,7 @@ <h3 class="title is-3">Your Friends</h3>
1616
/>
1717
</figure>
1818
<div class="content">
19-
<a href="/user/{{ friend.username }}">Friend Name</a>
19+
<a href="/user/{{ friend.username }}">{{ friend.username }}</a>
2020
</div>
2121
</li>
2222
{% endfor %} {% else %}
@@ -40,11 +40,13 @@ <h3 class="title is-3">Your Friends</h3>
4040
</span>
4141
</div>
4242
</div>
43-
<div class="results">
43+
<div id="results" class="results">
4444
<p>No results found yet.</p>
4545
</div>
4646
</div>
4747
</div>
4848
</div>
4949
</section>
50+
{% endblock %} {% block js %}
51+
<script src="{{ url_for("static", filename="./js/friend.js") }}"></script>
5052
{% endblock %}

templates/user_page/settings.html

+11
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ <h1 class="title">Settings</h1>
4040
/>
4141
</div>
4242
</div>
43+
<div class="field">
44+
<label class="label" for="bio">BIO</label>
45+
<div class="control">
46+
<textarea
47+
name="bio"
48+
id="bio"
49+
class="textarea is-info"
50+
placeholder="Add bio here…"
51+
></textarea>
52+
</div>
53+
</div>
4354
<hr />
4455
<button type="submit" class="button is-primary">Save Changes</button>
4556
</form>

0 commit comments

Comments
 (0)