├── .gitignore ├── __pycache__ └── main.cpython-38.pyc ├── main.py ├── requirements.txt ├── static └── style.css ├── tema_sql.zip └── templates ├── base.html ├── category.html ├── index.html ├── login.html ├── new-post.html ├── not-found.html ├── post.html └── register.html /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /__pycache__/main.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tayfunerbilen/python-blog/994b12d55d2d4ac84009da934be3799ba7d39204/__pycache__/main.cpython-38.pyc -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | import mysql.connector 3 | import timeago 4 | import hashlib 5 | from slugify import slugify 6 | from flask import Flask, url_for, render_template, redirect, request, session 7 | 8 | db = mysql.connector.connect( 9 | host="localhost", 10 | user="root", 11 | password="root", 12 | database="python" 13 | ) 14 | 15 | cursor = db.cursor(dictionary=True) 16 | 17 | app = Flask(__name__) 18 | app.secret_key = b'_5#y2L"F4Q8z\n\xec]/' 19 | 20 | 21 | def md5(string): 22 | return hashlib.md5(string.encode()).hexdigest() 23 | 24 | 25 | def categories(): 26 | sql = "SELECT * FROM categories ORDER BY category_name ASC" 27 | cursor.execute(sql) 28 | cats = cursor.fetchall() 29 | return cats 30 | 31 | 32 | def hasPost(url): 33 | sql = "SELECT post_id FROM posts WHERE post_url = %s" 34 | cursor.execute(sql, (url,)) 35 | post = cursor.fetchone() 36 | return post 37 | 38 | 39 | def hasUser(email): 40 | sql = "SELECT user_id FROM users WHERE user_email = %s" 41 | cursor.execute(sql, (email,)) 42 | post = cursor.fetchone() 43 | return post 44 | 45 | 46 | def timeAgo(date): 47 | return timeago.format(date, datetime.now(), 'tr') 48 | 49 | 50 | app.jinja_env.globals.update(categories=categories) 51 | app.jinja_env.filters['timeAgo'] = timeAgo 52 | 53 | 54 | @app.route('/') 55 | def home(): 56 | sql = "SELECT * FROM posts " \ 57 | "INNER JOIN users ON users.user_id = posts.post_user_id " \ 58 | "INNER JOIN categories ON categories.category_id = posts.post_category_id " \ 59 | "ORDER BY post_id DESC" 60 | cursor.execute(sql) 61 | posts = cursor.fetchall() 62 | return render_template('index.html', posts=posts) 63 | 64 | 65 | @app.route('/category/') 66 | def category(url): 67 | cursor.execute("SELECT * FROM categories WHERE category_url = %s", (url,)) 68 | cat = cursor.fetchone() 69 | 70 | if cat: 71 | sql = "SELECT * FROM posts " \ 72 | "INNER JOIN users ON users.user_id = posts.post_user_id " \ 73 | "INNER JOIN categories ON categories.category_id = posts.post_category_id " \ 74 | "WHERE post_category_id = %s " \ 75 | "ORDER BY post_id DESC" 76 | cursor.execute(sql, (cat['category_id'],)) 77 | posts = cursor.fetchall() 78 | return render_template('category.html', category=cat, posts=posts) 79 | else: 80 | return redirect(url_for('home')) 81 | 82 | 83 | @app.route('/login', methods=['GET', 'POST']) 84 | def login(): 85 | if 'user_id' in session: 86 | return redirect(url_for('home')) 87 | 88 | error = '' 89 | if request.method == 'POST': 90 | if request.form['email'] == '': 91 | error = 'E-posta adresinizi belirtin.' 92 | elif request.form['password'] == '': 93 | error = 'Şifrenizi belirtin.' 94 | else: 95 | sql = "SELECT * FROM users WHERE user_email = %s && user_password = %s" 96 | cursor.execute(sql, (request.form['email'], md5(request.form['password']),)) 97 | user = cursor.fetchone() 98 | if user: 99 | session['user_id'] = user['user_id'] 100 | return redirect(url_for('home')) 101 | else: 102 | error = 'Girdiğiniz bilgilere ait kullanıcı bulunamadı.' 103 | 104 | return render_template('login.html', error=error) 105 | 106 | 107 | @app.route('/register', methods=['GET', 'POST']) 108 | def register(): 109 | error = '' 110 | if request.method == 'POST': 111 | if request.form['username'] == '': 112 | error = 'Adınızı ve soyadınız belirtin' 113 | elif request.form['email'] == '': 114 | error = 'E-posta adresinizi belirtin' 115 | elif request.form['password'] == '' or request.form['re_password'] == '': 116 | error = 'Şifrenizi belirtin.' 117 | elif request.form['password'] != request.form['re_password']: 118 | error = 'Girdiğiniz şifreler birbiriyle uyuşmuyor' 119 | elif hasUser(request.form['email']): 120 | error = 'Bu e-posta ile birisi zaten kayıtlı, başka bir tane deneyin' 121 | else: 122 | sql = "INSERT INTO users SET user_name = %s, user_email = %s, user_password = %s" 123 | cursor.execute(sql, (request.form['username'], request.form['email'], md5(request.form['password']))) 124 | db.commit() 125 | if cursor.rowcount: 126 | session['user_id'] = cursor.lastrowid 127 | return redirect(url_for('home')) 128 | else: 129 | error = 'Teknik bir problemden dolayı kaydınız oluşturulamadı' 130 | 131 | return render_template('register.html', error=error) 132 | 133 | 134 | @app.route('/logout') 135 | def logout(): 136 | session.clear() 137 | return redirect(url_for('home')) 138 | 139 | 140 | @app.route('/post/') 141 | def post(url): 142 | sql = "SELECT * FROM posts " \ 143 | "INNER JOIN users ON users.user_id = posts.post_user_id " \ 144 | "INNER JOIN categories ON categories.category_id = posts.post_category_id " \ 145 | "WHERE post_url = %s" 146 | cursor.execute(sql, (url,)) 147 | post = cursor.fetchone() 148 | if post: 149 | return render_template('post.html', post=post) 150 | else: 151 | return redirect(url_for('home')) 152 | 153 | 154 | @app.route('/new-post', methods=['GET', 'POST']) 155 | def newPost(): 156 | error = '' 157 | if request.method == 'POST': 158 | if request.form['title'] == '': 159 | error = 'Makale başlığını belirtin' 160 | elif request.form['category_id'] == '': 161 | error = 'Makale kategorisini seçin' 162 | elif request.form['content'] == '': 163 | error = 'Makale içeriğini yazın' 164 | elif hasPost(slugify(request.form['title'])): 165 | error = 'Makale zaten ekli, başka bir ad deneyin' 166 | else: 167 | sql = "INSERT INTO posts SET post_title = %s, post_url = %s, post_content = %s, post_user_id = %s, post_category_id = %s" 168 | cursor.execute(sql, ( 169 | request.form['title'], slugify(request.form['title']), request.form['content'], session['user_id'], 170 | request.form['category_id'],)) 171 | db.commit() 172 | if cursor.rowcount: 173 | return redirect(url_for('post', url=slugify(request.form['title']))) 174 | else: 175 | error = 'Teknik bir problemden dolayı makaleniz eklenemedi' 176 | 177 | return render_template('new-post.html', error=error) 178 | 179 | 180 | @app.errorhandler(404) 181 | def page_not_found(error): 182 | return render_template('not-found.html'), 404 183 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | click==7.1.2 2 | Flask==1.1.2 3 | itsdangerous==1.1.0 4 | Jinja2==2.11.2 5 | MarkupSafe==1.1.1 6 | mysql-connector-python==8.0.22 7 | protobuf==3.14.0 8 | python-slugify==4.0.1 9 | six==1.15.0 10 | text-unidecode==1.3 11 | timeago==1.0.14 12 | Werkzeug==1.0.1 13 | -------------------------------------------------------------------------------- /static/style.css: -------------------------------------------------------------------------------- 1 | @import "https://fonts.googleapis.com/css2?family=Mulish:wght@300;400;500;600;700;800&display=swap"; 2 | 3 | * { 4 | padding: 0; 5 | margin: 0; 6 | list-style: none; 7 | border: 0; 8 | outline: 0; 9 | line-height: 1; 10 | text-decoration: none; 11 | box-sizing: border-box; 12 | -webkit-font-smoothing: antialiased 13 | } 14 | 15 | html, body { 16 | height: 100%; 17 | font-family: "Muli", sans-serif; 18 | background: #f8f8f8 19 | } 20 | 21 | .container { 22 | width: 1200px; 23 | margin: 0 auto 24 | } 25 | 26 | .header { 27 | background: #18191a; 28 | margin-bottom: 25px 29 | } 30 | 31 | .header .container { 32 | height: 60px; 33 | display: flex; 34 | justify-content: space-between; 35 | align-items: center; 36 | padding: 0 15px 37 | } 38 | 39 | .header .container .logo { 40 | font-size: 22px; 41 | font-weight: 300; 42 | color: #fff 43 | } 44 | 45 | .header .container nav ul { 46 | display: flex 47 | } 48 | 49 | .header .container nav ul li { 50 | margin-left: 10px 51 | } 52 | 53 | .header .container nav ul li a { 54 | font-size: 16px; 55 | color: #fff; 56 | padding: 8px 15px; 57 | font-weight: 500 58 | } 59 | 60 | .header .container nav ul li.btn { 61 | padding-left: 25px; 62 | border-left: 1px solid #393a3b 63 | } 64 | 65 | .header .container nav ul li.btn a { 66 | background: #7158e2; 67 | border-radius: 5px 68 | } 69 | 70 | .main { 71 | width: 1000px 72 | } 73 | 74 | .main h3 { 75 | margin-bottom: 20px; 76 | font-size: 30px; 77 | text-align: center 78 | } 79 | 80 | .main .articles article { 81 | background: #fff; 82 | padding: 15px; 83 | margin-bottom: 15px; 84 | box-shadow: 1px 2px 4px 0 rgba(0, 0, 0, .03) 85 | } 86 | 87 | .main .articles article h4 { 88 | font-size: 20px; 89 | font-weight: bold; 90 | margin-bottom: 10px 91 | } 92 | 93 | .main .articles article ul { 94 | margin-bottom: 15px; 95 | display: flex 96 | } 97 | 98 | .main .articles article ul li { 99 | margin-right: 15px; 100 | padding-right: 15px; 101 | border-right: 1px solid #ddd 102 | } 103 | 104 | .main .articles article ul li:last-child { 105 | margin-right: 0; 106 | padding-right: 0; 107 | border: none 108 | } 109 | 110 | .main .articles article .show-btn { 111 | border: 1px solid #7158e2; 112 | display: inline-block; 113 | font-size: 16px; 114 | color: #7158e2; 115 | padding: 6px 15px; 116 | border-radius: 5px 117 | } 118 | 119 | .form { 120 | width: 500px; 121 | margin: 0 auto; 122 | background: #fff; 123 | padding: 20px; 124 | border: 1px solid #ddd 125 | } 126 | 127 | .form ul li { 128 | margin-bottom: 15px 129 | } 130 | 131 | .form ul li label { 132 | display: block; 133 | font-size: 16px; 134 | font-weight: 500; 135 | margin-bottom: 10px 136 | } 137 | 138 | .form ul li input { 139 | width: 100%; 140 | height: 40px; 141 | font-weight: bold; 142 | font-size: 18px; 143 | padding: 0 15px; 144 | border-radius: 5px; 145 | border: 1px solid #eee; 146 | color: #222 147 | } 148 | 149 | .form ul li input:focus { 150 | color: #7158e2; 151 | border-color: #7158e2 152 | } 153 | 154 | .form ul li button { 155 | width: 100%; 156 | height: 40px; 157 | border-radius: 5px; 158 | color: #fff; 159 | background: #7158e2; 160 | font-size: 16px; 161 | cursor: pointer 162 | } 163 | 164 | .form .or { 165 | display: block; 166 | text-align: center; 167 | color: #777; 168 | margin-bottom: 10px 169 | } 170 | 171 | .form .form-url { 172 | display: block; 173 | text-align: center; 174 | color: #7158e2; 175 | text-decoration: underline 176 | } 177 | 178 | .post-detail { 179 | padding: 20px; 180 | margin-top: 40px; 181 | background: #fff; 182 | box-shadow: 0 0 10px 0 rgba(0, 0, 0, .06) 183 | } 184 | 185 | .post-meta { 186 | padding-top: 20px; 187 | text-align: center 188 | } 189 | 190 | .post-meta ul { 191 | display: inline-flex 192 | } 193 | 194 | .post-meta ul li { 195 | margin-right: 25px 196 | } 197 | 198 | /*# sourceMappingURL=style.css.map */ 199 | .error { 200 | padding: 8px 10px; 201 | background: darkred; 202 | color: #fff; 203 | font-size: 15px; 204 | margin-bottom: 15px; 205 | } 206 | 207 | .form ul li select { 208 | width: 100%; 209 | height: 40px; 210 | font-weight: bold; 211 | font-size: 18px; 212 | padding: 0 15px; 213 | border-radius: 5px; 214 | border: 1px solid #eee; 215 | color: #222; 216 | appearance: none; 217 | cursor: pointer; 218 | } 219 | 220 | .form ul li textarea { 221 | width: 100%; 222 | font-weight: bold; 223 | font-size: 18px; 224 | padding: 15px; 225 | font-family: 'Muli', sans-serif; 226 | line-height: 1.6; 227 | border-radius: 5px; 228 | border: 1px solid #eee; 229 | color: #222; 230 | appearance: none; 231 | cursor: pointer; 232 | } -------------------------------------------------------------------------------- /tema_sql.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tayfunerbilen/python-blog/994b12d55d2d4ac84009da934be3799ba7d39204/tema_sql.zip -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% block title %}{% endblock %} - Prototurk 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 | 16 | 33 | 34 |
35 |
36 | 37 |
38 | {% block content %}{% endblock %} 39 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /templates/category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}{{ category['category_name'] }}{% endblock %} 3 | 4 | {% block content %} 5 |

{{ category['category_name'] }}

6 | 7 |
8 | 9 | {% for post in posts %} 10 |
11 |

{{ post['post_title'] }}

12 |
    13 |
  • {{ post['post_date']|timeAgo }}
  • 14 |
  • {{ post['user_name'] }}
  • 15 |
  • {{ post['category_name'] }}
  • 16 |
17 | Görüntüle 18 |
19 | {% endfor %} 20 | 21 |
22 | {% endblock %} -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Blog{% endblock %} 3 | 4 | {% block content %} 5 |

Son paylaştıklarım

6 | 7 |
8 | 9 | {% for post in posts %} 10 |
11 |

{{ post['post_title'] }}

12 |
    13 |
  • {{ post['post_date']|timeAgo }}
  • 14 |
  • {{ post['user_name'] }}
  • 15 |
  • {{ post['category_name'] }}
  • 16 |
17 | Görüntüle 18 |
19 | {% endfor %} 20 | 21 |
22 | {% endblock %} -------------------------------------------------------------------------------- /templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Blog{% endblock %} 3 | 4 | {% block content %} 5 |

Giriş yap

6 | 7 |
8 | 9 | {% if error %} 10 |
11 | {{ error }} 12 |
13 | {% endif %} 14 | 15 |
    16 |
  • 17 | 18 | 19 |
  • 20 |
  • 21 | 22 | 23 |
  • 24 |
  • 25 | 26 |
  • 27 |
28 | hesabın yok mu? 29 | Hemen kayıt ol! 30 |
31 | {% endblock %} -------------------------------------------------------------------------------- /templates/new-post.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Blog{% endblock %} 3 | 4 | {% block content %} 5 |

İçerik Ekle

6 | 7 |
8 | 9 | {% if error %} 10 |
11 | {{ error }} 12 |
13 | {% endif %} 14 | 15 |
    16 |
  • 17 | 18 | 19 |
  • 20 |
  • 21 | 22 | 28 |
  • 29 |
  • 30 | 31 | 32 |
  • 33 |
  • 34 | 35 |
  • 36 |
37 |
38 | {% endblock %} -------------------------------------------------------------------------------- /templates/not-found.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Blog{% endblock %} 3 | 4 | {% block content %} 5 |

Aradığın sayfa bulunamadı!

6 | {% endblock %} -------------------------------------------------------------------------------- /templates/post.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}{{ post['post_title'] }}{% endblock %} 3 | 4 | {% block content %} 5 |

{{ post['post_title'] }}

6 | 7 |
8 | {{ post['post_content']|safe }} 9 |
10 | 11 | 18 | {% endblock %} -------------------------------------------------------------------------------- /templates/register.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Blog{% endblock %} 3 | 4 | {% block content %} 5 |

Kayıt ol

6 | 7 |
8 | 9 | {% if error %} 10 |
11 | {{ error }} 12 |
13 | {% endif %} 14 | 15 |
    16 |
  • 17 | 18 | 19 |
  • 20 |
  • 21 | 22 | 23 |
  • 24 |
  • 25 | 26 | 27 |
  • 28 |
  • 29 | 30 | 31 |
  • 32 |
  • 33 | 34 |
  • 35 |
36 | hesabın var mı? 37 | Hemen giriş yap! 38 |
39 | {% endblock %} --------------------------------------------------------------------------------