forked from VictoryCTO/project-python-flask
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e1e6b03
commit 1e84225
Showing
8 changed files
with
246 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,38 @@ | ||
from app.extensions import db, bcrypt | ||
from app.extensions import db | ||
from datetime import datetime, tzinfo, timedelta | ||
|
||
|
||
class UTC(tzinfo): | ||
def utcoffset(self, dt): | ||
return timedelta(0) | ||
|
||
def tzname(self, dt): | ||
return "UTC" | ||
|
||
def dst(self, dt): | ||
return timedelta(0) | ||
|
||
|
||
def utc_now(): | ||
return datetime.now(UTC()) | ||
|
||
|
||
class User(db.Model): | ||
__tablename__ = "users" | ||
id = db.Column(db.Integer, primary_key=True) | ||
username = db.Column(db.String(80), unique=True, nullable=False) | ||
email = db.Column(db.String(120), unique=True, nullable=False) | ||
password = db.Column(db.String(128), nullable=False) | ||
active = db.Column(db.Boolean, default=False) # Issue 02-Active users | ||
|
||
def __repr__(self): | ||
return f"<User {self.username}>" | ||
|
||
|
||
class UserActiveStatusChange(db.Model): | ||
__tablename__ = "users_active_status_changes" | ||
id = db.Column(db.Integer, primary_key=True) | ||
id_user = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False) | ||
status = db.Column(db.String(10), nullable=False, default="inactive") | ||
date = db.Column(db.DateTime, default=utc_now) | ||
user = db.relationship("User", backref="status_changes") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,101 @@ | ||
from flask import Blueprint, jsonify, request | ||
from ..models import User | ||
from flask import Blueprint, Response, jsonify, request | ||
from ..models import User, UserActiveStatusChange | ||
from ..extensions import db | ||
from ..services.user_service import create_user, check_password | ||
import logging | ||
import sys | ||
import json | ||
|
||
# Configure logger to print to shell. | ||
logger = logging.getLogger("alembic.env") | ||
handler = logging.StreamHandler(sys.stdout) | ||
handler.setLevel(logging.DEBUG) | ||
formatter = logging.Formatter("%(message)s") | ||
handler.setFormatter(formatter) | ||
logger.addHandler(handler) | ||
logger.setLevel(logging.DEBUG) | ||
|
||
user_bp = Blueprint("user_bp", __name__) | ||
|
||
|
||
# Route to register a new user. | ||
@user_bp.route("/register", methods=["POST"]) | ||
def register(): | ||
data = request.get_json() | ||
username = data.get("username") | ||
email = data.get("email") | ||
password = data.get("password") | ||
|
||
# status = defaults to inactive | ||
user = create_user(username, email, password) | ||
return jsonify({"message": "User registered successfully"}), 201 | ||
return jsonify({f"message": "User " + username + " registered successfully"}), 201 | ||
|
||
|
||
# Route to log in a user. | ||
@user_bp.route("/login", methods=["POST"]) | ||
def login(): | ||
data = request.get_json() | ||
email = data.get("email") | ||
password = data.get("password") | ||
|
||
if check_password(email, password) is True: | ||
return jsonify({"message": "Login successful", "email": email}), 200 | ||
else: | ||
return jsonify({"message": "Invalid credentials"}), 401 | ||
|
||
|
||
# Dummy profile route for the user. | ||
@user_bp.route("/profile", methods=["GET"]) | ||
def profile(): | ||
# Dummy profile route for the user | ||
# In a real system, you would have authentication and user session handling | ||
return jsonify({"message": "User profile information"}), 200 | ||
|
||
|
||
# Route to hit to toggle active/inactive status of a user. | ||
@user_bp.route("/toggle-active", methods=["POST"]) | ||
def toggle_active(): | ||
data = request.get_json() | ||
email = data.get("email") | ||
user = User.query.filter_by(email=email).first() | ||
if user is None: | ||
return jsonify({"message": "User not found"}), 404 | ||
else: | ||
user.active = not user.active | ||
# Save the status change to UserActiveStatusChange table. | ||
status_change = UserActiveStatusChange( | ||
id_user=user.id, status="active" if user.active else "inactive" | ||
) | ||
db.session.commit() | ||
return jsonify({"message": f"User status toggled to {user.active}"}), 200 | ||
|
||
|
||
# Route to show all users. | ||
@user_bp.route("/users", methods=["GET"]) | ||
def users(): | ||
users = User.query.all() | ||
user_list = [] | ||
for user in users: | ||
user_list.append( | ||
{"username": user.username, "email": user.email, "active": user.active} | ||
) | ||
logger.debug(f"{user.username} | {user.email} | {user.active}") | ||
response = json.dumps(user_list) | ||
return Response(response, mimetype="application/json"), 200 | ||
|
||
|
||
# Route to delete a user. | ||
@user_bp.route("/delete-user", methods=["POST"]) | ||
def delete_user(): | ||
data = request.get_json() | ||
email = data.get("email") | ||
user = User.query.filter_by(email=email).first() | ||
if user is None: | ||
return jsonify({"message": "User not found"}), 404 | ||
else: | ||
# Delete references to user in UserActiveStatusChange table. | ||
status_changes = UserActiveStatusChange.query.filter_by(id_user=user.id).all() | ||
for status_change in status_changes: | ||
db.session.delete(status_change) | ||
# Now delete the user. | ||
db.session.delete(user) | ||
db.session.commit() | ||
logger.debug(f"{user} deleted") | ||
return jsonify({"message": "User deleted"}), 200 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
"""empty message | ||
Revision ID: 522fbb921d60 | ||
Revises: 19c3d8fa2068, f9213fe72dcc | ||
Create Date: 2024-10-15 07:12:23.368660 | ||
""" | ||
|
||
from alembic import op | ||
import sqlalchemy as sa | ||
|
||
|
||
# revision identifiers, used by Alembic. | ||
revision = "522fbb921d60" | ||
down_revision = ("19c3d8fa2068", "f9213fe72dcc") | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade(): | ||
pass | ||
|
||
|
||
def downgrade(): | ||
pass |
52 changes: 52 additions & 0 deletions
52
migrations/versions/d7cc877e7cf0_update_user_and_useractivestatuschange_.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
"""Update User and UserActiveStatusChange models | ||
Revision ID: d7cc877e7cf0 | ||
Revises: 522fbb921d60 | ||
Create Date: 2024-10-15 08:57:26.306876 | ||
""" | ||
|
||
from alembic import op | ||
import sqlalchemy as sa | ||
|
||
|
||
# revision identifiers, used by Alembic. | ||
revision = "d7cc877e7cf0" | ||
down_revision = "522fbb921d60" | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade(): | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.create_table( | ||
"users", | ||
sa.Column("id", sa.Integer(), nullable=False), | ||
sa.Column("username", sa.String(length=80), nullable=False), | ||
sa.Column("email", sa.String(length=120), nullable=False), | ||
sa.Column("password", sa.String(length=128), nullable=False), | ||
sa.Column("active", sa.Boolean(), nullable=True), | ||
sa.PrimaryKeyConstraint("id"), | ||
sa.UniqueConstraint("email"), | ||
sa.UniqueConstraint("username"), | ||
) | ||
op.create_table( | ||
"users_active_status_changes", | ||
sa.Column("id", sa.Integer(), nullable=False), | ||
sa.Column("id_user", sa.Integer(), nullable=False), | ||
sa.Column("status", sa.Boolean(), nullable=False), | ||
sa.Column("date", sa.DateTime(), nullable=True), | ||
sa.ForeignKeyConstraint( | ||
["id_user"], | ||
["users.id"], | ||
), | ||
sa.PrimaryKeyConstraint("id"), | ||
) | ||
# ### end Alembic commands ### | ||
|
||
|
||
def downgrade(): | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.drop_table("users_active_status_changes") | ||
op.drop_table("users") | ||
# ### end Alembic commands ### |
43 changes: 43 additions & 0 deletions
43
migrations/versions/dcfa167aa33c_change_status_column_from_boolean_to_.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
"""Change status column from boolean to string | ||
Revision ID: dcfa167aa33c | ||
Revises: d7cc877e7cf0 | ||
Create Date: 2024-10-15 09:32:20.240064 | ||
""" | ||
|
||
from alembic import op | ||
import sqlalchemy as sa | ||
|
||
|
||
# revision identifiers, used by Alembic. | ||
revision = "dcfa167aa33c" | ||
down_revision = "d7cc877e7cf0" | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade(): | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
with op.batch_alter_table("users_active_status_changes", schema=None) as batch_op: | ||
batch_op.alter_column( | ||
"status", | ||
existing_type=sa.BOOLEAN(), | ||
type_=sa.String(length=10), | ||
existing_nullable=False, | ||
) | ||
|
||
# ### end Alembic commands ### | ||
|
||
|
||
def downgrade(): | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
with op.batch_alter_table("users_active_status_changes", schema=None) as batch_op: | ||
batch_op.alter_column( | ||
"status", | ||
existing_type=sa.String(length=10), | ||
type_=sa.BOOLEAN(), | ||
existing_nullable=False, | ||
) | ||
|
||
# ### end Alembic commands ### |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,24 @@ | ||
import os | ||
from app import create_app | ||
from app import create_app, db | ||
from app.config import DevelopmentConfig, ProductionConfig | ||
|
||
# Set up the app | ||
config_class = ( | ||
DevelopmentConfig if os.getenv("FLASK_ENV") == "development" else ProductionConfig | ||
) | ||
app = create_app(config_class=config_class) | ||
|
||
# Import models after the app is created | ||
from app.models import User, UserActiveStatusChange | ||
|
||
if __name__ == "__main__": | ||
app.run() | ||
with app.app_context(): | ||
print("Registered tables:") | ||
for table in db.metadata.tables: | ||
print(f"- {table}") | ||
|
||
# print("\nAttempting to create tables...") | ||
# db.create_all() | ||
# print("Tables created successfully.") | ||
|
||
app.run(debug=True) |