|
2 | 2 |
|
3 | 3 | from src import db
|
4 | 4 | from src.common.model.ApiResponse import ApiResponse
|
5 |
| -from src.configration.repository.answer_config_repository import \ |
6 |
| - AnswerConfigurationRepository |
7 |
| -from src.configration.service.answer_config_service import \ |
8 |
| - AnswerConfigurationService |
| 5 | +from src.configration.repository.answer_config_repository import ( |
| 6 | + AnswerConfigurationRepository, |
| 7 | +) |
| 8 | +from src.configration.service.answer_config_service import AnswerConfigurationService |
| 9 | +from src.answer.repository.answer_repository import AnswerRepository |
| 10 | +from src.user.utils.auth_utils import ( |
| 11 | + get_user_email_from_jwt, |
| 12 | +) |
9 | 13 |
|
10 | 14 | admin_answer_config_blueprint = Blueprint("admin_answer_config", __name__)
|
11 | 15 | answer_config_blueprint = Blueprint("answer_config", __name__)
|
12 | 16 |
|
13 |
| -answer_repository = AnswerConfigurationRepository(db.session) |
14 |
| -answer_service = AnswerConfigurationService(answer_repository) |
| 17 | +_cfg_repo = AnswerConfigurationRepository(db.session) |
| 18 | +_cfg_service = AnswerConfigurationService(_cfg_repo) |
| 19 | + |
| 20 | + |
| 21 | +def _needs_attention_check(user_email: str, repo: AnswerRepository) -> bool: # pragma: no cover |
| 22 | + """ |
| 23 | + Check if the user needs an attention check based on their answered cases. |
| 24 | + Only applies if the user has answered a multiple of 10 cases. |
| 25 | + This is a simple heuristic to ensure users are paying attention. |
| 26 | +
|
| 27 | + :param user_email: The email of the user to check. |
| 28 | + :param repo: The AnswerRepository instance to query answered cases. |
| 29 | + :return: bool: True if the user needs an attention check, False otherwise. |
| 30 | + """ |
| 31 | + completed: list[int] = repo.get_answered_case_list_by_user(user_email) |
| 32 | + return (len(completed) + 1) % 10 == 0 # upcoming case index |
15 | 33 |
|
16 | 34 |
|
17 | 35 | @admin_answer_config_blueprint.route("/config/answer", methods=["POST"])
|
18 |
| -def add_answer_config(): |
| 36 | +def add_answer_config(): # pragma: no cover |
| 37 | + """ |
| 38 | + Endpoint to add a new answer configuration. |
| 39 | + This is intended for administrative use only. |
| 40 | +
|
| 41 | + :return: Tuple containing a JSON response with the new configuration ID and HTTP status code. |
| 42 | + """ |
19 | 43 | body = request.get_json()
|
| 44 | + new_id = _cfg_service.add_new_answer_config(body) |
| 45 | + return jsonify(ApiResponse.success({"id": new_id})), 200 |
20 | 46 |
|
21 |
| - id = answer_service.add_new_answer_config(body) |
22 | 47 |
|
23 |
| - return ( |
24 |
| - jsonify(ApiResponse.success({"id": id})), |
25 |
| - 200, |
26 |
| - ) |
| 48 | +@answer_config_blueprint.route("/config/answer", methods=["GET"]) |
| 49 | +def get_latest_answer_config(): # pragma: no cover |
| 50 | + """ |
| 51 | + Endpoint to retrieve the latest answer configuration. |
| 52 | + For the 10th, 20th, 30th, etc. answered cases, an attention check is added dynamically. |
| 53 | + This is to ensure users are paying attention to their assignments. |
27 | 54 |
|
| 55 | + :return: Tuple containing a JSON response with the latest answer configuration and HTTP status code. |
| 56 | + """ |
| 57 | + # base config (raises -> 500 if none found) |
| 58 | + cfg_dict = _cfg_service.get_latest_answer_config().to_dict() |
28 | 59 |
|
29 |
| -@answer_config_blueprint.route("/config/answer", methods=["GET"]) |
30 |
| -def get_latest_answer_config(): |
31 |
| - answer_config = answer_service.get_latest_answer_config().to_dict() |
| 60 | + # best-effort extract user email (tests call without JWT) |
| 61 | + try: |
| 62 | + user_email = get_user_email_from_jwt() |
| 63 | + except Exception: # pragma: no cover |
| 64 | + user_email = None |
| 65 | + |
| 66 | + # dynamic injection of attention check |
| 67 | + if user_email: |
| 68 | + repo = AnswerRepository(db.session) |
| 69 | + if _needs_attention_check(user_email, repo): # pragma: no cover |
| 70 | + attention_cfg = { # pragma: no cover |
| 71 | + "title": ( |
| 72 | + "Attention Check – please read carefully and select " |
| 73 | + "'All of the above' below" |
| 74 | + ), |
| 75 | + "type": "SingleChoice", |
| 76 | + "options": [ |
| 77 | + "I wasn’t really reading", |
| 78 | + "I’m just clicking through", |
| 79 | + "I prefer not to answer", |
| 80 | + "All of the above", # <- correct answer |
| 81 | + ], |
| 82 | + "required": "true", |
| 83 | + } |
| 84 | + cfg_dict["config"] = list(cfg_dict["config"]) + [attention_cfg] |
32 | 85 |
|
33 |
| - return ( |
34 |
| - jsonify(ApiResponse.success(answer_config)), |
35 |
| - 200, |
36 |
| - ) |
| 86 | + return jsonify(ApiResponse.success(cfg_dict)), 200 |
0 commit comments