Coverage for opportunities/routes_opportunities.py: 73%
116 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-05 14:02 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-05 14:02 +0000
1"""Routes for opportunities"""
3from html import escape
4import uuid
5from flask import (
6 flash,
7 jsonify,
8 redirect,
9 render_template,
10 request,
11 send_file,
12 session,
13 url_for,
14)
15from core import handlers
16from course_modules.models import Module
17from courses.models import Course
18from employers.models import Employers
19from .models import Opportunity
22def add_opportunities_routes(app):
23 """Add routes for opportunities"""
25 @app.route("/opportunities/search", methods=["GET"])
26 @handlers.admin_or_employers_required
27 def search_opportunities():
28 """
29 Unified route for searching opportunities by admins and employers.
30 Determines user type from session.
31 """
32 # Fetch user session details
33 from app import DEADLINE_MANAGER
35 user_type = handlers.get_user_type()
36 employer = session.get("employer", None)
37 print(f"[DEBUG] User type: {user_type}")
38 # Fetch opportunities based on user type
39 if user_type == "admin":
40 opportunities = Opportunity().get_opportunities_for_search(_id=None)
41 else:
42 opportunities = Opportunity().get_opportunities_for_search(
43 _id=employer.get("_id", None)
44 )
46 # Prepare context for rendering
47 context = {
48 "opportunities": opportunities,
49 "user_type": user_type,
50 "courses": Course().get_courses(),
51 "modules": Module().get_modules(),
52 }
54 # Add employers map if admin
55 if user_type == "admin":
56 employers_map = {
57 employer["_id"]: employer for employer in Employers().get_employers()
58 }
59 context["employers_map"] = employers_map
60 context["page"] = "opportunities"
62 return render_template(
63 "opportunities/search.html",
64 **context,
65 deadline_type=DEADLINE_MANAGER.get_deadline_type(),
66 )
68 @app.route(
69 "/opportunities/employer_add_update_opportunity", methods=["GET", "POST"]
70 )
71 @handlers.admin_or_employers_required
72 def employer_add_update_opportunity():
73 # Check if the details deadline has passed and the employer is in the session
74 from app import DEADLINE_MANAGER
76 if DEADLINE_MANAGER.is_past_details_deadline() and "employer" in session:
77 return render_template(
78 "employers/past_deadline.html",
79 data=(
80 "Adding/Updating details deadline has passed as of "
81 f"{DEADLINE_MANAGER.get_details_deadline()}"
82 ),
83 referrer=request.referrer,
84 employer=session["employer"], # Pass employer to the template
85 user_type="employer",
86 deadline_type=DEADLINE_MANAGER.get_deadline_type(),
87 )
89 if request.method == "POST":
90 try:
91 opportunity = {
92 "_id": request.form.get("_id"),
93 "title": request.form.get("title"),
94 "description": request.form.get("description"),
95 "url": request.form.get("url", ""),
96 "employer_id": None,
97 "location": request.form.get("location"),
98 "modules_required": [
99 module.strip()
100 for module in request.form.get("modules_required")[1:-1]
101 .replace('"', "")
102 .split(",")
103 ],
104 "courses_required": [
105 course.strip()
106 for course in request.form.get("courses_required")[1:-1]
107 .replace('"', "")
108 .split(",")
109 ],
110 "spots_available": int(request.form.get("spots_available")),
111 "duration": request.form.get("duration"),
112 }
114 # Check if any required field is empty
115 for key, value in opportunity.items():
116 if not value and key not in {
117 "employer_id",
118 "url",
119 "modules_required",
120 "courses_required",
121 }:
122 raise ValueError(
123 f"Field {key} is required and cannot be empty."
124 )
125 if opportunity["modules_required"] == [""]:
126 opportunity["modules_required"] = []
127 if opportunity["courses_required"] == [""]:
128 opportunity["courses_required"] = []
130 if opportunity["spots_available"] < 1:
131 raise ValueError("Spots available must be at least 1.")
132 if opportunity["duration"] not in [
133 "1_day",
134 "1_week",
135 "1_month",
136 "3_months",
137 "6_months",
138 "12_months",
139 ]:
140 raise ValueError("Invalid duration value.")
141 except Exception as e:
142 return jsonify({"error": str(e)}), 400
144 opportunity["title"] = escape(opportunity["title"])
145 opportunity["description"] = escape(opportunity["description"])
146 opportunity["url"] = escape(opportunity["url"])
147 opportunity["location"] = escape(opportunity["location"])
148 opportunity["duration"] = escape(opportunity["duration"])
149 opportunity["modules_required"] = [
150 escape(module) for module in opportunity["modules_required"]
151 ]
152 opportunity["courses_required"] = [
153 escape(course) for course in opportunity["courses_required"]
154 ]
156 if handlers.is_admin():
157 opportunity["employer_id"] = request.form.get("company")
158 return Opportunity().add_update_opportunity(opportunity, True)
160 original = Opportunity().get_opportunity_by_id(opportunity["_id"])
161 if original and original["employer_id"] != session["employer"]["_id"]:
162 return jsonify({"error": "Unauthorized Access."}), 401
163 opportunity["employer_id"] = session["employer"]["_id"]
164 return Opportunity().add_update_opportunity(opportunity, False)
166 # Get the opportunity by ID if it exists
167 opportunity_id = request.args.get("opportunity_id")
168 if opportunity_id is not None:
169 opportunity = Opportunity().get_opportunity_by_id(opportunity_id)
170 else:
171 opportunity = {"_id": uuid.uuid4().hex, "spots_available": 1}
173 # Include employer in the context
174 employer = session.get("employer", None)
175 user_type = "admin" if handlers.is_admin() else "employer"
176 employers = Employers().get_employers()
177 return render_template(
178 "opportunities/employer_add_update_opportunity.html",
179 opportunity=opportunity,
180 courses=Course().get_courses(),
181 modules=Module().get_modules(),
182 user_type=user_type,
183 employer=employer, # Add employer to the template context
184 page="opportunities",
185 employers=employers,
186 deadline_type=DEADLINE_MANAGER.get_deadline_type(),
187 )
189 @app.route("/opportunities/employer_delete_opportunity", methods=["POST", "GET"])
190 @handlers.admin_or_employers_required
191 def employer_delete_opportunity():
192 opportunity_id = request.args.get("opportunity_id")
193 if not opportunity_id:
194 flash("Opportunity ID is required", "error")
195 return redirect(request.referrer)
197 Opportunity().delete_opportunity_by_id(opportunity_id)
198 flash("Opportunity deleted successfully", "success")
199 return redirect(url_for("search_opportunities"))
201 @app.route("/opportunities/upload", methods=["GET", "POST"])
202 @handlers.admin_or_employers_required
203 def upload_opportunities():
204 from app import DEADLINE_MANAGER
206 user_type = "admin" if handlers.is_admin() else "employer"
208 if request.method == "POST":
209 file = request.files["file"]
210 if not file:
211 return jsonify({"error": "No file provided"}), 400
212 if not handlers.allowed_file(file.filename, ["xlsx", "xls"]):
213 return jsonify({"error": "Invalid file type"}), 400
215 if user_type == "admin":
216 return Opportunity().upload_opportunities(file, True)
218 return Opportunity().upload_opportunities(file, False)
220 return render_template(
221 "opportunities/upload.html",
222 user_type=user_type,
223 page="opportunities",
224 deadline_type=DEADLINE_MANAGER.get_deadline_type(),
225 )
227 @app.route("/opportunities/download_all", methods=["GET"])
228 @handlers.admin_or_employers_required
229 def download_opportunities():
230 user_type = "admin" if handlers.is_admin() else "employer"
231 if user_type == "admin":
232 return Opportunity().download_opportunities(True)
233 return Opportunity().download_opportunities(False)
235 @app.route("/opportunities/download_template", methods=["GET"])
236 @handlers.admin_or_employers_required
237 def download_opportunities_template():
238 user_type = "admin" if handlers.is_admin() else "employer"
240 if user_type == "admin":
241 return send_file(
242 "data_model_upload_template/admin_opportunities_template.xlsx",
243 as_attachment=True,
244 )
245 return send_file(
246 "data_model_upload_template/employer_opportunities_template.xlsx",
247 as_attachment=True,
248 )
250 @app.route("/opportunities/delete_all", methods=["DELETE"])
251 @handlers.admin_or_employers_required
252 def delete_all_opportunities():
253 user_type = "admin" if handlers.is_admin() else "employer"
254 if user_type == "admin":
255 return Opportunity().delete_all_opportunities(True)
256 return Opportunity().delete_all_opportunities(False)