Source code for camcops_server.tasks.demoquestionnaire

"""
camcops_server/tasks/demoquestionnaire.py

===============================================================================

    Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
    Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

    This file is part of CamCOPS.

    CamCOPS is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CamCOPS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.

===============================================================================

"""

import datetime
from typing import Any, Optional, Type

from pendulum import DateTime as Pendulum
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.sql.sqltypes import Float, Time, UnicodeText

from camcops_server.cc_modules.cc_blob import Blob, blob_relationship
from camcops_server.cc_modules.cc_constants import CssClass
from camcops_server.cc_modules.cc_db import add_multiple_columns
from camcops_server.cc_modules.cc_html import answer
from camcops_server.cc_modules.cc_request import CamcopsRequest
from camcops_server.cc_modules.cc_sqla_coltypes import (
    mapped_camcops_column,
    PendulumDateTimeAsIsoTextColType,
    DiagnosticCodeColType,
)
from camcops_server.cc_modules.cc_task import Task


# =============================================================================
# TASKS: DEMO QUESTIONNAIRE
# =============================================================================

N_MCQ = 10  # 8 in v1; 10 in v2
N_MCQBOOL = 3
N_MULTIPLERESPONSE = 6
N_BOOLTEXT = 22
N_BOOLIMAGE = 2
N_PICKER = 2
N_SLIDER = 2


def divtest(divname: str) -> str:
    return f'<div class="{divname}">.{divname}</div>\n'


[docs]class DemoQuestionnaire( Task, ): """ Server implementation of the demo questionnaire task. """ __tablename__ = "demoquestionnaire" shortname = "Demo" is_anonymous = True # type: ignore[assignment] @classmethod def extend_columns(cls: Type["DemoQuestionnaire"], **kwargs: Any) -> None: add_multiple_columns(cls, "mcq", 1, N_MCQ) add_multiple_columns(cls, "mcqbool", 1, N_MCQBOOL) add_multiple_columns(cls, "multipleresponse", 1, N_MULTIPLERESPONSE) add_multiple_columns(cls, "booltext", 1, N_BOOLTEXT) add_multiple_columns(cls, "boolimage", 1, N_BOOLIMAGE) add_multiple_columns(cls, "picker", 1, N_PICKER) add_multiple_columns(cls, "slider", 1, N_SLIDER, Float) mcqtext_1a: Mapped[Optional[str]] = mapped_column(UnicodeText) mcqtext_1b: Mapped[Optional[str]] = mapped_column(UnicodeText) mcqtext_2a: Mapped[Optional[str]] = mapped_column(UnicodeText) mcqtext_2b: Mapped[Optional[str]] = mapped_column(UnicodeText) mcqtext_3a: Mapped[Optional[str]] = mapped_column(UnicodeText) mcqtext_3b: Mapped[Optional[str]] = mapped_column(UnicodeText) typedvar_text: Mapped[Optional[str]] = mapped_column(UnicodeText) typedvar_text_multiline: Mapped[Optional[str]] = mapped_column(UnicodeText) typedvar_text_rich: Mapped[Optional[str]] = mapped_column( UnicodeText ) # v2 typedvar_int: Mapped[Optional[int]] = mapped_column() typedvar_real: Mapped[Optional[float]] = mapped_column() date_only: Mapped[Optional[datetime.date]] = mapped_column() date_time: Mapped[Optional[Pendulum]] = mapped_column( PendulumDateTimeAsIsoTextColType ) thermometer: Mapped[Optional[int]] = mapped_column() diagnosticcode_code: Mapped[Optional[str]] = mapped_column( DiagnosticCodeColType ) diagnosticcode_description: Mapped[Optional[str]] = mapped_camcops_column( UnicodeText, exempt_from_anonymisation=True, ) diagnosticcode2_code: Mapped[Optional[str]] = mapped_column( DiagnosticCodeColType ) # v2 diagnosticcode2_description: Mapped[Optional[str]] = mapped_camcops_column( UnicodeText, exempt_from_anonymisation=True, ) # v2 photo_blobid: Mapped[Optional[int]] = mapped_camcops_column( is_blob_id_field=True, blob_relationship_attr_name="photo", ) # IGNORED. REMOVE WHEN ALL PRE-2.0.0 TABLETS GONE: photo_rotation: Mapped[Optional[int]] = ( mapped_column() ) # DEFUNCT as of v2.0.0 canvas_blobid: Mapped[Optional[int]] = mapped_camcops_column( is_blob_id_field=True, blob_relationship_attr_name="canvas", ) canvas2_blobid: Mapped[Optional[int]] = mapped_camcops_column( is_blob_id_field=True, blob_relationship_attr_name="canvas2", ) spinbox_int: Mapped[Optional[int]] = mapped_column() # v2 spinbox_real: Mapped[Optional[float]] = mapped_column() # v2 time_only: Mapped[Optional[datetime.time]] = mapped_column( "time_only", Time ) # v2 photo = blob_relationship( # type: ignore[assignment] "DemoQuestionnaire", "photo_blobid" ) # type: Optional[Blob] canvas = blob_relationship( # type: ignore[assignment] "DemoQuestionnaire", "canvas_blobid" ) # type: Optional[Blob] canvas2 = blob_relationship( # type: ignore[assignment] "DemoQuestionnaire", "canvas2_blobid" ) # type: Optional[Blob]
[docs] @staticmethod def longname(req: "CamcopsRequest") -> str: _ = req.gettext return _("Demonstration Questionnaire")
# noinspection PyMethodOverriding
[docs] @staticmethod def is_complete() -> bool: return True
[docs] def get_task_html(self, req: CamcopsRequest) -> str: h = f""" <div class="{CssClass.SUMMARY}"> <table class="{CssClass.SUMMARY}"> {self.get_is_complete_tr(req)} </table> </div> <div class="{CssClass.EXPLANATION}"> This is a demo questionnaire, containing no genuine information. </div> <table class="{CssClass.TASKDETAIL}"> <tr> <th width="50%">Question</th> <th width="50%">Answer</th> </tr> """ for i in range(1, N_MCQ + 1): h += self.get_twocol_val_row("mcq" + str(i)) for i in range(1, N_MCQBOOL + 1): h += self.get_twocol_bool_row(req, "mcqbool" + str(i)) for i in range(1, N_MULTIPLERESPONSE + 1): h += self.get_twocol_bool_row(req, "multipleresponse" + str(i)) for i in range(1, N_BOOLTEXT + 1): h += self.get_twocol_bool_row(req, "booltext" + str(i)) for i in range(1, N_BOOLIMAGE + 1): h += self.get_twocol_bool_row(req, "boolimage" + str(i)) for i in range(1, N_PICKER + 1): h += self.get_twocol_val_row("picker" + str(i)) for i in range(1, N_SLIDER + 1): h += self.get_twocol_val_row("slider" + str(i)) h += self.get_twocol_string_row("mcqtext_1a") h += self.get_twocol_string_row("mcqtext_1b") h += self.get_twocol_string_row("mcqtext_2a") h += self.get_twocol_string_row("mcqtext_2b") h += self.get_twocol_string_row("mcqtext_3a") h += self.get_twocol_string_row("mcqtext_3b") h += self.get_twocol_string_row("typedvar_text") h += self.get_twocol_string_row("typedvar_text_multiline") h += self.get_twocol_string_row("typedvar_text_rich") h += self.get_twocol_val_row("typedvar_int") h += self.get_twocol_val_row("typedvar_real") h += self.get_twocol_val_row("date_only") h += self.get_twocol_val_row("date_time") h += self.get_twocol_val_row("thermometer") h += self.get_twocol_string_row("diagnosticcode_code") h += self.get_twocol_string_row("diagnosticcode_description") h += self.get_twocol_string_row("diagnosticcode2_code") h += self.get_twocol_string_row("diagnosticcode2_description") # noinspection PyTypeChecker h += self.get_twocol_picture_row(self.photo, "photo") # noinspection PyTypeChecker h += self.get_twocol_picture_row(self.canvas, "canvas") # noinspection PyTypeChecker h += self.get_twocol_picture_row(self.canvas2, "canvas2") h += ( """ </table> <div> In addition to the data (above), this task demonstrates HTML/CSS styles used in the CamCOPS views. </div> <h1>Header 1</h1> <h2>Header 2</h2> <h3>Header 3</h3> <div> Plain div with <sup>superscript</sup> and <sub>subscript</sub>. <br> Answers look like this: """ + answer("Answer") + """<br> Missing answers look liks this: """ + answer(None) + """<br> </div> """ ) h += divtest(CssClass.BAD_ID_POLICY_MILD) h += divtest(CssClass.BAD_ID_POLICY_SEVERE) h += divtest(CssClass.CLINICIAN) h += divtest(CssClass.COPYRIGHT) h += divtest(CssClass.ERROR) h += divtest(CssClass.EXPLANATION) h += divtest(CssClass.FOOTNOTES) h += divtest(CssClass.FORMTITLE) h += divtest(CssClass.GREEN) h += divtest(CssClass.HEADING) h += divtest(CssClass.IMPORTANT) h += divtest(CssClass.INCOMPLETE) h += divtest(CssClass.INDENTED) h += divtest(CssClass.LIVE_ON_TABLET) h += divtest(CssClass.NAVIGATION) h += divtest(CssClass.OFFICE) h += divtest(CssClass.PATIENT) h += divtest(CssClass.RESPONDENT) h += divtest(CssClass.SMALLPRINT) h += divtest(CssClass.SPECIALNOTE) h += divtest(CssClass.SUBHEADING) h += divtest(CssClass.SUBSUBHEADING) h += divtest(CssClass.SUMMARY) h += divtest(CssClass.SUPERUSER) h += divtest(CssClass.TASKHEADER) h += divtest(CssClass.TRACKERHEADER) h += divtest(CssClass.TRACKER_ALL_CONSISTENT) h += divtest(CssClass.WARNING) h += """ <table> <tr> <th>Standard table heading; column 1</th><th>Column 2</th> </tr> <tr> <td>Standard table row; column 1</td><td>Column 2</td> </tr> </table> <div>Inlined <code>code looks like this</code>. <div>There are some others, too.</div> """ return h