Skip to content

Commit 6dc73f2

Browse files
some more changes
1 parent 010857e commit 6dc73f2

25 files changed

+1027
-121
lines changed

app/__init__.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ def create_default_admin():
2222
existing_admin = Admin.query.filter_by(username=default_username).first()
2323
if not existing_admin:
2424
admin = Admin(
25-
fname="Default",
26-
lname="Admin",
25+
fname="Admin",
26+
lname="User",
2727
username=default_username,
2828
password_hash=generate_password_hash(default_password),
2929
email=default_email
@@ -50,7 +50,7 @@ def create_app():
5050
app.config["REMEMBER_COOKIE_DURATION"] = timedelta(days=31)
5151
app.config.update(
5252
MAIL_SERVER='localhost',
53-
MAIL_PORT=1025,
53+
MAIL_PORT=2525,
5454
MAIL_USE_TLS=False,
5555
MAIL_USE_SSL=False,
5656
MAIL_USERNAME=None,
@@ -59,7 +59,7 @@ def create_app():
5959
print("Configured to use local SMTP debugging server.")
6060

6161
# Start the local SMTP debugging server
62-
smtpd_command = ['python', '-m', 'aiosmtpd', '-n', '-l', 'localhost:1025']
62+
smtpd_command = ['python', '-m', 'aiosmtpd', '-n', '-l', 'localhost:2525']
6363
subprocess.Popen(smtpd_command)
6464
print("Local SMTP debugging server started.")
6565

@@ -70,7 +70,9 @@ def create_app():
7070
from .customer import customer
7171
from .professional import professional
7272
from .auth import auth
73-
73+
from .api import api
74+
75+
app.register_blueprint(api, url_prefix='/api')
7476
app.register_blueprint(admin, url_prefix="/admin")
7577
app.register_blueprint(customer, url_prefix="/")
7678
app.register_blueprint(professional, url_prefix="/professional")

app/admin.py

+38-18
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,34 @@
1212
@login_required
1313
@role_required('admin')
1414
def admin_dashboard():
15-
customers = Customer.query.all()
16-
professionals = Professional.query.all()
15+
# Service Request Data
1716
services = Service.query.all()
18-
19-
return render_template('admin_dashboard.html', customers=customers, professionals=professionals, services=services)
17+
service_request_data = {
18+
"labels": [service.name for service in services],
19+
"data": [len(service.requests) for service in services]
20+
}
21+
22+
# Professional Performance Data
23+
professionals = Professional.query.all()
24+
professional_performance_data = {
25+
"labels": [pro.fname + " " + pro.lname for pro in professionals],
26+
"data": [round(pro.rating or 0, 2) for pro in professionals]
27+
}
28+
29+
# Customer Engagement Data
30+
customers = Customer.query.all()
31+
customer_engagement_data = {
32+
"labels": [customer.fname + " " + customer.lname for customer in customers],
33+
"data": [len(customer.requests) for customer in customers]
34+
}
35+
36+
return render_template(
37+
'admin_dashboard.html',
38+
service_request_data=service_request_data,
39+
professional_performance_data=professional_performance_data,
40+
customer_engagement_data=customer_engagement_data
41+
)
42+
2043

2144

2245
@admin.route('/admin/approve-professional/<int:professional_id>')
@@ -25,41 +48,38 @@ def admin_dashboard():
2548
def approve_professional(professional_id):
2649
try:
2750
professional = Professional.query.get(professional_id)
28-
if professional:
29-
professional.is_verified = True
51+
if professional and not professional.is_verified:
52+
professional.is_verified = True
3053
db.session.commit()
3154
flash("Professional verified successfully.", "success")
3255
else:
33-
flash("Professional not found.", "warning")
56+
flash("Professional not found or already verified.", "warning")
3457
except SQLAlchemyError:
3558
db.session.rollback()
36-
flash("An error occurred while approving the professional.", "warning")
59+
flash("An error occurred while verifying the professional.", "warning")
3760

38-
return redirect(url_for('admin_dashboard'))
61+
return redirect(url_for('admin.admin_dashboard'))
3962

4063

4164
@admin.route('/admin/block-user/<int:user_id>/<string:user_type>')
4265
@login_required
4366
@role_required('admin')
4467
def block_user(user_id, user_type):
4568
try:
46-
if user_type == 'customer':
47-
user = Customer.query.get(user_id)
48-
else:
49-
user = Professional.query.get(user_id)
50-
69+
user = Customer.query.get(user_id) if user_type == 'customer' else Professional.query.get(user_id)
5170
if user:
52-
user.is_blocked = not user.is_blocked
71+
user.is_blocked = not user.is_blocked
5372
db.session.commit()
5473
status = "unblocked" if not user.is_blocked else "blocked"
55-
flash(f"User successfully {status}.", "success")
74+
flash(f"User {status} successfully.", "success")
5675
else:
5776
flash("User not found.", "warning")
5877
except SQLAlchemyError:
5978
db.session.rollback()
60-
flash("An error occurred while updating the user.", "warning")
79+
flash("An error occurred while blocking/unblocking the user.", "warning")
6180

62-
return redirect(url_for('admin_dashboard'))
81+
return redirect(url_for('admin.admin_dashboard'))
82+
6383

6484

6585
@admin.route('/admin/create-service', methods=['GET', 'POST'])

app/api.py

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
from flask import Blueprint, jsonify, request
2+
from .models import db, Customer, Professional, Service, Request
3+
from flask_login import login_required
4+
5+
api = Blueprint('api', __name__)
6+
7+
# Get all users
8+
@api.route('/users', methods=['GET'])
9+
@login_required
10+
def get_users():
11+
users = Customer.query.all()
12+
professionals = Professional.query.all()
13+
return jsonify({
14+
"customers": [{"id": user.id, "name": f"{user.fname} {user.lname}"} for user in users],
15+
"professionals": [{"id": pro.id, "name": f"{pro.fname} {pro.lname}"} for pro in professionals]
16+
})
17+
18+
# Get all services
19+
@api.route('/services', methods=['GET'])
20+
def get_services():
21+
services = Service.query.all()
22+
return jsonify([{
23+
"id": service.id,
24+
"name": service.name,
25+
"price": service.price,
26+
"time_required": service.time_required_in_hours,
27+
"description": service.description,
28+
"provider_id": service.provider
29+
} for service in services])
30+
31+
# Create a new service
32+
@api.route('/services', methods=['POST'])
33+
@login_required
34+
def create_service():
35+
data = request.json
36+
new_service = Service(
37+
name=data['name'],
38+
price=data['price'],
39+
time_required_in_hours=data['time_required'],
40+
description=data['description'],
41+
provider=data['provider_id']
42+
)
43+
db.session.add(new_service)
44+
db.session.commit()
45+
return jsonify({"message": "Service created successfully!"}), 201
46+
47+
# Get a specific service
48+
@api.route('/services/<int:service_id>', methods=['GET'])
49+
def get_service(service_id):
50+
service = Service.query.get_or_404(service_id)
51+
return jsonify({
52+
"id": service.id,
53+
"name": service.name,
54+
"price": service.price,
55+
"time_required": service.time_required_in_hours,
56+
"description": service.description,
57+
"provider_id": service.provider
58+
})
59+
60+
# Update a service
61+
@api.route('/services/<int:service_id>', methods=['PUT'])
62+
@login_required
63+
def update_service(service_id):
64+
service = Service.query.get_or_404(service_id)
65+
data = request.json
66+
service.name = data.get('name', service.name)
67+
service.price = data.get('price', service.price)
68+
service.time_required_in_hours = data.get('time_required', service.time_required_in_hours)
69+
service.description = data.get('description', service.description)
70+
db.session.commit()
71+
return jsonify({"message": "Service updated successfully!"})
72+
73+
# Delete a service
74+
@api.route('/services/<int:service_id>', methods=['DELETE'])
75+
@login_required
76+
def delete_service(service_id):
77+
service = Service.query.get_or_404(service_id)
78+
db.session.delete(service)
79+
db.session.commit()
80+
return jsonify({"message": "Service deleted successfully!"})

app/auth.py

+37-37
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
# Helper functions for validation
1111
def is_valid_email(email):
1212
regex = r'^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w+$'
13-
return re.match(regex, email) is not None
13+
return re.match(regex, str(email)) is not None
1414

1515
def is_valid_password(password):
1616
if len(password) < 8:
@@ -29,42 +29,38 @@ def login():
2929
if request.method == "POST":
3030
username = request.form.get('username')
3131
password = request.form.get('password')
32-
role = request.form.get('role').lower()
32+
role = request.form.get('role')
3333
remember = request.form.get('remember') == "on"
3434

35-
if not username or not password:
36-
flash("Username and password are required.", "warning")
37-
return redirect(url_for('auth.login'))
38-
39-
try:
40-
if role == "customer":
41-
user = Customer.query.filter_by(username=username).first()
42-
elif role == "professional":
43-
user = Professional.query.filter_by(username=username).first()
44-
elif role == "admin":
45-
user = Admin.query.filter_by(username=username).first()
46-
else:
47-
flash("Invalid role. Please select a role and try again.", "warning")
48-
return redirect(url_for('auth.login'))
49-
except SQLAlchemyError:
50-
flash("User not found. Please check your details and try again.", "warning")
35+
# Validate input
36+
if not username or not password or not role:
37+
flash("All fields are required.", "warning")
5138
return redirect(url_for('auth.login'))
5239

40+
# Fetch user based on role
41+
user = None
42+
if role == "customer":
43+
user = Customer.query.filter_by(username=username).first()
44+
elif role == "professional":
45+
user = Professional.query.filter_by(username=username).first()
46+
elif role == "admin":
47+
user = Admin.query.filter_by(username=username).first()
48+
49+
# Authenticate user
5350
if user and check_password_hash(user.password_hash, password):
54-
try:
55-
login_user(user, remember=remember)
56-
flash("Logged in successfully", "success")
57-
next_page = request.args.get('next')
58-
session['role'] = role
59-
60-
if next_page in [url_for('auth.login'), url_for('auth.signup'), url_for('auth.signup_as_customer'), url_for('auth.signup_as_professional')]:
61-
return redirect(url_for('customer.home'))
62-
63-
return redirect(next_page or url_for('customer.home'))
64-
except Exception as e:
65-
flash("An error occurred during login: " + str(e), "warning")
51+
if user.role != role:
52+
flash("Invalid role for this account.", "warning")
53+
return redirect(url_for('auth.login'))
54+
if getattr(user, 'is_blocked', False): # Check if the user is blocked
55+
flash("Your account has been blocked. Please contact support.", "warning")
56+
return redirect(url_for('auth.login'))
57+
58+
login_user(user, remember=remember)
59+
session['role'] = role
60+
flash("Logged in successfully!", "success")
61+
return redirect(url_for('customer.home'))
6662
else:
67-
flash("Invalid username or password", "warning")
63+
flash("Invalid username or password.", "warning")
6864
return render_template("login.html")
6965

7066

@@ -143,11 +139,14 @@ def signup_as_professional():
143139
email = request.form.get('email')
144140
phone = request.form.get('phone')
145141
address = request.form.get('address')
142+
service_type = request.form.get('service_type') # New
143+
experience = request.form.get('experience') # New
146144

147-
if not username or not password or not email or not phone:
148-
flash("Username, password, email, and phone are required.", "warning")
145+
# Basic validation
146+
if not username or not password or not email or not phone or not service_type or not experience:
147+
flash("All fields are required.", "warning")
149148
return redirect(url_for('auth.signup_as_professional'))
150-
149+
151150
if not is_valid_email(email):
152151
flash("Invalid email address.", "warning")
153152
return redirect(url_for('auth.signup_as_professional'))
@@ -163,7 +162,6 @@ def signup_as_professional():
163162
if Professional.query.filter_by(email=email).first():
164163
flash("Email already in use. Please login instead.", "warning")
165164
return redirect(url_for('auth.signup_as_professional'))
166-
167165
try:
168166
user = Professional(
169167
username=username,
@@ -172,11 +170,13 @@ def signup_as_professional():
172170
password_hash=generate_password_hash(password),
173171
email=email,
174172
phone=phone,
175-
address=address
173+
address=address,
174+
service_type=service_type,
175+
experience=int(experience) # Ensure integer
176176
)
177177
db.session.add(user)
178178
db.session.commit()
179-
flash("User registered successfully", "success")
179+
flash("Professional registered successfully!", "success")
180180
return redirect(url_for('auth.login'))
181181
except SQLAlchemyError:
182182
db.session.rollback()

0 commit comments

Comments
 (0)