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"""Overview page of contributions. 

2 

3* Country selection 

4* Grouping by categories 

5* Statistics 

6""" 

7 

8from flask import make_response 

9 

10from config import Names as N 

11from control.utils import mjson, mktsv, pick as G, serverprint 

12from control.table import Table, SENSITIVE_TABLES, SENSITIVE_FIELDS 

13from control.typ.related import castObjectId 

14 

15 

16REVIEWED1 = "reviewed1" 

17REVIEWED2 = "reviewed2" 

18R1RANK = "r1Rank" 

19R2RANK = "r2Rank" 

20 

21ASSESSED_STATUS = { 

22 None: ("no assessment", "a-none"), 

23 N.incomplete: ("started", "a-started"), 

24 N.incompleteRevised: ("revision", "a-started"), 

25 N.incompleteWithdrawn: ("withdrawn", "a-none"), 

26 N.complete: ("filled-in", "a-self"), 

27 N.completeRevised: ("revised", "a-self"), 

28 N.completeWithdrawn: ("withdrawn", "a-none"), 

29 N.submitted: ("in review", "a-inreview"), 

30 N.submittedRevised: ("in review", "a-inreview"), 

31 N.reviewReject: ("rejected", "a-rejected"), 

32 N.reviewAccept: ("accepted", "a-accepted"), 

33} 

34ASSESSED_LABELS = {stage: info[0] for (stage, info) in ASSESSED_STATUS.items()} 

35ASSESSED_CLASS = {stage: info[1] for (stage, info) in ASSESSED_STATUS.items()} 

36ASSESSED_CLASS1 = {info[0]: info[1] for info in ASSESSED_STATUS.values()} 

37ASSESSED_DEFAULT_CLASS = ASSESSED_STATUS[None][1] 

38ASSESSED_RANK = {stage: i for (i, stage) in enumerate(ASSESSED_STATUS)} 

39 

40NO_REVIEW = { 

41 N.incomplete, 

42 N.incompleteRevised, 

43 N.incompleteWithdrawn, 

44 N.complete, 

45 N.completeRevised, 

46 N.completeWithdrawn, 

47} 

48IN_REVIEW = { 

49 N.submitted, 

50 N.submittedRevised, 

51} 

52ADVISORY_REVIEW = { 

53 N.reviewAdviseAccept, 

54 N.reviewAdviseReject, 

55 N.reviewAdviseRevise, 

56} 

57FINAL_REVIEW = { 

58 N.reviewAccept, 

59 N.reviewReject, 

60 N.reviewRevise, 

61} 

62 

63 

64REVIEWED_STATUS = { 

65 None: ("", "r-none"), 

66 "noReview": ("not reviewable", "r-noreview"), 

67 "inReview": ("in review", "r-inreview"), 

68 "skipReview": ("review skipped", "r-skipreview"), 

69 N.reviewAdviseReject: ("rejected", "r-rejected"), 

70 N.reviewAdviseAccept: ("accepted", "r-accepted"), 

71 N.reviewAdviseRevise: ("revise", "r-revised"), 

72 N.reviewReject: ("rejected", "r-rejected"), 

73 N.reviewAccept: ("accepted", "r-accepted"), 

74 N.reviewRevise: ("revise", "r-revised"), 

75} 

76REVIEW_LABELS = {stage: info[0] for (stage, info) in REVIEWED_STATUS.items()} 

77REVIEW_CLASS = {stage: info[1] for (stage, info) in REVIEWED_STATUS.items()} 

78REVIEW_CLASS1 = {info[0]: info[1] for info in REVIEWED_STATUS.values()} 

79REVIEW_DEFAULT_CLASS = REVIEWED_STATUS[None][1] 

80REVIEW_RANK = {stage: i for (i, stage) in enumerate(REVIEWED_STATUS)} 

81 

82 

83class Api: 

84 def __init__(self, context): 

85 self.context = context 

86 

87 types = context.types 

88 self.countryType = types.country 

89 self.yearType = types.year 

90 self.typeType = types.typeContribution 

91 self.headers = dict( 

92 json={ 

93 "Expires": "0", 

94 "Cache-Control": "no-cache, no-store, must-revalidate", 

95 "Content-Type": "application/json", 

96 "Content-Encoding": "utf-8", 

97 }, 

98 tsv={ 

99 "Expires": "0", 

100 "Cache-Control": "no-cache, no-store, must-revalidate", 

101 "Content-Type": "text/tab-separated-values", 

102 "Content-Encoding": "utf-8", 

103 }, 

104 ) 

105 

106 def notimplemented(self, verb): 

107 serverprint(f"Invalid api call requested: {verb}") 

108 return make_response(mjson(None), self.headers["json"]) 

109 

110 def list(self, givenTable): 

111 parts = givenTable.rsplit(".", 1) 

112 if len(parts) == 1: 

113 table = givenTable 

114 ext = "json" 

115 else: 

116 (table, ext) = parts 

117 if ext not in {"json", "tsv"}: 

118 serverprint(f"Invalid extension: {ext} in {givenTable}") 

119 return make_response(mjson(None), self.headers["json"]) 

120 

121 data = None 

122 if table is not None and table not in SENSITIVE_TABLES: 

123 if table == "contrib": 

124 data = self.getContribs(ext) 

125 else: 

126 context = self.context 

127 tableObj = Table(context, table) 

128 data = tableObj.wrap(None, logical=True) 

129 if data is None: 

130 serverprint(f"Non existing table requested: {table}") 

131 return make_response( 

132 mjson(data) if ext == "json" else mktsv(data), self.headers[ext] 

133 ) 

134 

135 def view(self, table, givenEid): 

136 record = None 

137 eid = castObjectId(givenEid) 

138 if table is not None and eid is not None and table not in SENSITIVE_TABLES: 

139 context = self.context 

140 tableObj = Table(context, table) 

141 recordObj = tableObj.record(eid=eid) 

142 record = recordObj.wrapLogical() 

143 if table == "contrib": 

144 extra = self.getExtra(record) 

145 for (k, v) in extra.items(): 

146 record[k] = v 

147 for k in SENSITIVE_FIELDS: 

148 if k in record: 

149 del record[k] 

150 k = "typeContribution" 

151 if k in record: 

152 record["type"] = record[k] 

153 del record[k] 

154 if record is None: 

155 serverprint(f"Non existing record requested: {table}/{givenEid}") 

156 return make_response(mjson(record), self.headers["json"]) 

157 

158 def getExtra(self, record): 

159 context = self.context 

160 wf = context.wf 

161 workflow = wf.computeWorkflow(record) 

162 

163 selected = G(workflow, N.selected) 

164 aStage = G(workflow, N.aStage) 

165 r2Stage = G(workflow, N.r2Stage) 

166 if r2Stage in {N.reviewAccept, N.reviewReject}: 

167 aStage = r2Stage 

168 score = G(workflow, N.score) 

169 assessed = ASSESSED_STATUS[aStage][0] 

170 aRank = (G(ASSESSED_RANK, aStage, default=0), score or 0) 

171 if aStage != N.reviewAccept: 

172 score = None 

173 

174 extra = { 

175 N.assessed: assessed, 

176 N.arank: aRank, 

177 N.astage: aStage, 

178 N.score: score, 

179 N.selected: selected, 

180 } 

181 preR1Stage = G(workflow, N.r1Stage) 

182 noReview = aStage is None or aStage in NO_REVIEW 

183 inReview = aStage in IN_REVIEW 

184 advReview = preR1Stage in ADVISORY_REVIEW 

185 r1Stage = ( 

186 "noReview" 

187 if noReview 

188 else preR1Stage 

189 if advReview 

190 else "inReview" 

191 if inReview 

192 else "skipReview" 

193 ) 

194 r2Stage = ( 

195 "noReview" 

196 if noReview 

197 else "inReview" 

198 if inReview 

199 else G(workflow, N.r2Stage) 

200 ) 

201 reviewed1 = REVIEWED_STATUS[r1Stage][0] 

202 reviewed2 = REVIEWED_STATUS[r2Stage][0] 

203 r1Rank = G(REVIEW_RANK, r1Stage, default=0) 

204 r2Rank = G(REVIEW_RANK, r2Stage, default=0) 

205 extra.update( 

206 { 

207 REVIEWED1: reviewed1, 

208 REVIEWED2: reviewed2, 

209 R1RANK: r1Rank, 

210 R2RANK: r2Rank, 

211 N.r1Stage: r1Stage, 

212 N.r2Stage: r2Stage, 

213 } 

214 ) 

215 return extra 

216 

217 def getContribs(self, ext): 

218 context = self.context 

219 db = context.db 

220 countryType = self.countryType 

221 yearType = self.yearType 

222 typeType = self.typeType 

223 

224 asTsv = ext == "tsv" 

225 

226 contribs = [] 

227 

228 if asTsv: 

229 contribsFull = {G(r, N._id): r for r in db.getList(N.contrib)} 

230 context = self.context 

231 tableObj = Table(context, N.contrib) 

232 

233 for record in db.bulkContribWorkflow(None, False): 

234 title = G(record, N.title) 

235 contribId = G(record, N._id) 

236 

237 selected = G(record, N.selected) 

238 aStage = G(record, N.aStage) 

239 r2Stage = G(record, N.r2Stage) 

240 if r2Stage in {N.reviewAccept, N.reviewReject}: 

241 aStage = r2Stage 

242 score = G(record, N.score) 

243 assessed = ASSESSED_STATUS[aStage][0] 

244 aRank = (G(ASSESSED_RANK, aStage, default=0), score or 0) 

245 if aStage != N.reviewAccept: 

246 score = None 

247 

248 countryRep = countryType.titleStr( 

249 G(db.country, G(record, N.country)), markup=None 

250 ) 

251 yearRep = yearType.titleStr(G(db.year, G(record, N.year)), markup=None) 

252 typeRep = typeType.titleStr( 

253 G(db.typeContribution, G(record, N.type)), markup=None 

254 ) 

255 

256 contribRecord = { 

257 N._id: contribId, 

258 N.country: countryRep, 

259 N.year: yearRep, 

260 N.type: typeRep, 

261 N.title: title, 

262 N.assessed: assessed, 

263 N.arank: aRank, 

264 N.astage: aStage, 

265 N.score: score, 

266 N.selected: selected, 

267 } 

268 preR1Stage = G(record, N.r1Stage) 

269 noReview = aStage is None or aStage in NO_REVIEW 

270 inReview = aStage in IN_REVIEW 

271 advReview = preR1Stage in ADVISORY_REVIEW 

272 r1Stage = ( 

273 "noReview" 

274 if noReview 

275 else preR1Stage 

276 if advReview 

277 else "inReview" 

278 if inReview 

279 else "skipReview" 

280 ) 

281 r2Stage = ( 

282 "noReview" 

283 if noReview 

284 else "inReview" 

285 if inReview 

286 else G(record, N.r2Stage) 

287 ) 

288 reviewed1 = REVIEWED_STATUS[r1Stage][0] 

289 reviewed2 = REVIEWED_STATUS[r2Stage][0] 

290 r1Rank = G(REVIEW_RANK, r1Stage, default=0) 

291 r2Rank = G(REVIEW_RANK, r2Stage, default=0) 

292 contribRecord.update( 

293 { 

294 REVIEWED1: reviewed1, 

295 REVIEWED2: reviewed2, 

296 R1RANK: r1Rank, 

297 R2RANK: r2Rank, 

298 N.r1Stage: r1Stage, 

299 N.r2Stage: r2Stage, 

300 } 

301 ) 

302 if asTsv: 

303 fullObj = tableObj.record(record=G(contribsFull, contribId, {})) 

304 full = fullObj.wrapLogical() 

305 contribRecord.update({ 

306 N.dateDecided: G(full, N.dateDecided), 

307 N.vcc: G(full, N.vcc), 

308 N.description: G(full, N.description), 

309 N.contactPersonName: G(full, N.contactPersonName), 

310 N.contactPersonEmail: G(full, N.contactPersonEmail), 

311 N.urlContribution: G(full, N.urlContribution), 

312 N.urlAcademic: G(full, N.urlAcademic), 

313 N.tadirahObject: G(full, N.tadirahObject), 

314 N.tadirahActivity: G(full, N.tadirahActivity), 

315 N.tadirahTechnique: G(full, N.tadirahTechnique), 

316 N.keyword: G(full, N.keyword), 

317 N.discipline: G(full, N.discipline), 

318 }) 

319 contribs.append(contribRecord) 

320 

321 return contribs