Skip to content

Commit 1f88f0c

Browse files
committed
added env and cloudinary upload for images
1 parent 898fffb commit 1f88f0c

17 files changed

+89
-11
lines changed

.env

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
SECRET_KEY=super-secret-key
2+
DATABASE_URL=sqlite:///app.db
3+
CLOUD_NAME=dci3uqyyn
4+
API_KEY=469532533267283
5+
API_SECRET=hj-7nj65Whevxe8W4B6ATTK8Z5w
6+
CLOUDINARY_URL=cloudinary://469532533267283:hj-7nj65Whevxe8W4B6ATTK8Z5w@dci3uqyyn

.idea/.gitignore

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/dataSources.xml

+12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

__pycache__/app.cpython-312.pyc

865 Bytes
Binary file not shown.

__pycache__/config.cpython-312.pyc

420 Bytes
Binary file not shown.

__pycache__/models.cpython-312.pyc

499 Bytes
Binary file not shown.

app.py

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
from flask import request, redirect, session, render_template, url_for
1+
from flask import request, redirect, session, render_template, url_for, flash
22
import bcrypt
33
from config import db, app
44
from models import Blog, User
55
from werkzeug.exceptions import NotFound, Unauthorized, BadRequest, Conflict, InternalServerError
6+
import cloudinary.uploader
67

78

89
@app.route('/')
@@ -68,6 +69,7 @@ def sign_up():
6869
username = request.form["username"]
6970
password = request.form["password"]
7071
email = request.form["email"]
72+
profile_img = request.files["profile_img"]
7173

7274
exist_email = User.query.filter_by(email=email).first()
7375
exist_username = User.query.filter_by(username=username).first()
@@ -80,7 +82,10 @@ def sign_up():
8082

8183
hashed_pass = bcrypt.hashpw(password.encode("utf-8"), salt=bcrypt.gensalt())
8284

83-
new_user = User(username=username, password_hash=hashed_pass.decode("utf-8"), email=email)
85+
upload_result = cloudinary.uploader.upload(profile_img, folder="profile_images", resource_type="image")
86+
87+
new_user = User(username=username, password_hash=hashed_pass.decode("utf-8"), email=email, profile_img=upload_result["url"])
88+
print(new_user)
8489
db.session.add(new_user)
8590

8691
if new_user:
@@ -90,6 +95,7 @@ def sign_up():
9095
return redirect(url_for("login"))
9196
except Exception as e:
9297
print(e)
98+
flash(str(e))
9399
raise InternalServerError(description="Something went wrong", response=redirect(url_for("home_page")))
94100
else:
95101
raise InternalServerError(description="Something went wrong", response=redirect(url_for("home_page")))
@@ -103,11 +109,14 @@ def create_post():
103109
title = request.form["title"]
104110
subtitle = request.form["subtitle"]
105111
text = request.form["text"]
112+
blog_img = request.files["blog_img"]
106113

107114
if "user_id" in session:
108115
user = User.query.get(session["user_id"])
109116

110-
new_blog = Blog(title=title, subtitle=subtitle, author_name=user.username, text=text, user_id=user.id)
117+
upload_result = cloudinary.uploader.upload(blog_img, folder="blog_images", resource_type="image")
118+
119+
new_blog = Blog(title=title, subtitle=subtitle, author_name=user.username, text=text, user_id=user.id, blog_img=upload_result["url"])
111120
else:
112121
raise Unauthorized(response=redirect(url_for("login")))
113122

config.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1+
import os
12
from flask import Flask
3+
from dotenv import load_dotenv
24
from flask_cors import CORS
35
from flask_migrate import Migrate
46
from flask_sqlalchemy import SQLAlchemy
57
from sqlalchemy import MetaData
8+
import cloudinary
9+
10+
load_dotenv()
611

712
app = Flask(__name__)
8-
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
13+
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv("DATABASE_URL")
914
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
1015
app.json.compact = False
1116

@@ -17,4 +22,7 @@
1722

1823
CORS(app)
1924

20-
app.config["SECRET_KEY"] = "SUPER_SECRET_KEY_FOR_FLASK_APP"
25+
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY")
26+
27+
cloudinary.config(cloud_name = os.getenv('CLOUD_NAME'), api_key=os.getenv('API_KEY'),
28+
api_secret=os.getenv('API_SECRET'))

instance/app.db

0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

migrations/versions/d6ab6004872a_.py migrations/versions/22f064836675_.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
"""empty message
22
3-
Revision ID: d6ab6004872a
3+
Revision ID: 22f064836675
44
Revises:
5-
Create Date: 2024-03-26 14:03:33.682165
5+
Create Date: 2024-03-29 14:36:04.986299
66
77
"""
88
from alembic import op
99
import sqlalchemy as sa
1010

1111

1212
# revision identifiers, used by Alembic.
13-
revision = 'd6ab6004872a'
13+
revision = '22f064836675'
1414
down_revision = None
1515
branch_labels = None
1616
depends_on = None
@@ -24,6 +24,8 @@ def upgrade():
2424
sa.Column('email', sa.String(length=255), nullable=False),
2525
sa.Column('password_hash', sa.String(length=255), nullable=False),
2626
sa.Column('created_at', sa.DateTime(), nullable=True),
27+
sa.Column('role', sa.Enum('admin', 'user'), nullable=True),
28+
sa.Column('profile_img', sa.String(length=255), nullable=True),
2729
sa.PrimaryKeyConstraint('id'),
2830
sa.UniqueConstraint('email')
2931
)
@@ -35,6 +37,7 @@ def upgrade():
3537
sa.Column('subtitle', sa.String(length=255), nullable=False),
3638
sa.Column('text', sa.Text(), nullable=False),
3739
sa.Column('created_at', sa.DateTime(), nullable=True),
40+
sa.Column('blog_img', sa.String(length=255), nullable=True),
3841
sa.ForeignKeyConstraint(['user_id'], ['users.id'], name=op.f('fk_blogs_user_id_users')),
3942
sa.PrimaryKeyConstraint('id')
4043
)
Binary file not shown.
Binary file not shown.

models.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
from config import db
22
from datetime import datetime
3-
from sqlalchemy import Column, String, Integer, Text, DateTime, ForeignKey
3+
from sqlalchemy import Column, String, Integer, Text, DateTime, ForeignKey, Enum
4+
5+
6+
class EnumRole:
7+
ADMIN = "admin"
8+
USER = "user"
49

510

611
class User(db.Model):
@@ -12,6 +17,8 @@ class User(db.Model):
1217
password_hash = Column(String(255), nullable=False)
1318
blogs = db.relationship("Blog", backref="author")
1419
created_at = Column(DateTime, default=datetime.utcnow)
20+
role = Column(Enum(EnumRole.ADMIN, EnumRole.USER), default=EnumRole.USER)
21+
profile_img = Column(String(255), default="default.jpg")
1522

1623
def __repr__(self):
1724
return "<User %r>" % self.id
@@ -27,6 +34,7 @@ class Blog(db.Model):
2734
subtitle = Column(String(255), nullable=False)
2835
text = Column(Text, nullable=False)
2936
created_at = Column(DateTime, default=datetime.utcnow)
37+
blog_img = Column(String(255), default="default.jpg")
3038

3139
def __repr__(self):
3240
return "<BlogPost %r>" % self.id

requirements.txt

154 Bytes
Binary file not shown.

templates/auth_page/sign-up.html

+18-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,24 @@
1515
<h1 class="title is-1">Curious Caterpillar</h1>
1616
<h2 class="subtitle">Create Your Account</h2>
1717
<div class="box">
18-
<form action="/auth/sign-up" method="POST">
18+
<form
19+
action="/auth/sign-up"
20+
method="POST"
21+
enctype="multipart/form-data"
22+
>
23+
<div class="field">
24+
<label class="label" for="profile-img">Profile image</label>
25+
<div class="control">
26+
<input
27+
class="input"
28+
type="file"
29+
id="profile-img"
30+
name="profile_img"
31+
placeholder="Add profile image"
32+
required
33+
/>
34+
</div>
35+
</div>
1936
<div class="field">
2037
<label class="label" for="username">Username</label>
2138
<div class="control">

templates/blogs_page/create_post.html

+14-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,20 @@
99
<section class="section">
1010
<div class="container">
1111
<h1 class="title">Create New Post</h1>
12-
<form action="/create-post" method="POST">
12+
<form action="/create-post" method="POST" enctype="multipart/form-data">
13+
<div class="field">
14+
<label class="label" for="blog-img">Blog image</label>
15+
<div class="control">
16+
<input
17+
class="input"
18+
type="file"
19+
id="blog-img"
20+
name="blog_img"
21+
placeholder="Upload a catchy image"
22+
required
23+
/>
24+
</div>
25+
</div>
1326
<div class="field">
1427
<label class="label" for="title">Title</label>
1528
<div class="control">

0 commit comments

Comments
 (0)