Skip to content

Commit

Permalink
Issue 04-Add role entity to the model-fin
Browse files Browse the repository at this point in the history
  • Loading branch information
ScotterMonk committed Oct 15, 2024
1 parent 3b53544 commit 79c48df
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 9 deletions.
39 changes: 34 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,37 @@ We are going to make six figure bet on you. You are going to put your career in

We deeply appreciate the time you are taking to ensure joining Victory is of benefit to all concerned (yourself, Victory and our clients).

# 01 Added this comment for testing purposes.
# 02 Post-pull of action workflow to sync local with remote.
# 03 Error in workflow from Poetry version. Changed from 1.5.1 to 1.8.3.
# 04 Pyproject.toml changed significantly since poetry.lock was last generated.
# 05 04 push did not activate action.
# API calls

REGISTER
Invoke-WebRequest -Uri http://127.0.0.1:5000/register -Method POST -Headers @{"Content-Type" = "application/json"} -Body '{"username":"Dev Userson", "email":"[email protected]", "password":"sosecure"}'

Invoke-WebRequest -Uri http://127.0.0.1:5000/register -Method POST -Headers @{"Content-Type" = "application/json"} -Body '{"username":"Scott Swain", "email":"[email protected]", "password":"sosecure"}'

Invoke-WebRequest -Uri http://127.0.0.1:5000/register -Method POST -Headers @{"Content-Type" = "application/json"} -Body '{"username":"Bozo Clown", "email":"[email protected]", "password":"sosecure"}'

Invoke-WebRequest -Uri http://127.0.0.1:5000/register -Method POST -Headers @{"Content-Type" = "application/json"} -Body '{"username":"Bruce Lee", "email":"[email protected]", "password":"sosecure"}'

LOGIN
Invoke-WebRequest -Uri http://127.0.0.1:5000/login -Method POST -Headers @{"Content-Type" = "application/json"} -Body '{"email":"[email protected]", "password":"sosecure"}'

TOGGLE ACTIVE
Invoke-WebRequest -Uri http://127.0.0.1:5000/toggle-active -Method POST -Headers @{"Content-Type" = "application/json"} -Body '{"email":"[email protected]"}'

SHOW ALL USERS (deprecated to the next two calls)
Invoke-WebRequest -Uri http://127.0.0.1:5000/users -Method GET -Headers @{"Content-Type" = "application/json"}

SHOW ALL USERS with ROLES
Invoke-WebRequest -Uri http://127.0.0.1:5000/users-roles -Method GET -Headers @{"Content-Type" = "application/json"}

ACCESS REPORT
Invoke-WebRequest -Uri http://127.0.0.1:5000/access-report -Method POST -Headers @{"Content-Type" = "application/json"} -Body '{"limit_to":"all_users"}'

DELETE USER
Invoke-WebRequest -Uri http://127.0.0.1:5000/delete-user -Method POST -Headers @{"Content-Type" = "application/json"} -Body '{"email":"[email protected]"}'

CREATE ROLE(S)
Invoke-WebRequest -Uri http://127.0.0.1:5000/create-roles -Method POST -Headers @{"Content-Type" = "application/json"} -Body '{"roles_depts":["Senior Dev,Getting Started", "Dev,Getting Started"]}'

ASSIGN ROLE(S)
Invoke-WebRequest -Uri http://127.0.0.1:5000/assign-roles -Method POST -Headers @{"Content-Type" = "application/json"} -Body '{"emails_roles_depts":["[email protected],Senior Dev,Getting Started", "[email protected],Dev,Getting Started"]}'
6 changes: 3 additions & 3 deletions app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ class UserActiveStatusChange(db.Model):
user = db.relationship("User", backref="status_changes")


"""Allow for the creation of one or more roles with attributes
""" Allow for the creation of one or more roles with attributes
role_id, role_name, and department_name.
Combination of role_name and department_name is unique
Allow for a user to be assigned one or more roles
and for a role to be assigned to one or more users.
Users_roles table relies on roles_lookup
for putting a name and dept to a role id."""
for putting a name and dept to a role id. """


class User(db.Model):
Expand All @@ -55,7 +55,7 @@ def __repr__(self):
return f"<User {self.username}>"


class UserRole(db.Model):
class UsersRoles(db.Model):
__tablename__ = "users_roles"
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
Expand Down
134 changes: 133 additions & 1 deletion app/routes/user_routes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from flask import Blueprint, Response, jsonify, request
from ..models import User, UserActiveStatusChange
from ..models import User, UserActiveStatusChange, RolesLookup, UsersRoles
from ..extensions import db
from ..services.user_service import create_user, check_password
import logging
Expand All @@ -21,6 +21,7 @@
# Route to register a new user.
@user_bp.route("/register", methods=["POST"])
def register():
# Add user authentication
data = request.get_json()
username = data.get("username")
email = data.get("email")
Expand All @@ -33,6 +34,7 @@ def register():
# Route to log in a user.
@user_bp.route("/login", methods=["POST"])
def login():
# Add user authentication
data = request.get_json()
email = data.get("email")
password = data.get("password")
Expand All @@ -52,6 +54,7 @@ def profile():
# Route to hit to toggle active/inactive status of a user.
@user_bp.route("/toggle-active", methods=["POST"])
def toggle_active():
# Add user authentication
data = request.get_json()
email = data.get("email")
user = User.query.filter_by(email=email).first()
Expand All @@ -71,6 +74,7 @@ def toggle_active():
# Deprecated in favor of access-report route.
@user_bp.route("/users", methods=["GET"])
def users():
# Add user authentication
users = User.query.all()
user_list = []
for user in users:
Expand All @@ -92,6 +96,7 @@ def users():
# Route to show all users.
@user_bp.route("/access-report", methods=["POST"])
def access_report():
# Add user authentication
data = request.get_json()
limit_to = data.get("limit_to")
# limit_to may be "all_users", "active_users", or "inactive_users"
Expand Down Expand Up @@ -120,9 +125,44 @@ def access_report():
return Response(response, mimetype="application/json"), 200


# Route to show all users and their roles.
@user_bp.route("/users-roles", methods=["GET"])
def users_roles():
# Add user authentication
users = User.query.all()
user_list = []
for user in users:
id_user = user.id
# for each user, get the roles and departments using the users_roles table
roles_depts = (
db.session.query(RolesLookup.role_name, RolesLookup.department_name)
.join(UsersRoles, RolesLookup.id == UsersRoles.role_id)
.filter(UsersRoles.user_id == id_user)
.all()
)
roles_list = []
for role_dept in roles_depts:
roles_list.append(f"{role_dept[0]}/{role_dept[1]}")

user_list.append(
{
"user": user.username,
"email": user.email,
"roles": str(roles_list),
"active": user.active,
}
)
logger.debug(
f"{user.username} | {user.email} | Active: {user.active} | Roles: {str(roles_list)}"
)
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():
# Add user authentication
data = request.get_json()
email = data.get("email")
user = User.query.filter_by(email=email).first()
Expand All @@ -138,3 +178,95 @@ def delete_user():
db.session.commit()
logger.debug(f"{user} deleted")
return jsonify({"message": "User deleted"}), 200


""" Create role(s)/dept(s) in roles_lookup with attributes role_name and department_name.
Combination of role_name and department_name is unique. """


@user_bp.route("/create-roles", methods=["POST"])
def create_roles():
# Add user authentication
"""POST looks like:
Invoke-WebRequest -Uri http://127.0.0.1:5000/create-roles -Method POST -Headers @{"Content-Type" = "application/json"}
-Body '{"role_dept":"dev,accounting", "role_dept":"admin,logistics"}'"""
data = request.get_json()
# The following line is only getting the first role_dept, not all of them.
roles_depts = data.get("roles_depts") # Expecting a list of roles and departments
logger.debug(f"roles_depts={str(roles_depts)}")
# Add input validation here.
# Add error checking.
for role_dept in roles_depts:
# logger.debug(f"role_dept={str(role_dept)}")
# Chose not to use tuple unpacking below, for clarity/debugging/scalability.
role_name = role_dept.split(",")[0]
dept_name = role_dept.split(",")[1]

# Check if the role/dept combos exist and if not, add to roles_lookup
role_exists = RolesLookup.query.filter_by(
role_name=role_name, department_name=dept_name
).first()
if role_exists is None:
logger.debug(f"Role/dept {role_name}/{dept_name} combination not found")
new_role = RolesLookup(role_name=role_name, department_name=dept_name)
logger.debug(f"Role/dept {role_name}/{dept_name} combination added")
db.session.add(new_role)
db.session.commit()

return jsonify({"message": "Roles created"}), 201


""" Allow for a user to be assigned one or more roles.
This will be done by adding record(s) to the users_roles table.
Potential for this to receive a list of roles to assign to a user
or a list of users (via email) to assign role(s) to. """


@user_bp.route("/assign-roles", methods=["POST"])
def assign_roles():
"""POST looks like:
Invoke-WebRequest -Uri http://127.0.0.1:5000/assign-roles -Method POST -Headers @{"Content-Type" = "application/json"}
-Body '{"emails_roles_depts":["[email protected],dev,accounting", "[email protected],admin,logistics"]}'
"""

data = request.get_json()
emails_roles_depts = data.get(
"emails_roles_depts"
) # Expecting a list of roles and departments

if not emails_roles_depts:
return jsonify({"message": "Invalid input"}), 400

for email_role_dept in emails_roles_depts:
parts = email_role_dept.split(",")
if len(parts) != 3:
logger.debug(f"Invalid entry: {email_role_dept}")
continue

user_email, role_name, dept_name = parts

# Check if the role/dept combo exists and if not, add to roles_lookup
role_exists = RolesLookup.query.filter_by(
role_name=role_name, department_name=dept_name
).first()
if role_exists is None:
new_role = RolesLookup(role_name=role_name, department_name=dept_name)
db.session.add(new_role)
db.session.commit()
role_exists = new_role

# Assign the role to the user
user = User.query.filter_by(email=user_email).first()
if user is None:
logger.debug(f"User with email {user_email} not found")
continue

user_role_exists = UsersRoles.query.filter_by(
user_id=user.id, role_id=role_exists.id
).first()
if user_role_exists is None:
user_role = UsersRoles(user_id=user.id, role_id=role_exists.id)
db.session.add(user_role)

db.session.commit()
return jsonify({"message": "Roles assigned"}), 200

0 comments on commit 79c48df

Please sign in to comment.