From 338589d83ee99e9ffd70eb5fe7ea4d98a035384d Mon Sep 17 00:00:00 2001 From: cleverson Date: Tue, 30 Jan 2024 19:33:30 -0300 Subject: [PATCH] =?UTF-8?q?modifica=C3=A7=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 10 +-- README.md | 17 ----- app/__init__.py | 9 --- app/admin.py | 162 ++++++++++++++++++++++++++++++++++++++++++ app/auth.py | 133 ++++++++++++++++++++++------------ app/blog.py | 71 +++++------------- app/models.py | 84 ++++++++-------------- requirements.txt | 4 -- templates/index.html | 9 --- templates/layout.html | 9 --- 10 files changed, 300 insertions(+), 208 deletions(-) create mode 100644 app/admin.py diff --git a/.gitignore b/.gitignore index 99e03e4..0acc02d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,6 @@ -<<<<<<< HEAD __pycache__/ instance/ migrations/ flask_session/ -.venv/ -======= -__pycache__ - -instance -migrations -flask_session ->>>>>>> 78d4ede (create auth) +.venv/ \ No newline at end of file diff --git a/README.md b/README.md index f3bfc69..d1e6d9c 100644 --- a/README.md +++ b/README.md @@ -2,34 +2,17 @@ ## como rodar esse projeto -<<<<<<< HEAD -<<<<<<< HEAD -======= -======= ->>>>>>> 78d4ede (create auth) * Antes de mais nada, é indicado criar um ambiente virtual. ```sh python3 -m venv .venv ``` -<<<<<<< HEAD ->>>>>>> 78d4ede (create auth) -======= ->>>>>>> 78d4ede (create auth) ```sh export FLASK_app=app export FLASK_ENV=Development export FLASK_DEBUG=True -<<<<<<< HEAD -<<<<<<< HEAD -flask run -======= python3 -m flask run -h localhost ->>>>>>> 78d4ede (create auth) -======= -python3 -m flask run -h localhost ->>>>>>> 78d4ede (create auth) ``` ## migrate diff --git a/app/__init__.py b/app/__init__.py index 2519514..f35a8d2 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,4 +1,3 @@ -from flask import Flask from flask import Flask, render_template from flask_migrate import Migrate from flask_session import Session @@ -8,14 +7,6 @@ def create_register_blueprint(app): from .auth import auth - from .blog import blog - - app.register_blueprint(auth) - app.register_blueprint(blog) - - -def create_app(): - app = Flask(__name__, template_folder='../templates') from .admin import admin from .blog import blog diff --git a/app/admin.py b/app/admin.py new file mode 100644 index 0000000..c723657 --- /dev/null +++ b/app/admin.py @@ -0,0 +1,162 @@ +import re +from unidecode import unidecode +from uuid import uuid4 +from flask import Blueprint, request, redirect, session, render_template, flash, jsonify +from app.models import Contents, db + +admin = Blueprint('admin', __name__) + +@admin.route('/admin', methods=['GET']) +def home(): + if not session.get("token"): + return redirect('/login') + + draft_list = Contents.query.filter(Contents.status == "draft").all() + contents_list = Contents.query.filter(Contents.status == "published").all() + + return render_template('admin/home.html', draft_list=draft_list, contents_list=contents_list) + + +@admin.route('/publish', methods=['GET', 'POST']) +def publish(): + if not session.get("token"): + return redirect('/login') + + if request.method == "POST": + title, content, description = get_title_content_description() + + if data_valid(title, content): + insert_content( + title=title, + body=content, + status='published', + accessType='public', + description=description + ) + return redirect('/') + + flash("O titulo ou texto não está preenchido adequadamente! Por favor, verifique se você preencheu os campo corretamente!") + + return render_template('admin/editor.html', is_draft_mode=True) + + +@admin.route('/update/', methods=['GET', 'POST', 'PUT']) +def update(id): + if not session.get("token"): + return redirect('/login') + + if request.method == "POST": + data = request.get_json() + + title = data['title'] + body = data['body'] + description = data['description'] + + if data_valid(title, body): + update_content(id=id, title=title,body=body, description=description) + return jsonify({"status_code": 200, 'success': True}), 200 + + return jsonify({"status_code":200, "success":True, "message":"O titulo ou texto não está preenchido adequadamente! Por favor, verifique se você preencheu os campo corretamente!"}), 200 + + if request.method == 'PUT': + data = request.get_json() + + title = data['title'] + body = data['body'] + description = data['description'] + + if data_valid(title, body): + update_content(id=id, title=title,body=body, status='published', description=description) + return jsonify({"status_code": 200, 'success': True}), 200 + + if request.method == "GET": + title, body, description = obtain_draft_title_and_body(id) + return render_template('admin/editor.html', id=id, title=title, body=body, description=description, is_draft_mode=False) + + +@admin.route('/draft', methods=['POST']) +def draft(): + if request.method == "POST": + data = request.get_json() + + title = data['title'] + content = data['body'] + description = data['description'] + + if data_valid(title, content): + insert_content( + title=title, + body=content, + status='draft', + accessType='public', + description=description + ) + return jsonify({"status_code": 200, 'success': True}), 200 + + return jsonify({ + "error": { + "status_code": 400, + "message": "Os campos título e texto não foram preenchidos adequadamente. Por favor, verifique se você preencheu os campos corretamente." + } + }), 400 + + return jsonify({"status_code": 400, "erro": "Método não permitido"}), 405 + + +@admin.route('/delete/post/', methods=['DELETE']) +def delete_post(post_id): + if not session.get("token"): + return jsonify({ + "status": "error", + "message": "Você não tem permissão para deletar este post.", + "code": 403 + }), 403 + + Contents.query.filter(Contents.id == post_id).delete() + db.session.commit() + + return jsonify({"status_code":200, "success":True}), 200 + +def obtain_draft_title_and_body(id: str): + query = Contents.query.filter(Contents.id == id) + draft_data = query.first() + title, body, description = draft_data.title, draft_data.body, draft_data.description + return title, body, description + +def get_title_content_description(): + return request.form.get("title"), request.form.get("markdown-content"), request.form.get('description') + +def data_valid(title: str, content: str) -> bool: + return len(title.strip()) > 0 and len(content.strip()) > 0 + +def update_content(id:str, title: str, body: str,description:str, status:str = None) -> None: + if status is None: + Contents.query.filter_by(id=id).update({Contents.title:title, Contents.body:body, Contents.description:description}) + db.session.commit() + return + Contents.query.filter_by(id=id).update({Contents.title:title, Contents.body:body, Contents.status:status, Contents.description:description}) + db.session.commit() + +def generate_slug(title:str) -> str: + title = unidecode(title) + slug = re.sub(r'[^\w\s-]', '', title.lower()) + slug = re.sub(r'\s', '-', slug) + return slug + +def insert_content(title: str, body: str, status: str, accessType: str, description:str) -> None: + """ + status: "published" or "draft" + accessType: "public" or "private" + """ + db.session.add( + Contents( + id=str(uuid4()), + title=title, + body=body, + slug=generate_slug(title), + status=status, + accessType=accessType, + description=description + ) + ) + db.session.commit() diff --git a/app/auth.py b/app/auth.py index 8f09dc6..4863ccf 100644 --- a/app/auth.py +++ b/app/auth.py @@ -1,61 +1,106 @@ +import bcrypt from uuid import uuid4 -from flask import Blueprint, redirect, session, jsonify, render_template, request +from flask import Blueprint, redirect, session, render_template, request, flash +from sqlalchemy.sql import exists -from .models import Contents,Users, db +from app.models import Users, db - -auth = Blueprint('account', __name__) +auth = Blueprint('auth', __name__) @auth.route('/login', methods=['GET', 'POST']) def login(): - if request.method == 'POST': - USERNAME = request.form.get('username') - PASSWORD = request.form.get('password') - - query = Users.query.filter(Users.username==USERNAME, Users.password==PASSWORD) - result = query.first() + error = None + if request.method == 'POST': + username, password = get_username_and_password() + + if check_username_exist(username): + + hashpass = get_hash_password(username) + user_type = get_user_type(username) - if result: - session["token"] = uuid4() - return redirect("/") - else: - return jsonify({"message": "usuario ou senha incorreta!" }) - return render_template('login.html') + if bcrypt.checkpw(password.encode('utf-8'), hashpass): + if user_type == 'admin': + session["token"] = uuid4() + return redirect("/admin") + else: + flash("Você não tem permissão para acessar essa página!\nÉ necessário pedir permissão para o admin da página!") + else: + flash("Usuário ou senha incorretas!") + else: + flash("Usuário não existe!") + return render_template('auth/login.html', error=error) @auth.route('/logout') def logout(): - session["token"] = None - return redirect("/") + session["token"] = None + print('logout') + return redirect("/admin") @auth.route('/register', methods=['GET', 'POST']) def register(): - if request.method == 'POST': - #registrar como admin - if Users.query.count() == 0: - db.session.add( - Users( - id = str(uuid4()), - username=request.form.get('username'), - password=request.form.get('password'), - userType='admin' - ) - ) - db.session.commit() - return redirect("/login") - - else: - db.session.add( - Users( - id = str(uuid4()), - username=request.form.get('username'), - password=request.form.get('password'), - userType='user' + error = None + if request.method == 'POST': + username, password = get_username_and_password() + + # registrar como admin + if Users.query.count() == 0: + register_user( + username=username, + password=password, + user_type='admin' ) - ) - db.session.commit() - return redirect("/login") - - return render_template('register.html') \ No newline at end of file + return redirect("/login") + else: + username_exist = check_username_exist(username) + if not username_exist: + register_user( + username=username, + password=password, + user_type='user' + ) + return redirect("/login") + else: + error = "usuário já cadastrado!" + return render_template('auth/register.html', error=error) + + + +def get_hash_password(username): + hash_password = Users.query.filter_by(username=username).first().password + return hash_password + + +def get_user_type(username): + user_type = Users.query.filter_by(username=username).first().userType + return user_type + + +def check_username_exist(username): + query = Users.query.filter(Users.username == username) + result = query.first() + return result + + +def get_username_and_password(): + return request.form.get('username'), request.form.get('password') + + +def register_user(username, password, user_type): + db.session.add( + Users( + id=str(uuid4()), + username=username, + password=encrypt_password(password), + userType=user_type + ) + ) + db.session.commit() + + +def encrypt_password(password): + byte_password = password.encode('utf-8') + hash_password = bcrypt.hashpw(byte_password, bcrypt.gensalt()) + return hash_password diff --git a/app/blog.py b/app/blog.py index e0ac977..7a36104 100644 --- a/app/blog.py +++ b/app/blog.py @@ -1,64 +1,31 @@ -<<<<<<< HEAD -<<<<<<< HEAD -from flask import Blueprint, abort, jsonify, request -from .models import Contents, db import uuid +from flask import Blueprint, request, redirect, render_template, abort -bp_blog = Blueprint('blog',__name__, subdomain='blog') - - -@bp_blog.route('/', methods=['GET']) -def list_blog(): - contents = Contents.query.all() - - response = [] - for data in contents: - response.append({ - "id": data.id, - "title" : data.title, - "body": data.body - }) - return jsonify(response), 200 - +from .models import Contents, db -@bp_blog.route('/post', methods=['POST']) -def post(): - data = request.get_json() - query = Contents( - id = str(uuid.uuid4()), - title = data['title'], - body = data['body'] - ) +blog = Blueprint('blog', __name__) - db.session.add(query) - try: - db.session.commit() - except Exception as error: - print(error) - return "Error!", 400 +@blog.route('/', methods=['GET']) +def get_blog(): + contents = Contents.query.filter(Contents.status == "published").order_by(Contents.created_at.desc()).all() + return render_template('index.html', contents=contents) - return "Data entered successfully!", 201 -======= -======= ->>>>>>> 78d4ede (create auth) -import uuid -from flask import Blueprint, request, redirect, session -from .models import Contents, db +@blog.route('/', methods=['GET']) +def render_text(slug): + """ if not session.get("token"): + return redirect('/login') """ + data = Contents.query.filter(Contents.slug == slug).first() + + if data is None: + abort(404) -blog = Blueprint('blog', __name__) + title = data.title + body = data.body + date = data.created_at.strftime("%d/%m/%Y, %H:%M %p") + return render_template('blog/render_text.html', title=title, body=body, date=date) -@blog.route('/', methods=['GET']) -def get_blog(): - if not session.get("token"): - return redirect('/login') -<<<<<<< HEAD - return "HELLO world!" ->>>>>>> 78d4ede (create auth) -======= - return "HELLO world!" ->>>>>>> 78d4ede (create auth) diff --git a/app/models.py b/app/models.py index 3c1abb7..9e431bf 100644 --- a/app/models.py +++ b/app/models.py @@ -1,23 +1,12 @@ -from flask_sqlalchemy import SQLAlchemy -<<<<<<< HEAD -<<<<<<< HEAD - -db = SQLAlchemy() +from datetime import datetime -def config(app): -======= -======= ->>>>>>> 78d4ede (create auth) -from sqlalchemy import Integer, String, Column, Text, Enum +from flask_sqlalchemy import SQLAlchemy +from sqlalchemy import Integer, String, Column, Text, Enum, CheckConstraint, DateTime db = SQLAlchemy() def config_models(app) -> None: -<<<<<<< HEAD ->>>>>>> 78d4ede (create auth) -======= ->>>>>>> 78d4ede (create auth) db.init_app(app) app.db = db @@ -25,54 +14,39 @@ def config_models(app) -> None: class Contents(db.Model): __tablename__ = 'contents' -<<<<<<< HEAD -<<<<<<< HEAD - id = db.Column(db.String(36), primary_key=True, nullable=True) - title = db.Column(db.String(256), nullable=True) - body = db.Column(db.Text) - - def __init__(self, id: str, title: str, body: int) -> None: - self.id = id - self.title = title - self.body = body -======= -======= ->>>>>>> 78d4ede (create auth) - StatusEnum = Enum('draft', 'published', name='StatusEnum') - TypeEnum = Enum('public', 'private', name='TypeEnum') - - id = Column(String(36), primary_key=True, nullable=False) - title = Column(String(256), nullable=False) - body = Column(Text) - status = Column(StatusEnum, default='draft') - type = Column(TypeEnum, default='public') - - - def __init__(self, id: str, title: str, body:str, status:str, type:str) -> None: - self.id = id - self.title = title - self.body = body - self.status = status - self.type = type + id = Column(String(36), primary_key=True, nullable=False, unique=True) + title = Column(String(256), nullable=False) + body = Column(Text) + slug = Column(String(256), nullable=False, unique=True) + status = Column(String, CheckConstraint("status IN ('published', 'draft')"), default='draft') + accessType = Column(String, CheckConstraint("type IN ('public', 'private')"), default='public') + description = Column(String(1000), default='') + created_at = Column(DateTime, default=datetime.now) + updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) + + + def __init__(self, id: str, title: str, body:str, slug:str, status:str, accessType:str, description:str) -> None: + self.id = id + self.title = title + self.body = body + self.slug = slug + self.status = status + self.accessType = accessType + self.description = description class Users(db.Model): __tablename__ = 'users' - UserTypeEnum = Enum('user', 'admin', name='TypeEnum') - - id = Column(String(36), primary_key=True, nullable=False) - username = Column(String(20), nullable=False) - password = Column(String(100), nullable=False) - userType = Column(UserTypeEnum, nullable=False, default='user') + id = Column(String(36), primary_key=True, nullable=False, unique=True) + username = Column(String(50), nullable=False, unique=True) + password = Column(String(100), nullable=False) + userType = Column(String, CheckConstraint("userType IN ('admin' , 'user')"), nullable=False, default='user') + created_at = db.Column(db.DateTime, default=datetime.now) + updated_at = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now) def __init__(self, id:str, username: str, password:str, userType:str) -> None: self.id = id self.username = username self.password = password -<<<<<<< HEAD - self.userType = userType ->>>>>>> 78d4ede (create auth) -======= - self.userType = userType ->>>>>>> 78d4ede (create auth) + self.userType = userType \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 7bc3797..eb71f25 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,6 @@ FLASK >= 3.0.0 Flask-SQLAlchemy >= 3.1.1 Flask-Migrate >= 4.0.5 -<<<<<<< HEAD Flask-Session >= 0.5.0 bcrypt >= 4.1.2 unidecode >= 1.3.8 -======= -Flask-Session >= 0.5.0 ->>>>>>> 78d4ede (create auth) diff --git a/templates/index.html b/templates/index.html index a03575a..4e10278 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,7 +1,6 @@ {% extends "layout.html" %} {% block y %} -<<<<<<< HEAD -======= - - {% if session.name %} - You are Register {{ session.name }} logout. - {% else %} - You are not Register. login. - {% endif %} ->>>>>>> 78d4ede (create auth) {% endblock %} \ No newline at end of file diff --git a/templates/layout.html b/templates/layout.html index e9eb887..86868e2 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -2,7 +2,6 @@ -<<<<<<< HEAD this_is_cleverson_blog @@ -24,12 +23,4 @@ -======= - - flask - - - {% block y %}{% endblock %} - ->>>>>>> 78d4ede (create auth) \ No newline at end of file