Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1#!/usr/bin/env python 

2 

3""" 

4camcops_server/tasks/demoquestionnaire.py 

5 

6=============================================================================== 

7 

8 Copyright (C) 2012-2020 Rudolf Cardinal (rudolf@pobox.com). 

9 

10 This file is part of CamCOPS. 

11 

12 CamCOPS is free software: you can redistribute it and/or modify 

13 it under the terms of the GNU General Public License as published by 

14 the Free Software Foundation, either version 3 of the License, or 

15 (at your option) any later version. 

16 

17 CamCOPS is distributed in the hope that it will be useful, 

18 but WITHOUT ANY WARRANTY; without even the implied warranty of 

19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

20 GNU General Public License for more details. 

21 

22 You should have received a copy of the GNU General Public License 

23 along with CamCOPS. If not, see <https://www.gnu.org/licenses/>. 

24 

25=============================================================================== 

26 

27""" 

28 

29from typing import Any, Dict, Optional, Tuple, Type 

30 

31from sqlalchemy.ext.declarative import DeclarativeMeta 

32from sqlalchemy.sql.schema import Column 

33from sqlalchemy.sql.sqltypes import Date, Float, Integer, Time, UnicodeText 

34 

35from camcops_server.cc_modules.cc_blob import Blob, blob_relationship 

36from camcops_server.cc_modules.cc_constants import CssClass 

37from camcops_server.cc_modules.cc_db import add_multiple_columns 

38from camcops_server.cc_modules.cc_html import answer 

39from camcops_server.cc_modules.cc_request import CamcopsRequest 

40from camcops_server.cc_modules.cc_sqla_coltypes import ( 

41 CamcopsColumn, 

42 PendulumDateTimeAsIsoTextColType, 

43 DiagnosticCodeColType, 

44) 

45from camcops_server.cc_modules.cc_task import Task 

46 

47 

48# ============================================================================= 

49# TASKS: DEMO QUESTIONNAIRE 

50# ============================================================================= 

51 

52N_MCQ = 10 # 8 in v1; 10 in v2 

53N_MCQBOOL = 3 

54N_MULTIPLERESPONSE = 6 

55N_BOOLTEXT = 22 

56N_BOOLIMAGE = 2 

57N_PICKER = 2 

58N_SLIDER = 2 

59 

60 

61def divtest(divname: str) -> str: 

62 return f'<div class="{divname}">.{divname}</div>\n' 

63 

64 

65class DemoQuestionnaireMetaclass(DeclarativeMeta): 

66 # noinspection PyInitNewSignature 

67 def __init__(cls: Type['DemoQuestionnaire'], 

68 name: str, 

69 bases: Tuple[Type, ...], 

70 classdict: Dict[str, Any]) -> None: 

71 add_multiple_columns(cls, "mcq", 1, N_MCQ) 

72 add_multiple_columns(cls, "mcqbool", 1, N_MCQBOOL) 

73 add_multiple_columns(cls, "multipleresponse", 1, N_MULTIPLERESPONSE) 

74 add_multiple_columns(cls, "booltext", 1, N_BOOLTEXT) 

75 add_multiple_columns(cls, "boolimage", 1, N_BOOLIMAGE) 

76 add_multiple_columns(cls, "picker", 1, N_PICKER) 

77 add_multiple_columns(cls, "slider", 1, N_SLIDER, Float) 

78 super().__init__(name, bases, classdict) 

79 

80 

81class DemoQuestionnaire(Task, 

82 metaclass=DemoQuestionnaireMetaclass): 

83 """ 

84 Server implementation of the demo questionnaire task. 

85 """ 

86 __tablename__ = "demoquestionnaire" 

87 shortname = "Demo" 

88 is_anonymous = True 

89 

90 mcqtext_1a = Column("mcqtext_1a", UnicodeText) 

91 mcqtext_1b = Column("mcqtext_1b", UnicodeText) 

92 mcqtext_2a = Column("mcqtext_2a", UnicodeText) 

93 mcqtext_2b = Column("mcqtext_2b", UnicodeText) 

94 mcqtext_3a = Column("mcqtext_3a", UnicodeText) 

95 mcqtext_3b = Column("mcqtext_3b", UnicodeText) 

96 typedvar_text = Column("typedvar_text", UnicodeText) 

97 typedvar_text_multiline = Column("typedvar_text_multiline", UnicodeText) 

98 typedvar_text_rich = Column("typedvar_text_rich", UnicodeText) # v2 

99 typedvar_int = Column("typedvar_int", Integer) 

100 typedvar_real = Column("typedvar_real", Float) 

101 date_only = Column("date_only", Date) 

102 date_time = Column("date_time", PendulumDateTimeAsIsoTextColType) 

103 thermometer = Column("thermometer", Integer) 

104 diagnosticcode_code = Column("diagnosticcode_code", DiagnosticCodeColType) 

105 diagnosticcode_description = CamcopsColumn( 

106 "diagnosticcode_description", UnicodeText, 

107 exempt_from_anonymisation=True 

108 ) 

109 diagnosticcode2_code = Column( 

110 "diagnosticcode2_code", DiagnosticCodeColType 

111 ) # v2 

112 diagnosticcode2_description = CamcopsColumn( 

113 "diagnosticcode2_description", UnicodeText, 

114 exempt_from_anonymisation=True 

115 ) # v2 

116 photo_blobid = CamcopsColumn( 

117 "photo_blobid", Integer, 

118 is_blob_id_field=True, blob_relationship_attr_name="photo" 

119 ) 

120 # IGNORED. REMOVE WHEN ALL PRE-2.0.0 TABLETS GONE: 

121 photo_rotation = Column("photo_rotation", Integer) # DEFUNCT as of v2.0.0 # noqa 

122 canvas_blobid = CamcopsColumn( 

123 "canvas_blobid", Integer, 

124 is_blob_id_field=True, blob_relationship_attr_name="canvas" 

125 ) 

126 canvas2_blobid = CamcopsColumn( 

127 "canvas2_blobid", Integer, 

128 is_blob_id_field=True, blob_relationship_attr_name="canvas2" 

129 ) 

130 spinbox_int = Column("spinbox_int", Integer) # v2 

131 spinbox_real = Column("spinbox_real", Float) # v2 

132 time_only = Column("time_only", Time) # v2 

133 

134 photo = blob_relationship("DemoQuestionnaire", "photo_blobid") # type: Optional[Blob] # noqa 

135 canvas = blob_relationship("DemoQuestionnaire", "canvas_blobid") # type: Optional[Blob] # noqa 

136 canvas2 = blob_relationship("DemoQuestionnaire", "canvas2_blobid") # type: Optional[Blob] # noqa 

137 

138 @staticmethod 

139 def longname(req: "CamcopsRequest") -> str: 

140 _ = req.gettext 

141 return _("Demonstration Questionnaire") 

142 

143 # noinspection PyMethodOverriding 

144 @staticmethod 

145 def is_complete() -> bool: 

146 return True 

147 

148 def get_task_html(self, req: CamcopsRequest) -> str: 

149 h = f""" 

150 <div class="{CssClass.SUMMARY}"> 

151 <table class="{CssClass.SUMMARY}"> 

152 {self.get_is_complete_tr(req)} 

153 </table> 

154 </div> 

155 <div class="{CssClass.EXPLANATION}"> 

156 This is a demo questionnaire, containing no genuine 

157 information. 

158 </div> 

159 <table class="{CssClass.TASKDETAIL}"> 

160 <tr> 

161 <th width="50%">Question</th> 

162 <th width="50%">Answer</th> 

163 </tr> 

164 """ 

165 for i in range(1, N_MCQ + 1): 

166 h += self.get_twocol_val_row("mcq" + str(i)) 

167 for i in range(1, N_MCQBOOL + 1): 

168 h += self.get_twocol_bool_row(req, "mcqbool" + str(i)) 

169 for i in range(1, N_MULTIPLERESPONSE + 1): 

170 h += self.get_twocol_bool_row(req, "multipleresponse" + str(i)) 

171 for i in range(1, N_BOOLTEXT + 1): 

172 h += self.get_twocol_bool_row(req, "booltext" + str(i)) 

173 for i in range(1, N_BOOLIMAGE + 1): 

174 h += self.get_twocol_bool_row(req, "boolimage" + str(i)) 

175 for i in range(1, N_PICKER + 1): 

176 h += self.get_twocol_val_row("picker" + str(i)) 

177 for i in range(1, N_SLIDER + 1): 

178 h += self.get_twocol_val_row("slider" + str(i)) 

179 h += self.get_twocol_string_row("mcqtext_1a") 

180 h += self.get_twocol_string_row("mcqtext_1b") 

181 h += self.get_twocol_string_row("mcqtext_2a") 

182 h += self.get_twocol_string_row("mcqtext_2b") 

183 h += self.get_twocol_string_row("mcqtext_3a") 

184 h += self.get_twocol_string_row("mcqtext_3b") 

185 h += self.get_twocol_string_row("typedvar_text") 

186 h += self.get_twocol_string_row("typedvar_text_multiline") 

187 h += self.get_twocol_string_row("typedvar_text_rich") 

188 h += self.get_twocol_val_row("typedvar_int") 

189 h += self.get_twocol_val_row("typedvar_real") 

190 h += self.get_twocol_val_row("date_only") 

191 h += self.get_twocol_val_row("date_time") 

192 h += self.get_twocol_val_row("thermometer") 

193 h += self.get_twocol_string_row("diagnosticcode_code") 

194 h += self.get_twocol_string_row("diagnosticcode_description") 

195 h += self.get_twocol_string_row("diagnosticcode2_code") 

196 h += self.get_twocol_string_row("diagnosticcode2_description") 

197 # noinspection PyTypeChecker 

198 h += self.get_twocol_picture_row(self.photo, "photo") 

199 # noinspection PyTypeChecker 

200 h += self.get_twocol_picture_row(self.canvas, "canvas") 

201 # noinspection PyTypeChecker 

202 h += self.get_twocol_picture_row(self.canvas2, "canvas2") 

203 h += """ 

204 </table> 

205 

206 <div> 

207 In addition to the data (above), this task demonstrates 

208 HTML/CSS styles used in the CamCOPS views. 

209 </div> 

210 

211 <h1>Header 1</h1> 

212 <h2>Header 2</h2> 

213 <h3>Header 3</h3> 

214 

215 <div> 

216 Plain div with <sup>superscript</sup> and <sub>subscript</sub>. 

217 <br> 

218 Answers look like this: """ + answer("Answer") + """<br> 

219 Missing answers look liks this: """ + answer(None) + """<br> 

220 </div> 

221 """ 

222 h += divtest(CssClass.BAD_ID_POLICY_MILD) 

223 h += divtest(CssClass.BAD_ID_POLICY_SEVERE) 

224 h += divtest(CssClass.CLINICIAN) 

225 h += divtest(CssClass.COPYRIGHT) 

226 h += divtest(CssClass.ERROR) 

227 h += divtest(CssClass.EXPLANATION) 

228 h += divtest(CssClass.FOOTNOTES) 

229 h += divtest(CssClass.FORMTITLE) 

230 h += divtest(CssClass.GREEN) 

231 h += divtest(CssClass.HEADING) 

232 h += divtest(CssClass.IMPORTANT) 

233 h += divtest(CssClass.INCOMPLETE) 

234 h += divtest(CssClass.INDENTED) 

235 h += divtest(CssClass.LIVE_ON_TABLET) 

236 h += divtest(CssClass.NAVIGATION) 

237 h += divtest(CssClass.OFFICE) 

238 h += divtest(CssClass.PATIENT) 

239 h += divtest(CssClass.RESPONDENT) 

240 h += divtest(CssClass.SMALLPRINT) 

241 h += divtest(CssClass.SPECIALNOTE) 

242 h += divtest(CssClass.SUBHEADING) 

243 h += divtest(CssClass.SUBSUBHEADING) 

244 h += divtest(CssClass.SUMMARY) 

245 h += divtest(CssClass.SUPERUSER) 

246 h += divtest(CssClass.TASKHEADER) 

247 h += divtest(CssClass.TRACKERHEADER) 

248 h += divtest(CssClass.TRACKER_ALL_CONSISTENT) 

249 h += divtest(CssClass.WARNING) 

250 h += """ 

251 <table> 

252 <tr> 

253 <th>Standard table heading; column 1</th><th>Column 2</th> 

254 </tr> 

255 <tr> 

256 <td>Standard table row; column 1</td><td>Column 2</td> 

257 </tr> 

258 </table> 

259 

260 <div>Inlined <code>code looks like this</code>. 

261 

262 <div>There are some others, too.</div> 

263 """ 

264 return h