Coverage for portality/forms/application_forms.py: 82%

584 statements  

« prev     ^ index     » next       coverage.py v6.4.2, created at 2022-09-13 22:06 +0100

1""" 

2~~ApplicationForm:Feature~~ 

3""" 

4import datetime 

5from copy import deepcopy 

6 

7from wtforms import StringField, TextAreaField, IntegerField, BooleanField, RadioField, SelectMultipleField, \ 

8 SelectField, \ 

9 FormField, FieldList, HiddenField 

10from wtforms import widgets, validators 

11from wtforms.widgets.core import html_params, HTMLString 

12 

13from portality import constants 

14from portality import regex 

15from portality.core import app 

16from portality.crosswalks.application_form import ApplicationFormXWalk 

17from portality.crosswalks.journal_form import JournalFormXWalk 

18from portality.datasets import language_options, country_options, currency_options 

19from portality.forms import application_processors 

20from portality.forms.fields import TagListField, NestedFormField, UnconstrainedRadioField 

21from portality.forms.validate import ( 

22 HTTPURL, 

23 OptionalIf, 

24 MaxLen, 

25 RegexpOnTagList, 

26 StopWords, 

27 ISSNInPublicDOAJ, 

28 JournalURLInPublicDOAJ, 

29 DifferentTo, 

30 RequiredIfOtherValue, 

31 OnlyIf, 

32 NotIf, 

33 GroupMember, 

34 RequiredValue, 

35 BigEndDate, 

36 ReservedUsernames, 

37 CustomRequired, 

38 OwnerExists, NoScriptTag, Year 

39) 

40from portality.lib.formulaic import Formulaic, WTFormsBuilder 

41from portality.models import EditorGroup 

42from portality.regex import ISSN, ISSN_COMPILED 

43 

44# Stop words used in the keywords field 

45STOP_WORDS = [ 

46 "open access", 

47 "high quality", 

48 "peer-reviewed", 

49 "peer-review", 

50 "peer review", 

51 "peer reviewed", 

52 "quality", 

53 "medical journal", 

54 "multidisciplinary", 

55 "multi-disciplinary", 

56 "multi-disciplinary journal", 

57 "interdisciplinary", 

58 "inter disciplinary", 

59 "inter disciplinary research", 

60 "international journal", 

61 "journal", 

62 "scholarly journal", 

63 "open science", 

64 "impact factor", 

65 "scholarly", 

66 "research", 

67 "research journal" 

68] 

69 

70######################################################## 

71# Define all our individual fields 

72######################################################## 

73 

74class FieldDefinitions: 

75 # ~~->$ BOAI:FormField~~ 

76 BOAI = { 

77 "name": "boai", 

78 "label": "Does the journal adhere to DOAJ’s definition of open access?", 

79 "input": "radio", 

80 "options": [ 

81 {"display": "Yes", "value": "y"}, 

82 {"display": "No", "value": "n"} 

83 ], 

84 "help": { 

85 "long_help": ["See <a href='https://blog.doaj.org/2020/11/17/" 

86 "what-does-doaj-define-as-open-access/' " 

87 "target='_blank' rel='noopener'>" 

88 "DOAJ’s definition of open access explained " 

89 "in full</a>."], 

90 "doaj_criteria": "You must answer 'Yes'" 

91 }, 

92 "validate": [ 

93 {"required": {"message": "You must answer <strong>Yes</strong> to continue"}}, 

94 {"required_value" : {"value" : "y"}} 

95 ], 

96 "contexts": { 

97 "admin" : { 

98 "validate" : [] 

99 }, 

100 "editor": { 

101 "validate" : [], 

102 "disabled": True 

103 }, 

104 "associate_editor": { 

105 "validate" : [], 

106 "disabled": True 

107 } 

108 } 

109 } 

110 

111 # ~~->$ OAStatementURL:FormField~~ 

112 OA_STATEMENT_URL = { 

113 "name": "oa_statement_url", 

114 "label": "The journal website must display its open access statement. Where can we find this information?", 

115 "input": "text", 

116 "help": { 

117 "long_help": ["Here is an example of a suitable Open Access " 

118 "statement that meets our criteria: <blockquote>This" 

119 " is an open access journal which means that all " 

120 "content is freely available without charge to the " 

121 "user or his/her institution. Users are allowed to " 

122 "read, download, copy, distribute, print, search, or" 

123 " link to the full texts of the articles, or use " 

124 "them for any other lawful purpose, without asking " 

125 "prior permission from the publisher or the author. " 

126 "This is in accordance with the BOAI definition of " 

127 "open access.</blockquote>"], 

128 "short_help": "Link to the journal’s open access statement", 

129 "placeholder": "https://www.my-journal.com/open-access" 

130 }, 

131 "validate": [ 

132 {"required": {"message": "Enter the URL for the journal’s Open Access statement page"}}, 

133 "is_url" # ~~^->IsURL:FormValidator~~ 

134 ], 

135 "widgets": [ 

136 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

137 "clickable_url" # ~~^-> ClickableURL:FormWidget~~ 

138 ], 

139 "attr": { 

140 "type": "url" 

141 } 

142 } 

143 

144 #~~->$ Title:FormField~~ 

145 TITLE = { 

146 "name": "title", 

147 "label": "Journal title", 

148 "input": "text", 

149 "help": { 

150 "long_help": ["The journal title must match what is displayed on the website and what is registered at the " 

151 "<a href='https://portal.issn.org/' target='_blank' rel='noopener'> ISSN Portal</a>.", 

152 "For translated titles, you may add the " 

153 "translation as an alternative title."], 

154 "placeholder": "Journal title", 

155 "doaj_criteria": "Title in application form, title at ISSN and website must all match" 

156 }, 

157 "validate": [ 

158 {"required": {"message": "Enter the journal’s name"}}, 

159 "no_script_tag" # ~~^-> NoScriptTag:FormValidator 

160 ], 

161 "widgets": [ 

162 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

163 "full_contents" # ~~^->FullContents:FormWidget~~ 

164 ], 

165 "contexts": { 

166 "editor": { 

167 "disabled": True 

168 }, 

169 "associate_editor": { 

170 "disabled": True 

171 }, 

172 "update_request": { 

173 "disabled": True 

174 } 

175 } 

176 } 

177 

178 # ~~->$ AlternativeTitle:FormField~~ 

179 ALTERNATIVE_TITLE = { 

180 "name": "alternative_title", 

181 "label": "Alternative title (including translation of the title)", 

182 "input": "text", 

183 "optional": True, 

184 "help": { 

185 "placeholder": "Ma revue" 

186 }, 

187 "validate": [ 

188 "no_script_tag" # ~~^-> NoScriptTag:FormValidator 

189 ], 

190 "widgets": [ 

191 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

192 {"full_contents" : {"empty_disabled" : "[The journal has no alternative title]"}} # ~~^->FullContents:FormWidget~~ 

193 ], 

194 "contexts": { 

195 "update_request": { 

196 "disabled": True 

197 } 

198 } 

199 } 

200 

201 # ~~->$ JournalURL:FormField~~ 

202 JOURNAL_URL = { 

203 "name": "journal_url", 

204 "label": "Link to the journal’s homepage", 

205 "input": "text", 

206 "validate": [ 

207 "required", 

208 "is_url" # ~~^->IsURL:FormValidator~~ 

209 ], 

210 "widgets": [ 

211 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

212 "clickable_url" # ~~^-> ClickableURL:FormWidget~~ 

213 ], 

214 "help": { 

215 "placeholder": "https://www.my-journal.com" 

216 }, 

217 "contexts": { 

218 "public" : { 

219 "validate": [ 

220 {"required": {"message": "Enter the URL for the journal’s <strong>homepage</strong>"}}, 

221 "is_url", # ~~^->IsURL:FormValidator~~ 

222 "journal_url_in_public_doaj" # ~~^-> JournalURLInPublicDOAJ:FormValidator~~ 

223 ], 

224 } 

225 } 

226 } 

227 

228 #~~->$ PISSN:FormField~~ 

229 PISSN = { 

230 "name": "pissn", 

231 "label": "ISSN (print)", 

232 "input": "text", 

233 "help": { 

234 "long_help": ["Must be a valid ISSN, fully registered and confirmed at the " 

235 "<a href='https://portal.issn.org/' target='_blank' rel='noopener'> ISSN Portal.</a>", 

236 "The ISSN must match what is given on the journal website."], 

237 "short_help": "For example, 2049-3630", 

238 "doaj_criteria": "ISSN must be provided" 

239 }, 

240 "validate": [ 

241 {"optional_if": {"field": "eissn", # ~~^-> OptionalIf:FormValidator~~ 

242 "message": "You must provide <strong>one or both</strong> of an online ISSN or a print ISSN"}}, 

243 {"is_issn": {"message": "This is not a valid ISSN"}}, # ~~^-> IsISSN:FormValidator~~ 

244 {"different_to": {"field": "eissn", "message": "This field must contain a different value to 'ISSN (" 

245 "online)'"}} # ~~^-> DifferetTo:FormValidator~~ 

246 ], 

247 "widgets" : [ 

248 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

249 "full_contents" # ~~^->FullContents:FormWidget~~ 

250 ], 

251 "contexts": { 

252 "public" : { 

253 "validate": [ 

254 {"optional_if": {"field": "eissn", # ~~^-> OptionalIf:FormValidator~~ 

255 "message": "You must provide <strong>one or both</strong> of an online ISSN or a print ISSN"}}, 

256 {"is_issn": {"message": "This is not a valid ISSN"}}, # ~~^-> IsISSN:FormValidator~~ 

257 {"different_to": {"field": "eissn", 

258 "message": "This field must contain a different value to 'ISSN (" 

259 "online)'"}}, # ~~^-> DifferetTo:FormValidator~~ 

260 "issn_in_public_doaj" 

261 ], 

262 }, 

263 "admin" : { 

264 "help": { 

265 "long_help": ["Must be a valid ISSN, fully registered and confirmed at the " 

266 "<a href='https://portal.issn.org/' target='_blank' rel='noopener'> ISSN Portal</a>", 

267 "The ISSN must match what is given on the journal website."], 

268 "placeholder": "", 

269 "doaj_criteria": "ISSN must be provided" 

270 } 

271 }, 

272 "editor": { 

273 "disabled": True, 

274 "help": { 

275 "long_help": ["Must be a valid ISSN, fully registered and confirmed at the " 

276 "<a href='https://portal.issn.org/' target='_blank' rel='noopener'> ISSN Portal.</a>", 

277 "The ISSN must match what is given on the journal website."], 

278 "placeholder": "", 

279 "doaj_criteria": "ISSN must be provided" 

280 }, 

281 }, 

282 "associate_editor": { 

283 "disabled": True, 

284 "help": { 

285 "long_help": ["Must be a valid ISSN, fully registered and confirmed at the " 

286 "<a href='https://portal.issn.org/' target='_blank' rel='noopener'> ISSN Portal.</a>", 

287 "The ISSN must match what is given on the journal website."], 

288 "placeholder": "", 

289 "doaj_criteria": "ISSN must be provided" 

290 } 

291 }, 

292 "update_request": { 

293 "disabled": True 

294 } 

295 } 

296 } 

297 

298 #~~->$ EISSN:FormField~~ 

299 EISSN = { 

300 "name": "eissn", 

301 "label": "ISSN (online)", 

302 "input": "text", 

303 "help": { 

304 "long_help": ["Must be a valid ISSN, fully registered and confirmed at the " 

305 "<a href='https://portal.issn.org/' target='_blank' rel='noopener'> ISSN Portal</a>", 

306 "The ISSN must match what is given on the journal website."], 

307 "short_help": "For example, 0378-5955", 

308 "doaj_criteria": "ISSN must be provided" 

309 }, 

310 "validate": [ 

311 {"optional_if": {"field": "pissn", # ~~^-> OptionalIf:FormValidator~~ 

312 "message": "You must provide <strong>one or both</strong> of an online ISSN or a print ISSN"}}, 

313 {"is_issn": {"message": "This is not a valid ISSN"}}, # ~~^-> IsISSN:FormValidator~~ 

314 {"different_to": {"field": "pissn", "message" : "This field must contain a different value to 'ISSN (print)'"}} # ~~^-> DifferetTo:FormValidator~~ 

315 ], 

316 "widgets" : [ 

317 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

318 "full_contents" # ~~^->FullContents:FormWidget~~ 

319 ], 

320 "contexts": { 

321 "public" : { 

322 "validate" : [ 

323 {"optional_if": {"field": "pissn", # ~~^-> OptionalIf:FormValidator~~ 

324 "message": "You must provide <strong>one or both</strong> of an online ISSN or a print ISSN"}}, 

325 {"is_issn": {"message": "This is not a valid ISSN"}}, # ~~^-> IsISSN:FormValidator~~ 

326 {"different_to": {"field": "pissn", 

327 "message": "This field must contain a different value to 'ISSN (print)'"}}, # ~~^-> DifferetTo:FormValidator~~ 

328 "issn_in_public_doaj" 

329 ] 

330 }, 

331 "admin" : { 

332 "help": { 

333 "long_help": ["Must be a valid ISSN, fully registered and confirmed at the " 

334 "<a href='https://portal.issn.org/' target='_blank' rel='noopener'> ISSN Portal</a>", 

335 "The ISSN must match what is given on the journal website."], 

336 "placeholder": "", 

337 "doaj_criteria": "ISSN must be provided" 

338 } 

339 }, 

340 "editor": { 

341 "disabled": True, 

342 "help": { 

343 "long_help": ["Must be a valid ISSN, fully registered and confirmed at the " 

344 "<a href='https://portal.issn.org/' target='_blank' rel='noopener'> ISSN Portal.</a>", 

345 "The ISSN must match what is given on the journal website."], 

346 "placeholder": "", 

347 "doaj_criteria": "ISSN must be provided" 

348 }, 

349 }, 

350 "associate_editor": { 

351 "disabled": True, 

352 "help": { 

353 "long_help": ["Must be a valid ISSN, fully registered and confirmed at the " 

354 "<a href='https://portal.issn.org/' target='_blank' rel='noopener'> ISSN Portal.</a>", 

355 "The ISSN must match what is given on the journal website."], 

356 "placeholder": "", 

357 "doaj_criteria": "ISSN must be provided" 

358 } 

359 }, 

360 "update_request": { 

361 "disabled": True, 

362 "validate" : [ 

363 {"optional_if": {"field": "pissn", # ~~^-> OptionalIf:FormValidator~~ 

364 "message": "You must provide <strong>one or both</strong> of an online ISSN or a print ISSN"}}, 

365 {"is_issn": {"message": "This is not a valid ISSN"}}, # ~~^-> IsISSN:FormValidator~~ 

366 {"different_to": {"field": "pissn", # ~~^-> DifferetTo:FormValidator~~ 

367 "message": "This field must contain a different value to 'ISSN (print)'"}} 

368 ] 

369 } 

370 } 

371 } 

372 

373 # ~~->$ Keywords:FormField~~ 

374 KEYWORDS = { 

375 "name": "keywords", 

376 "label": "Up to 6 subject keywords in English", 

377 "input": "taglist", 

378 "help": { 

379 "long_help": ["Choose upto 6 keywords that describe the subject matter of the journal. " 

380 "Keywords must be in English.", "Use single words or short phrases (2 to 3 words) " 

381 "that describe the journal's main topic.", "Do not add acronyms, abbreviations or descriptive sentences.", 

382 "Note that the keywords may be edited by DOAJ editorial staff." ], 

383 }, 

384 "validate": [ 

385 {"required": {"message": "Enter at least <strong>one subject keyword</strong> in English"}}, 

386 {"stop_words": {"disallowed": STOP_WORDS}}, # ~~^->StopWords:FormValidator~~ 

387 {"max_tags": {"max": 6}} 

388 ], 

389 "postprocessing": [ 

390 "to_lower" # FIXME: this might just be a feature of the crosswalk 

391 ], 

392 "widgets": [ 

393 { 

394 "taglist": { 

395 "maximumSelectionSize": 6, 

396 "stopWords": STOP_WORDS, 

397 "field": "bibjson.keywords" 

398 } 

399 } 

400 ], 

401 "attr": { 

402 "class": "input-xlarge" 

403 } 

404 } 

405 

406 # ~~->$ Language:FormField~~ 

407 LANGUAGE = { 

408 "name": "language", 

409 "label": "Languages in which the journal accepts manuscripts", 

410 "input": "select", 

411 "default" : "", 

412 "options_fn": "iso_language_list", 

413 "repeatable": { 

414 "minimum" : 1, 

415 "initial": 5 

416 }, 

417 "validate": [ 

418 {"required": {"message": "Enter <strong>at least one</strong> language"}} 

419 ], 

420 "widgets": [ 

421 {"select": {}}, 

422 "multiple_field" 

423 ], 

424 "help": { 

425 "placeholder": "Type or select the language" 

426 }, 

427 "attr": { 

428 "class": "input-xlarge unstyled-list" 

429 } 

430 } 

431 

432 # ~~->$ PublisherName:FormField~~ 

433 PUBLISHER_NAME = { 

434 "name": "publisher_name", 

435 "label": "Publisher’s name", 

436 "input": "text", 

437 "validate": [ 

438 {"required": {"message": "Enter the name of the journal’s publisher"}} 

439 ], 

440 "widgets": [ 

441 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

442 {"autocomplete": {"type" : "journal", "field": "bibjson.publisher.name.exact"}}, 

443 "full_contents" # ~~^->FullContents:FormWidget~~ 

444 ], 

445 "help": { 

446 "placeholder": "Type or select the publisher’s name" 

447 }, 

448 "contexts" : { 

449 "bulk_edit" : { 

450 "validate" : [] 

451 } 

452 } 

453 } 

454 

455 # ~~->$ PublisherCountry:FormField~~ 

456 PUBLISHER_COUNTRY = { 

457 "name": "publisher_country", 

458 "label": "Publisher’s country", 

459 "input": "select", 

460 "default": "", 

461 "options_fn": "iso_country_list", 

462 "help": { 

463 "long_help": ["The country where the publisher carries out its business operations and is registered."], 

464 "doaj_criteria": "You must provide a publisher country", 

465 "placeholder": "Type or select the country" 

466 }, 

467 "validate": [ 

468 {"required": {"message": "Enter the <strong>country</strong> where the publisher carries out its business operations and is registered"}} 

469 ], 

470 "widgets": [ 

471 {"select": {}} 

472 ], 

473 "attr": { 

474 "class": "input-xlarge" 

475 }, 

476 "contexts": { 

477 "associate_editor": { 

478 "disabled": True 

479 }, 

480 "bulk_edit" : { 

481 "validate" : [] 

482 } 

483 } 

484 } 

485 

486 # ~~->$ InstitutionName:FormField~~ 

487 INSTITUTION_NAME = { 

488 "name": "institution_name", 

489 "label": "Society or institution’s name", 

490 "input": "text", 

491 "optional": True, 

492 "help": { 

493 "short_help": "The society or institution responsible for the journal", 

494 "long_help": ["Some societies or institutions are linked to a journal in some way but are not responsible " 

495 "for publishing it. The publisher can be a separate organisation. If your journal is linked to " 

496 "a society or other type of institution, enter that here."], 

497 "placeholder": "Type or select the society or institution’s name" 

498 }, 

499 "widgets": [ 

500 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

501 {"autocomplete": {"type" : "journal", "field": "bibjson.institution.name.exact"}}, 

502 "full_contents" # ~~^->FullContents:FormWidget~~ 

503 ] 

504 } 

505 

506 # ~~->$ InstitutionCountry:FormField~~ 

507 INSTITUTION_COUNTRY = { 

508 "name": "institution_country", 

509 "label": "Society or institution’s country", 

510 "input": "select", 

511 "default" : "", 

512 "options_fn": "iso_country_list", 

513 "optional": True, 

514 "help": { 

515 "short_help": "The country in which the society or institution is based", 

516 "placeholder": "Type or select the country" 

517 }, 

518 "widgets": [ 

519 {"select": {"allow_clear" : True}} 

520 ], 

521 "attr": { 

522 "class": "input-xlarge" 

523 } 

524 } 

525 

526 # ~~->$ License:FormField~~ 

527 LICENSE = { 

528 "name": "license", 

529 "label": "License(s) permitted by the journal", 

530 "input": "checkbox", 

531 "multiple": True, 

532 "options": [ 

533 {"display": "CC BY", "value": "CC BY"}, 

534 {"display": "CC BY-SA", "value": "CC BY-SA"}, 

535 {"display": "CC BY-ND", "value": "CC BY-ND"}, 

536 {"display": "CC BY-NC", "value": "CC BY-NC"}, 

537 {"display": "CC BY-NC-SA", "value": "CC BY-NC-SA"}, 

538 {"display": "CC BY-NC-ND", "value": "CC BY-NC-ND"}, 

539 {"display": "CC0", "value": "CC0"}, 

540 {"display": "Public domain", "value": "Public domain"}, 

541 {"display": "Publisher's own license", "value": "Publisher's own license", "subfields": ["license_attributes"]}, 

542 ], 

543 "help": { 

544 "long_help": ["The journal must use some form of licensing to be considered for indexing in DOAJ. ", 

545 "If Creative Commons licensing is not used, then select <em>Publisher's own license</em> and enter " 

546 "more details below.", 

547 "More information on CC licenses: <br/>" 

548 "<a href='https://creativecommons.org/licenses/by/4.0/" 

549 "' target='_blank' 'rel='noopener'>CC BY</a> <br/>" 

550 "<a href='https://creativecommons.org/licenses/by-sa/4.0/" 

551 "' target='_blank' 'rel='noopener'>CC BY-SA</a> <br/>" 

552 "<a href='https://creativecommons.org/licenses/by-nd/4.0/" 

553 "' target='_blank' 'rel='noopener'>CC BY-ND</a> <br/>" 

554 "<a href='https://creativecommons.org/licenses/by-nc/4.0/" 

555 "' target='_blank' 'rel='noopener'>CC BY-NC</a> <br/>" 

556 "<a href='https://creativecommons.org/licenses/by-nc-sa/4.0/" 

557 "' target='_blank' 'rel='noopener'>CC BY-NC-SA</a> <br/>" 

558 "<a href='https://creativecommons.org/licenses/by-nc-nd/4.0/" 

559 "' target='_blank' 'rel='noopener'>CC BY-NC-ND</a>", 

560 "<a href='https://wiki.creativecommons.org/wiki/CC0_" 

561 "FAQ#What_is_the_difference_between_CC0_and_the_Publ" 

562 "ic_Domain_Mark_.28.22PDM.22.29.3F' target='_blank' " 

563 "rel='noopener'>What is the difference between CC0 " 

564 "and the Public Domain Mark (\"PDM\")?</a>"], 

565 "doaj_criteria": "Content must be licensed", 

566 "seal_criteria": "Yes: CC BY, CC BY-SA, CC BY-NC" 

567 }, 

568 "validate": [ 

569 {"required": {"message": "Select <strong>at least one</strong> type of license"}} 

570 ] 

571 } 

572 

573 # ~~->$ LicenseAttributes:FormField~~ 

574 LICENSE_ATTRIBUTES = { 

575 "name": "license_attributes", 

576 "label": "Select all the attributes that your license has", 

577 "input": "checkbox", 

578 "multiple": True, 

579 "conditional": [ 

580 {"field": "license", "value": "Publisher's own license"} 

581 ], 

582 "options": [ 

583 {"display": "Attribution", "value": "BY"}, 

584 {"display": "Share Alike", "value": "SA"}, 

585 {"display": "No Derivatives", "value": "ND"}, 

586 {"display": "No Commercial Usage", "value": "NC"} 

587 ], 

588 "help": { 

589 "doaj_criteria": "Content must be licensed" 

590 } 

591 } 

592 

593 # ~~->$ LicenseTermsURL:FormField~~ 

594 LICENSE_TERMS_URL = { 

595 "name": "license_terms_url", 

596 "label": "Where can we find this information?", 

597 "input": "text", 

598 "diff_table_context": "License terms", 

599 "validate": [ 

600 {"required": {"message": "Enter the URL for the journal’s <strong>license terms</strong> page"}}, 

601 "is_url" # ~~^->IsURL:FormValidator~~ 

602 ], 

603 "help": { 

604 "short_help": "Link to the page where the license terms are stated on your site.", 

605 "doaj_criteria": "You must provide a link to your license terms", 

606 "placeholder": "https://www.my-journal.com/about#licensing", 

607 }, 

608 "widgets": [ 

609 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

610 "clickable_url" # ~~^-> ClickableURL:FormWidget~~ 

611 ] 

612 } 

613 

614 # ~~->$ LicenseDisplay:FormField~~ 

615 LICENSE_DISPLAY = { 

616 "name": "license_display", 

617 "label": "Does the journal embed and/or display licensing information in its articles?", 

618 "input": "radio", 

619 "options": [ 

620 {"display": "Yes", "value": "y", "subfields": ["license_display_example_url"]}, 

621 {"display": "No", "value": "n"} 

622 ], 

623 "help": { 

624 "long_help": ["It is recommended that licensing information is included in full-text articles " 

625 "but it is not required for inclusion. " 

626 "Answer <strong>Yes</strong> if licensing is displayed or " 

627 "embedded in all versions of each article."], 

628 "seal_criteria": "If the answer is Embed" 

629 }, 

630 "validate": [ 

631 {"required": {"message": "Select Yes or No"}} 

632 ] 

633 } 

634 

635 #~~->$ LicenseDisplayExampleUrl:FormField~~ 

636 LICENSE_DISPLAY_EXAMPLE_URL = { 

637 "name": "license_display_example_url", 

638 "label": "Recent article displaying or embedding a license in the full text", 

639 "input": "text", 

640 "conditional": [ 

641 {"field": "license_display", "value": "y"} 

642 ], 

643 "help": { 

644 "short_help": "Link to an example article", 

645 "placeholder": "https://www.my-journal.com/articles/article-page" 

646 }, 

647 "validate": [ 

648 {"required_if": { 

649 "field": "license_display", 

650 "value": "y", 

651 "message": "Enter the URL for any recent article that displays or embeds a license" 

652 } 

653 }, 

654 "is_url" # ~~^->IsURL:FormValidator~~ 

655 ], 

656 "widgets": [ 

657 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

658 "clickable_url" # ~~^-> ClickableURL:FormWidget~~ 

659 ] 

660 } 

661 

662 # ~~->$ CopyrightAuthorRetails:FormField~~ 

663 COPYRIGHT_AUTHOR_RETAINS = { 

664 "name": "copyright_author_retains", 

665 "label": "For all the licenses you have indicated above, do authors retain the copyright " 

666 "<b>and</b> full publishing rights without restrictions?", 

667 "input": "radio", 

668 "options": [ 

669 {"display": "Yes", "value": "y"}, 

670 {"display": "No", "value": "n"} 

671 ], 

672 "validate": [ 

673 {"required": {"message": "Select Yes or No"}} 

674 ], 

675 "help": { 

676 "long_help": ["Answer <strong>No</strong> if authors transfer " 

677 "copyright or assign exclusive rights to the publisher" 

678 " (including commercial rights). <br/><br/> Answer " 

679 "<strong>Yes</strong> only if authors publishing " 

680 "under any license allowed by the journal " 

681 "retain all rights."], 

682 "seal_criteria": "The author must retain the copyright" 

683 } 

684 } 

685 

686 # ~~->$ CopyrightURL:FormField~~ 

687 COPYRIGHT_URL = { 

688 "name": "copyright_url", 

689 "label": "Where can we find this information?", 

690 "input": "text", 

691 "diff_table_context": "Copyright terms", 

692 "help": { 

693 "short_help": "Link to the journal’s copyright terms" 

694 }, 

695 "placeholder": "https://www.my-journal.com/about#licensing", 

696 "validate": [ 

697 "is_url" # ~~^->IsURL:FormValidator~~ 

698 ], 

699 "widgets": [ 

700 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

701 "clickable_url" # ~~^-> ClickableURL:FormWidget~~ 

702 ], 

703 "contexts": { 

704 "public": { 

705 "validate": [ 

706 {"required": {"message": "Enter the URL for the journal’s <strong>copyright terms</strong> page"}}, 

707 "is_url" # ~~^->IsURL:FormValidator~~ 

708 ] 

709 }, 

710 "update_request": { 

711 "validate": [ 

712 "required", 

713 "is_url" # ~~^->IsURL:FormValidator~~ 

714 ] 

715 } 

716 } 

717 } 

718 

719 # ~~->$ ReviewProcess:FormField~~ 

720 REVIEW_PROCESS = { 

721 "name": "review_process", 

722 "label": "DOAJ only accepts peer-reviewed journals. " 

723 "Which type(s) of peer review does this journal use?", 

724 "input": "checkbox", 

725 "multiple": True, 

726 "options": [ 

727 {"display": "Editorial review", "value": "Editorial review"}, 

728 {"display": "Peer review", "value": "Peer review"}, 

729 {"display": "Blind peer review", "value": "Blind peer review"}, 

730 {"display": "Double blind peer review", "value": "Double blind peer review"}, 

731 {"display": "Post-publication peer review", "value": "Post-publication peer review"}, 

732 {"display": "Open peer review", "value": "Open peer review"}, 

733 {"display": "Other", "value": "other", "subfields": ["review_process_other"]} 

734 ], 

735 "help": { 

736 "long_help": ["Enter all types of review used by the journal for " 

737 "research articles. Note that editorial review is " 

738 "only accepted for arts and humanities journals."], 

739 "doaj_criteria": "Peer review must be carried out" 

740 }, 

741 "validate": [ 

742 {"required": {"message": "Select <strong>at least one</strong> type of review process"}} 

743 ] 

744 } 

745 

746 # ~~->$ ReviewProcessOther:FormField~~ 

747 REVIEW_PROCESS_OTHER = { 

748 "name": "review_process_other", 

749 "label": "Other peer review", 

750 "input": "text", 

751 "help": { 

752 "placeholder": "Other peer review" 

753 }, 

754 "conditional": [{"field": "review_process", "value": "other"}], 

755 "validate": [ 

756 {"required_if": { 

757 "field": "review_process", 

758 "value": "other", 

759 "message": "Enter the name of another type of peer review" 

760 } 

761 } 

762 ], 

763 "widgets" : [ 

764 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

765 ], 

766 "asynchronous_warning": [ 

767 {"warn_on_value": {"value": "None"}} 

768 ] 

769 } 

770 

771 # ~~->$ ReviewURL:FormField~~ 

772 REVIEW_URL = { 

773 "name": "review_url", 

774 "label": "Where can we find this information?", 

775 "input": "text", 

776 "diff_table_context": "Peer review policy", 

777 "help": { 

778 "doaj_criteria": "You must provide a URL", 

779 "short_help": "Link to the journal’s peer review policy" 

780 }, 

781 "validate": [ 

782 {"required": {"message": "Enter the URL for the journal’s <strong>peer review policy</strong> page"}}, 

783 "is_url" # ~~^->IsURL:FormValidator~~ 

784 ], 

785 "widgets": [ 

786 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

787 "clickable_url" # ~~^-> ClickableURL:FormWidget~~ 

788 ] 

789 } 

790 

791 # ~~->$ OAStart:FormField~~ 

792 OA_START = { 

793 "name": "oa_start", 

794 "label": "When did the journal start to publish all content using an open license?", 

795 "input": "number", 

796 "datatype": "integer", 

797 "help": { 

798 "long_help": ["Please enter the year that the journal started to publish all content as true open access, according to DOAJ's <a href='https://blog.doaj.org/2020/11/17/what-does-doaj-define-as-open-access/' target='_blank' rel='nofollow'>definition</a>.", 

799 "For journals that have flipped to open access, enter the year that the journal flipped, not the original launch date of the journal.", 

800 "For journals that have made digitised backfiles freely available, enter the year that the journal started publishing as a fully open access title, not the date of the earliest free content."] 

801 }, 

802 "validate": [ 

803 {"required": {"message": "Enter the Year (YYYY)."}}, 

804 {"int_range": {"gte": app.config.get('MINIMAL_OA_START_DATE', 1900), "lte": datetime.datetime.utcnow().year}}, 

805 {"year": {"message": "OA Start Date must be a year in a 4 digit format (eg. 1987) and must be greater than {}".format(app.config.get('MINIMAL_OA_START_DATE', 1900))}} 

806 ], 

807 "attr": { 

808 "min": app.config.get('MINIMAL_OA_START_DATE', 1900), 

809 "max": datetime.datetime.utcnow().year 

810 } 

811 } 

812 

813 # ~~->$ PlagiarismDetection:FormField~~ 

814 PLAGIARISM_DETECTION = { 

815 "name": "plagiarism_detection", 

816 "label": "Does the journal routinely screen article submissions for plagiarism?", 

817 "input": "radio", 

818 "help": { 

819 "long_help": ["Screening for plagiarism is recommended, but is not" 

820 " a requirement for inclusion in DOAJ. If the " 

821 "journal does screen for plagiarism, state the " 

822 "services(s) used on your website."], 

823 }, 

824 "options": [ 

825 {"display": "Yes", "value": "y", "subfields": ["review_process_other"]}, 

826 {"display": "No", "value": "n"} 

827 ], 

828 "validate": [ 

829 {"required": {"message": "Select Yes or No"}} 

830 ] 

831 } 

832 

833 #~~->$ PlagiarismURL:FormField~~ 

834 PLAGIARISM_URL = { 

835 "name": "plagiarism_url", 

836 "label": "Where can we find this information?", 

837 "diff_table_context": "Plagiarism screening", 

838 "input": "text", 

839 "conditional": [{"field": "plagiarism_detection", "value": "y"}], 

840 "help": { 

841 "doaj_criteria": "You must provide a URL", 

842 "placeholder": "https://www.my-journal.com/about#plagiarism", 

843 "short_help": "Link to the journal’s plagiarism policy", 

844 "long_help": ["The page should state that the journal actively checks for plagiarism and explain how this " 

845 "is done (including the name of any software or service used)."] 

846 }, 

847 "validate": [ 

848 {"required_if": { 

849 "field": "plagiarism_detection", 

850 "value": "y", 

851 "message": "Enter the URL for the journal’s <strong>plagiarism policy</strong> page" 

852 } 

853 }, 

854 "is_url" # ~~^->IsURL:FormValidator~~ 

855 ], 

856 "widgets": [ 

857 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

858 "clickable_url" # ~~^-> ClickableURL:FormWidget~~ 

859 ] 

860 } 

861 

862 # ~~->$ AimsScopeURL:FormField~~ 

863 AIMS_SCOPE_URL = { 

864 "name": "aims_scope_url", 

865 "label": "Link to the journal’s <b>Aims & Scope</b>", 

866 "input": "text", 

867 "help": { 

868 "doaj_criteria": "You must provide a URL", 

869 "placeholder": "https://www.my-journal.com/about#aims" 

870 }, 

871 "validate": [ 

872 {"required": {"message": "Enter the URL for the journal’s <strong>Aims & Scope</strong> page"}}, 

873 "is_url" # ~~^->IsURL:FormValidator~~ 

874 ], 

875 "widgets": [ 

876 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

877 "clickable_url" # ~~^-> ClickableURL:FormWidget~~ 

878 ] 

879 } 

880 

881 # ~~->$ EditorialBoardURL:FormField~~ 

882 EDITORIAL_BOARD_URL = { 

883 "name": "editorial_board_url", 

884 "label": "Link to the journal’s <b>Editorial Board</b>", 

885 "input": "text", 

886 "help": { 

887 "doaj_criteria": "You must provide a URL", 

888 "placeholder": "https://www.my-journal.com/about#board" 

889 }, 

890 "validate": [ 

891 {"required": {"message": "Enter the URL for the journal’s <strong>Editorial Board</strong> page"}}, 

892 "is_url" # ~~^->IsURL:FormValidator~~ 

893 ], 

894 "widgets": [ 

895 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

896 "clickable_url" # ~~^-> ClickableURL:FormWidget~~ 

897 ] 

898 } 

899 

900 # ~~->$ AuthorInstructionsURL:FormField~~ 

901 AUTHOR_INSTRUCTIONS_URL = { 

902 "name": "author_instructions_url", 

903 "label": "Link to the journal’s <b>Instructions for Authors</b>", 

904 "input": "text", 

905 "help": { 

906 "doaj_criteria": "You must provide a URL", 

907 "placeholder": "https://www.my-journal.com/for_authors" 

908 }, 

909 "validate": [ 

910 {"required": {"message": "Enter the URL for the journal’s <strong>Instructions for Authors</strong> page"}}, 

911 "is_url" # ~~^->IsURL:FormValidator~~ 

912 ], 

913 "widgets": [ 

914 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

915 "clickable_url" # ~~^-> ClickableURL:FormWidget~~ 

916 ] 

917 } 

918 

919 # ~~->$ PublicationTimeWeeks:FormField~~ 

920 PUBLICATION_TIME_WEEKS = { 

921 "name": "publication_time_weeks", 

922 "label": "Average number of <strong>weeks</strong> between article submission & publication", 

923 "input": "number", 

924 "datatype": "integer", 

925 "validate": [ 

926 {"required": {"message": "Enter an average number of weeks"}}, 

927 {"int_range": {"gte": 1, "lte": 100}} 

928 ], 

929 "asynchronous_warning": [ 

930 {"int_range": {"lte": 2}} 

931 ], 

932 "attr": { 

933 "min": "1", 

934 "max": "100" 

935 } 

936 } 

937 

938 # ~~->$ APC:FormField~~ 

939 APC = { 

940 "name": "apc", 

941 "label": "Does the journal charge fees for publishing an article (APCs)?", 

942 "input": "radio", 

943 "options": [ 

944 {"display": "Yes", "value": "y", "subfields": ["apc_charges"]}, 

945 {"display": "No", "value": "n"} 

946 ], 

947 "help": { 

948 "long_help": ["Publication fees are sometimes called " 

949 "article processing charges (APCs). You should answer" 

950 " Yes if any fee is required from the author for " 

951 "publishing their paper."], 

952 "doaj_criteria": "You must tell us about any APCs" 

953 }, 

954 "validate": [ 

955 {"required": {"message": "Select Yes or No"}} 

956 ] 

957 } 

958 

959 # ~~->$ APCCharges:FormField~~ 

960 APC_CHARGES = { 

961 "name": "apc_charges", 

962 "input": "group", 

963 "label": "Highest fee charged", 

964 "repeatable": { 

965 "minimum": 1, 

966 "initial": 5 

967 }, 

968 "conditional": [ 

969 {"field": "apc", "value": "y"} 

970 ], 

971 "help": { 

972 "long_help": [" If the journal charges a range of fees for " 

973 "publication of an article, enter the highest fee. " 

974 "If the fee can be paid in more than one currency, " 

975 "you may list them here."] 

976 }, 

977 "subfields": [ 

978 "apc_currency", 

979 "apc_max" 

980 ], 

981 "template": "application_form/_list.html", 

982 "entry_template": "application_form/_entry_group_horizontal.html", 

983 "widgets": [ 

984 "multiple_field" 

985 ] 

986 } 

987 

988 # ~~->$ APCCurrency:FormField~~ 

989 APC_CURRENCY = { 

990 "subfield": True, 

991 "group": "apc_charges", 

992 "name": "apc_currency", 

993 "input": "select", 

994 "options_fn": "iso_currency_list", 

995 "default": "", 

996 "help": { 

997 "placeholder": "Currency" 

998 }, 

999 "widgets": [ 

1000 {"select": {}} 

1001 ], 

1002 "attr": { 

1003 "class": "input-xlarge" 

1004 }, 

1005 "validate": [ 

1006 {"required_if": { 

1007 "field": "apc", 

1008 "value": "y", 

1009 "message": "Enter the currency or currencies for the journal’s publishing fees" 

1010 } 

1011 } 

1012 ] 

1013 } 

1014 

1015 # ~~->$ APCMax:FormField~~ 

1016 APC_MAX = { 

1017 "subfield": True, 

1018 "group": "apc_charges", 

1019 "name": "apc_max", 

1020 "input": "number", 

1021 "datatype": "integer", 

1022 "help": { 

1023 "placeholder": "Highest fee charged" 

1024 }, 

1025 "validate":[ 

1026 {"required_if": { 

1027 "field": "apc", 

1028 "value": "y", 

1029 "message": "Enter the value of the highest publishing fee the journal has charged" 

1030 } 

1031 } 

1032 ], 

1033 "attr": { 

1034 "min": "1" 

1035 } 

1036 } 

1037 

1038 # ~~->$ APCURL:FormField~~ 

1039 APC_URL = { 

1040 "name": "apc_url", 

1041 "label": "Where can we find this information?", 

1042 "diff_table_context": "Publication fees", 

1043 "input": "text", 

1044 "help": { 

1045 "short_help": "Link to the page where this is stated. The page " 

1046 "must declare <b>whether or not</b> there is a fee " 

1047 "to publish an article in the journal.", 

1048 "doaj_criteria": "You must provide a URL", 

1049 "placeholder": "https://www.my-journal.com/about#apc" 

1050 }, 

1051 "validate": [ 

1052 {"required": {"message": "Enter the URL for the journal’s <strong>publication fees</strong> information page"}}, 

1053 "is_url" # ~~^->IsURL:FormValidator~~ 

1054 ], 

1055 "widgets": [ 

1056 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

1057 "clickable_url" # ~~^-> ClickableURL:FormWidget~~ 

1058 ] 

1059 } 

1060 

1061 # ~~->$ HasWaiver:FormField~~ 

1062 HAS_WAIVER = { 

1063 "name": "has_waiver", 

1064 "label": "Does the journal provide a waiver or discount " 

1065 "on publication fees for authors?", 

1066 "input": "radio", 

1067 "options": [ 

1068 {"display": "Yes", "value": "y", "subfields": ["waiver_url"]}, 

1069 {"display": "No", "value": "n"} 

1070 ], 

1071 "help": { 

1072 "long_help": ["Answer <strong>Yes</strong> if the journal provides" 

1073 " publication fee waivers for authors from " 

1074 "low-income economies, discounts for authors from " 

1075 "lower middle-income economies, and/or waivers and " 

1076 "discounts for other authors with " 

1077 "demonstrable needs."] 

1078 }, 

1079 "validate": [ 

1080 {"required": {"message": "Select Yes or No"}} 

1081 ] 

1082 } 

1083 

1084 # ~~->$ WaiverURL:FormField~~ 

1085 WAIVER_URL = { 

1086 "name": "waiver_url", 

1087 "label": "Where can we find this information?", 

1088 "input": "text", 

1089 "diff_table_context": "Publication fee waiver", 

1090 "conditional": [ 

1091 {"field": "has_waiver", "value": "y"} 

1092 ], 

1093 "help": { 

1094 "short_help": "Link to the journal’s waiver information.", 

1095 "doaj_criteria": "You must provide a URL", 

1096 "placeholder": "https://www.my-journal.com/about#waiver" 

1097 }, 

1098 "validate": [ 

1099 {"required_if": { 

1100 "field": "has_waiver", 

1101 "value": "y", 

1102 "message": "Enter the URL for the journal’s <strong>waiver information</strong> page" 

1103 } 

1104 }, 

1105 "is_url" # ~~^->IsURL:FormValidator~~ 

1106 ], 

1107 "widgets": [ 

1108 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

1109 "clickable_url" # ~~^-> ClickableURL:FormWidget~~ 

1110 ] 

1111 } 

1112 

1113 # ~~->$ HasOtherCharges:FormField~~ 

1114 HAS_OTHER_CHARGES = { 

1115 "name": "has_other_charges", 

1116 "label": "Does the journal charge any other fees to authors?", 

1117 "input": "radio", 

1118 "options": [ 

1119 {"display": "Yes", "value": "y", "subfields": ["other_charges_url"]}, 

1120 {"display": "No", "value": "n"} 

1121 ], 

1122 "help": { 

1123 "long_help": ["Declare all other charges: editorial processing charges, language editing fees, " 

1124 "colour charges, submission fees, page charges, membership fees, print subscription costs, " 

1125 "other supplementary charges"], 

1126 "doaj_criteria": "You must declare any other charges if they exist" 

1127 }, 

1128 "validate": [ 

1129 {"required": {"message": "Select Yes or No"}} 

1130 ] 

1131 } 

1132 

1133 # ~~->$ OtherChargesURL:FormField~~ 

1134 OTHER_CHARGES_URL = { 

1135 "name": "other_charges_url", 

1136 "label": "Where can we find this information?", 

1137 "input": "text", 

1138 "diff_table_context": "Other fees", 

1139 "conditional": [ 

1140 {"field": "has_other_charges", "value": "y"} 

1141 ], 

1142 "help": { 

1143 "short_help": "Link to the journal’s fees information", 

1144 "doaj_criteria": "You must provide a URL" 

1145 }, 

1146 "validate": [ 

1147 {"required_if": { 

1148 "field": "has_other_charges", 

1149 "value": "y", 

1150 "message": "Enter the URL for the journal’s <strong>fees<strong> information page" 

1151 } 

1152 }, 

1153 "is_url" # ~~^->IsURL:FormValidator~~ 

1154 ], 

1155 "widgets": [ 

1156 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

1157 "clickable_url" # ~~^-> ClickableURL:FormWidget~~ 

1158 ] 

1159 } 

1160 

1161 # ~~->$ PreservationService:FormField~~ 

1162 PRESERVATION_SERVICE = { 

1163 "name": "preservation_service", 

1164 "label": "Long-term preservation service(s) where the journal is currently archived", 

1165 "input": "checkbox", 

1166 "multiple": True, 

1167 "options": [ 

1168 {"display": "CINES", "value": "CINES", "subfields": ["preservation_service_url"]}, 

1169 {"display": "CLOCKSS", "value": "CLOCKSS", "subfields": ["preservation_service_url"]}, 

1170 {"display": "LOCKSS", "value": "LOCKSS", "subfields": ["preservation_service_url"]}, 

1171 {"display": "Internet Archive", "value": "Internet Archive", "subfields": ["preservation_service_url"]}, 

1172 {"display": "PKP PN", "value": "PKP PN", "subfields": ["preservation_service_url"]}, 

1173 {"display": "PubMed Central (PMC)", "value": "PMC", "subfields": ["preservation_service_url"]}, 

1174 {"display": "Portico", "value": "Portico", "subfields": ["preservation_service_url"]}, 

1175 {"display": "A national library", "value": "national_library", "subfields": ["preservation_service_library", "preservation_service_url"]}, 

1176 {"display": "Other", "value": "other", "subfields": ["preservation_service_other", "preservation_service_url"]}, 

1177 {"display": "<em>The journal content isn’t archived with a long-term preservation service</em>", 

1178 "value": "none", "exclusive": True} 

1179 ], 

1180 "help": { 

1181 "long_help": [ 

1182 "Content must be actively deposited in each of the options you choose. " 

1183 "If the journal is registered with a service but archiving is not yet active," 

1184 " choose <em>The journal content isn’t archived with a long-term preservation service</em>.", 

1185 "PubMed Central covers PMC U.S.A. and EuropePMC(Wellcome Trust)."] 

1186 }, 

1187 "validate": [ 

1188 {"required": {"message": "Select <strong>at least one</strong> option"}} 

1189 ] 

1190 } 

1191 

1192 # ~~->$ PreservationServiceLibrary:FormField~~ 

1193 PRESERVATION_SERVICE_LIBRARY = { 

1194 "name": "preservation_service_library", 

1195 "label": "A national library", 

1196 "input": "text", 

1197 "repeatable" : { 

1198 "minimum": 1, 

1199 "initial" : 2 

1200 }, 

1201 "help": { 

1202 "short_help": "Name of national library" 

1203 }, 

1204 "conditional": [{"field": "preservation_service", "value": "national_library"}], 

1205 "validate": [ 

1206 {"required_if": { 

1207 "field": "preservation_service", 

1208 "value": "national_library", 

1209 "message": "Enter the name(s) of the national library or libraries where the journal is archived" 

1210 } 

1211 } 

1212 ], 

1213 "asynchronous_warning": [ 

1214 {"warn_on_value": {"value": "None"}} 

1215 ], 

1216 "widgets": [ 

1217 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

1218 "multiple_field" 

1219 ], 

1220 "attr": { 

1221 "class": "input-xlarge unstyled-list" 

1222 } 

1223 } 

1224 

1225 # ~~->$ PreservationServiceOther:FormField~~ 

1226 PRESERVATION_SERVICE_OTHER = { 

1227 "name": "preservation_service_other", 

1228 "label": "Other archiving policy:", 

1229 "input": "text", 

1230 "conditional": [{"field": "preservation_service", "value": "other"}], 

1231 "validate": [ 

1232 {"required_if": { 

1233 "field": "preservation_service", 

1234 "value": "other", 

1235 "message": "Enter the name of another archiving policy" 

1236 } 

1237 } 

1238 ], 

1239 "asynchronous_warning": [ 

1240 {"warn_on_value": {"value": "None"}} 

1241 ], 

1242 "widgets" : [ 

1243 "trim_whitespace" # ~~^-> TrimWhitespace:FormWidget~~ 

1244 ] 

1245 } 

1246 

1247 # ~~->$ PreservationServiceURL:FormField~~ 

1248 PRESERVATION_SERVICE_URL = { 

1249 "name": "preservation_service_url", 

1250 "label": "Where can we find this information?", 

1251 "input": "text", 

1252 "diff_table_context": "Archiving policy", 

1253 "help": { 

1254 "short_help": "Link to the preservation and archiving information", 

1255 "doaj_criteria": "You must provide a URL", 

1256 "placeholder": "https://www.my-journal.com/about#archiving" 

1257 }, 

1258 "conditional": [ 

1259 {"field": "preservation_service", "value": "CINES"}, 

1260 {"field": "preservation_service", "value": "CLOCKSS"}, 

1261 {"field": "preservation_service", "value": "LOCKSS"}, 

1262 {"field": "preservation_service", "value": "Internet Archive"}, 

1263 {"field": "preservation_service", "value": "PKP PN"}, 

1264 {"field": "preservation_service", "value": "PMC"}, 

1265 {"field": "preservation_service", "value": "Portico"}, 

1266 {"field": "preservation_service", "value": "national_library"}, 

1267 {"field": "preservation_service", "value": "other"} 

1268 ], 

1269 "validate": [ 

1270 { 

1271 "required_if": { 

1272 "field": "preservation_service", 

1273 "value": [ 

1274 "CINES", 

1275 "CLOCKSS", 

1276 "LOCKSS", 

1277 "Internet Archive", 

1278 "PKP PN", 

1279 "PMC", 

1280 "Portico", 

1281 "national_library", 

1282 "other" 

1283 ] 

1284 } 

1285 }, 

1286 "is_url" # ~~^->IsURL:FormValidator~~ 

1287 ], 

1288 "widgets": [ 

1289 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

1290 "clickable_url" # ~~^-> ClickableURL:FormWidget~~ 

1291 ] 

1292 } 

1293 

1294 # ~~->$ DepositPolicy:FormField~~ 

1295 DEPOSIT_POLICY = { 

1296 "name": "deposit_policy", 

1297 "label": "Does the journal have a policy allowing authors to deposit versions of their work in an " 

1298 "institutional or other repository of their choice? Where is this policy recorded?", 

1299 "input": "checkbox", 

1300 "multiple": True, 

1301 "options": [ 

1302 {"display": "Sherpa/Romeo", "value": "Sherpa/Romeo", "subfields": ["deposit_policy_url"]}, 

1303 {"display": "Dulcinea", "value": "Dulcinea", "subfields": ["deposit_policy_url"]}, 

1304 {"display": "Diadorim", "value": "Diadorim", "subfields": ["deposit_policy_url"]}, 

1305 {"display": "Other (including publisher’s own site)", "value": "other", "subfields": ["deposit_policy_other", "deposit_policy_url"]}, 

1306 {"display": "<em>The journal has no repository policy</em>", "value": "none", "exclusive": True} 

1307 ], 

1308 "help": { 

1309 "long_help": ["Many authors wish to deposit a copy of their paper in an institutional or other repository " 

1310 "of their choice. What is the journal’s policy for this?", 

1311 "You should state your policy with regard to the different versions of the paper:" 

1312 "<ul style='list-style-type: none;'>" 

1313 "<li>Submitted version</li>" 

1314 "<li>Accepted version (Author Accepted Manuscript)</li>" 

1315 "<li>Published version (Version of Record)</li>" 

1316 "</ul>", 

1317 "For a journal to qualify for the DOAJ Seal, it must allow all versions to be deposited in an institutional or other repository of the author’s choice without embargo." 

1318 ]}, 

1319 "validate": [ 

1320 {"required": {"message": "Select <strong>at least one</strong> option"}} 

1321 ] 

1322 } 

1323 

1324 # ~~->$ DepositPolicyOther:FormField~~ 

1325 DEPOSIT_POLICY_OTHER = { 

1326 "name": "deposit_policy_other", 

1327 "label": "Name of other website where policy is registered", 

1328 "input": "text", 

1329 "conditional": [{"field": "deposit_policy", "value": "other"}], 

1330 "validate": [ 

1331 {"required_if": { 

1332 "field": "deposit_policy", 

1333 "value": "other", 

1334 "message": "Enter the name of another repository policy" 

1335 } 

1336 } 

1337 ], 

1338 "asynchronous_warning": [ 

1339 {"warn_on_value": {"value": "None"}} 

1340 ], 

1341 "widgets" : [ 

1342 "trim_whitespace" # ~~^-> TrimWhitespace:FormWidget~~ 

1343 ] 

1344 } 

1345 

1346 # ~~->$ DepositPolicyURL:FormField~~ 

1347 DEPOSIT_POLICY_URL = { 

1348 "name": "deposit_policy_url", 

1349 "label": "Where can we find this information?", 

1350 "input": "text", 

1351 "diff_table_context": "Repository policy", 

1352 "conditional": [{"field": "deposit_policy", "value": "Sherpa/Romeo"}, 

1353 {"field": "deposit_policy", "value": "Dulcinea"}, 

1354 {"field": "deposit_policy", "value": "Diadorim"}, 

1355 {"field": "deposit_policy", "value": "Diadorim"}, 

1356 {"field": "deposit_policy", "value": "other"}], 

1357 "help": { 

1358 "doaj_criteria": "You must provide a URL", 

1359 "short_help": "Link to the policy in a directory or on the " 

1360 "publisher’s site", 

1361 "placeholder": "https://www.my-journal.com/about#repository_policy" 

1362 }, 

1363 "validate": [ 

1364 "is_url" # ~~^->IsURL:FormValidator~~ 

1365 ], 

1366 "widgets": [ 

1367 "trim_whitespace", # ~~^-> TrimWhitespace:FormWidget~~ 

1368 "clickable_url" # ~~^-> ClickableURL:FormWidget~~ 

1369 ], 

1370 "contexts" : { 

1371 "public" : { 

1372 "validate": [ 

1373 { 

1374 "required_if": { 

1375 "field": "deposit_policy", 

1376 "value": [ 

1377 "Sherpa/Romeo", 

1378 "Dulcinea", 

1379 "Diadorim", 

1380 "other" 

1381 ] 

1382 } 

1383 }, 

1384 "is_url" # ~~^->IsURL:FormValidator~~ 

1385 ] 

1386 }, 

1387 "update_request" : { 

1388 "validate" : [ 

1389 { 

1390 "required_if": { 

1391 "field": "deposit_policy", 

1392 "value": [ 

1393 "Sherpa/Romeo", 

1394 "Dulcinea", 

1395 "Diadorim", 

1396 "other" 

1397 ] 

1398 } 

1399 }, 

1400 "is_url" # ~~^->IsURL:FormValidator~~ 

1401 ] 

1402 } 

1403 } 

1404 } 

1405 

1406 # ~~->$ PersistentIdentifiers:FormField~~ 

1407 PERSISTENT_IDENTIFIERS = { 

1408 "name": "persistent_identifiers", 

1409 "label": "Persistent article identifiers used by the journal", 

1410 "input": "checkbox", 

1411 "multiple": True, 

1412 "hint": "Select at least one", 

1413 "options": [ 

1414 {"display": "DOIs", "value": "DOI"}, 

1415 {"display": "ARKs", "value": "ARK"}, 

1416 {"display": "Handles", "value": "Handles"}, 

1417 {"display": "PURLs", "value": "PURL"}, 

1418 {"display": "Other", "value": "other", "subfields": ["persistent_identifiers_other"]}, 

1419 {"display": "<em>The journal does not use persistent article identifiers</em>", "value": "none", "exclusive": True} 

1420 ], 

1421 "help": { 

1422 "long_help": ["A persistent article identifier (PID) is used to find the article no matter where it is " 

1423 "located. The most common type of PID is the digital object identifier (DOI). ", 

1424 "<a href='https://en.wikipedia.org/wiki/Persistent_identifier' target='_blank' rel='noopener'>Read more about PIDs.</a>"], 

1425 }, 

1426 "validate": [ 

1427 {"required": {"message": "Select <strong>at least one</strong> option"}} 

1428 ] 

1429 } 

1430 

1431 # ~~->$ PersistentIdentifiersOther:FormField~~ 

1432 PERSISTENT_IDENTIFIERS_OTHER = { 

1433 "name": "persistent_identifiers_other", 

1434 "label": "Other identifier", 

1435 "input": "text", 

1436 "conditional": [{"field": "persistent_identifiers", "value": "other"}], 

1437 "validate": [ 

1438 {"required_if": { 

1439 "field": "persistent_identifiers", 

1440 "value": "other", 

1441 "message": "Enter the name of another type of identifier" 

1442 } 

1443 } 

1444 ], 

1445 "asynchronous_warning": [ 

1446 {"warn_on_value": {"value": "None"}} 

1447 ], 

1448 "widgets" : [ 

1449 "trim_whitespace" # ~~^-> TrimWhitespace:FormWidget~~ 

1450 ] 

1451 } 

1452 

1453 # ~~->$ Orcids:FormField~~ 

1454 ORCID_IDS = { 

1455 "name": "orcid_ids", 

1456 "label": "Does the journal allow for ORCID iDs to be present in article metadata?", 

1457 "input": "radio", 

1458 "options": [ 

1459 {"display": "Yes", "value": "y"}, 

1460 {"display": "No", "value": "n"} 

1461 ], 

1462 "default" : "", 

1463 "help": { 

1464 "long_help": ["An <a href='https://orcid.org/' target='_blank' rel='noopener'>ORCID</a> (Open Researcher and Contributor) iD is an alphanumeric code to uniquely identify " 

1465 "authors."], 

1466 }, 

1467 "contexts" : { 

1468 "public" : { 

1469 "validate": [ 

1470 {"required": {"message": "Select Yes or No"}} 

1471 ] 

1472 }, 

1473 "update_request" : { 

1474 "validate" : [ 

1475 {"required": {"message": "Select Yes or No"}} 

1476 ] 

1477 } 

1478 } 

1479 } 

1480 

1481 # ~~->$ OpenCitations:FormField~~ 

1482 OPEN_CITATIONS = { 

1483 "name": "open_citations", 

1484 "label": "Does the journal comply with I4OC standards for open citations?", 

1485 "input": "radio", 

1486 "options": [ 

1487 {"display": "Yes", "value": "y"}, 

1488 {"display": "No", "value": "n"} 

1489 ], 

1490 "default" : "", 

1491 "help": { 

1492 "long_help": ["The <a href='https://i4oc.org/#goals' target='_blank' rel='noopener'>I4OC standards</a> ask that citations are structured, separable, and open. "], 

1493 }, 

1494 "contexts" : { 

1495 "public" : { 

1496 "validate": [ 

1497 {"required": {"message": "Select Yes or No"}} 

1498 ] 

1499 }, 

1500 "update_request" : { 

1501 "validate" : [ 

1502 {"required": {"message": "Select Yes or No"}} 

1503 ] 

1504 } 

1505 } 

1506 } 

1507 

1508 ####################################### 

1509 ## Ediorial fields 

1510 

1511 # ~~->$ DOAJSeal:FormField~~ 

1512 DOAJ_SEAL = { 

1513 "name": "doaj_seal", 

1514 "label": "The journal has fulfilled all the criteria for the Seal. Award the Seal?", 

1515 "input": "checkbox", 

1516 "validate": [ 

1517 { 

1518 "only_if" : { 

1519 "fields" : [ 

1520 {"field" : "license_display", "value" : "y"}, 

1521 {"field" : "copyright_author_retains", "value" : "y"}, 

1522 {"field" : "preservation_service", "not" : "none"}, 

1523 {"field" : "preservation_service_url", "not" : ""}, 

1524 {"field" : "deposit_policy", "not" : "none"}, 

1525 {"field" : "persistent_identifiers", "not" : "none"}, 

1526 {"field" : "license", "or" : ["CC BY", "CC BY-SA", "CC BY-NC", "CC BY-NC-SA"]} 

1527 ], 

1528 "message" : "In order to award the query: the license must be CC BY, CC BY-SA, CC BY-NC, or CC BY-NC-SA; " 

1529 "the license must be displayed or embedded; " 

1530 "the author must retain their copyright; " 

1531 "the journal must make use of a preservation service; " 

1532 "a url for the preservation service must be provided; " 

1533 "the journal must have a deposit policy; " 

1534 "the journal must use a persistent identifier" 

1535 } 

1536 } 

1537 ] 

1538 } 

1539 

1540 # FIXME: this probably shouldn't be in the admin form fieldsets, rather its own separate form 

1541 # ~~->$ QuickReject:FormField~~ 

1542 QUICK_REJECT = { 

1543 "name": "quick_reject", 

1544 "label": "Reason for rejection", 

1545 "input": "select", 

1546 "options_fn": "quick_reject" 

1547 } 

1548 

1549 # ~~->$ QuickRejectDetails:FormField~~ 

1550 QUICK_REJECT_DETAILS = { 

1551 "name": "quick_reject_details", 

1552 "label": "Additional info", 

1553 "input": "textarea", 

1554 "help": { 

1555 "long_help": ["The selected reason for rejection, and any additional information you include, " 

1556 "are sent to the journal contact with the rejection email."] 

1557 }, 

1558 "validate": [ 

1559 {"required_if": {"field": "quick_reject", "value": "other"}} 

1560 ], 

1561 } 

1562 

1563 # ~~->$ Owner:FormField~~ 

1564 OWNER = { 

1565 "name": "owner", 

1566 "label": "DOAJ Account", 

1567 "input": "text", 

1568 "validate": [ 

1569 "reserved_usernames", 

1570 "owner_exists" 

1571 ], 

1572 "widgets": [ 

1573 {"autocomplete": {"type" : "account", "field": "id", "include" : False}}, 

1574 "clickable_owner" 

1575 ], 

1576 "contexts" : { 

1577 "associate_editor" : { 

1578 "validate" : [ 

1579 {"required": {"message": "You must confirm the account id"}}, 

1580 "reserved_usernames", 

1581 "owner_exists" 

1582 ] 

1583 } 

1584 } 

1585 } 

1586 

1587 # ~~->$ ApplicationStatus:FormField~~ 

1588 APPLICATION_STATUS = { 

1589 "name": "application_status", 

1590 "label": "Change status", 

1591 "input": "select", 

1592 "options_fn": "application_statuses", 

1593 "validate": [ 

1594 "required" 

1595 ], 

1596 "help" : { 

1597 "update_requests_diff" : False, 

1598 "render_error_box": False 

1599 }, 

1600 "disabled" : "application_status_disabled", 

1601 "contexts" : { 

1602 "associate_editor" : { 

1603 "help" : { 

1604 "render_error_box": False, 

1605 "short_help" : "Set the status to 'In Progress' to signal to the applicant that you have started your review." 

1606 "Set the status to 'Completed' to alert the Editor that you have completed your review.", 

1607 "update_requests_diff": False 

1608 } 

1609 }, 

1610 "editor" : { 

1611 "help" : { 

1612 "render_error_box" : False, 

1613 "short_help" : "Revert the status to 'In Progress' to signal to the Associate Editor that further work is needed." 

1614 "Set the status to 'Ready' to alert the Managing Editor that you have completed your review.", 

1615 "update_requests_diff": False 

1616 } 

1617 } 

1618 }, 

1619 "widgets" : [ 

1620 # When Accepted selected display. 'This journal is currently assigned to its applicant account XXXXXX. Is this the correct account for this journal?' 

1621 "owner_review" 

1622 ] 

1623 } 

1624 

1625 # ~~->$ EditorGroup:FormField~~ 

1626 EDITOR_GROUP = { 

1627 "name": "editor_group", 

1628 "label": "Group", 

1629 "input": "text", 

1630 "widgets": [ 

1631 {"autocomplete": {"type" : "editor_group", "field": "name", "include" : False}} 

1632 ], 

1633 "contexts" : { 

1634 "editor" : { 

1635 "disabled" : True 

1636 }, 

1637 "admin" : { 

1638 "widgets" : [ 

1639 {"autocomplete": {"type": "editor_group", "field": "name", "include" : False}}, 

1640 {"load_editors" : {"field" : "editor"}} 

1641 ] 

1642 } 

1643 } 

1644 } 

1645 

1646 # ~~->$ Editor:FormField~~ 

1647 EDITOR = { 

1648 "name": "editor", 

1649 "label": "Individual", 

1650 "input": "select", 

1651 "options_fn": "editor_choices", 

1652 "default" : "", 

1653 "validate" : [ 

1654 { "group_member" : {"group_field" : "editor_group"}} 

1655 ], 

1656 "help" : { 

1657 "render_error_box": False 

1658 } 

1659 } 

1660 

1661 # ~~->$ DiscontinuedDate:FormField~~ 

1662 DISCONTINUED_DATE = { 

1663 "name": "discontinued_date", 

1664 "label": "Discontinued on", 

1665 "input": "text", 

1666 "validate" : [ 

1667 {"bigenddate" : {"message" : "Date must be a big-end formatted date (e.g. 2020-11-23)"}}, 

1668 { 

1669 "not_if" : { 

1670 "fields" : [ 

1671 {"field" : "continues"}, 

1672 {"field" : "continued_by"} 

1673 ], 

1674 "message" : "You cannot enter both a discontinued date and continuation information." 

1675 } 

1676 } 

1677 ], 

1678 "help" : { 

1679 "short_help" : "Please enter the discontinued date in the form YYYY-MM-DD (e.g. 2020-11-23). " 

1680 "If the day of the month is not known, please use '01' (e.g. 2020-11-01)", 

1681 "render_error_box" : False 

1682 } 

1683 } 

1684 

1685 # ~~->$ Continues:FormField~~ 

1686 CONTINUES = { 

1687 "name": "continues", 

1688 "label": "Continues an <strong>older</strong> journal with the ISSN(s)", 

1689 "input": "taglist", 

1690 "validate": [ 

1691 {"is_issn_list": {"message": "This is not a valid ISSN"}}, # ~~^-> IsISSN:FormValidator~~ 

1692 {"different_to": {"field": "continued_by"}}, # ~~^-> DifferetTo:FormValidator~~ 

1693 { 

1694 "not_if" : { 

1695 "fields" : [{"field" : "discontinued_date"}], 

1696 "message" : "You cannot enter both continuation information and a discontinued date" 

1697 } 

1698 } 

1699 ], 

1700 "widgets" : [ 

1701 "tagentry" 

1702 ], 

1703 "help" : { 

1704 "render_error_box": False 

1705 } 

1706 } 

1707 

1708 # ~~->$ ContinuedBy:FormField~~ 

1709 CONTINUED_BY = { 

1710 "name": "continued_by", 

1711 "label": "Continued by a <strong>newer</strong> journal with the ISSN(s)", 

1712 "input": "taglist", 

1713 "validate": [ 

1714 {"is_issn_list": {"message": "This is not a valid ISSN"}}, # ~~^-> IsISSN:FormValidator~~ 

1715 {"different_to": {"field": "continues"}}, # ~~^-> DifferetTo:FormValidator~~ 

1716 { 

1717 "not_if": { 

1718 "fields": [{"field": "discontinued_date"}], 

1719 "message": "You cannot enter both continuation information and a discontinued date" 

1720 } 

1721 } 

1722 ], 

1723 "widgets" : [ 

1724 "tagentry" 

1725 ], 

1726 "help" : { 

1727 "render_error_box": False 

1728 } 

1729 } 

1730 

1731 # ~~->$ Subject:FormField~~ 

1732 SUBJECT = { 

1733 "name": "subject", 

1734 "label": "Assign one or a maximum of two subject classifications", 

1735 "input": "taglist", 

1736 "help": { 

1737 "short_help": "Selecting a subject will not automatically select its sub-categories", 

1738 "render_error_box" : False, 

1739 }, 

1740 "validate": [ 

1741 {"required_if" : { 

1742 "field" : "application_status", 

1743 "value" : [ 

1744 constants.APPLICATION_STATUS_READY, 

1745 constants.APPLICATION_STATUS_COMPLETED, 

1746 constants.APPLICATION_STATUS_ACCEPTED 

1747 ], 

1748 "message" : "This field is required when setting the Application Status to {y}, {z} or {a}".format( 

1749 y=constants.APPLICATION_STATUS_READY, 

1750 z=constants.APPLICATION_STATUS_COMPLETED, 

1751 a=constants.APPLICATION_STATUS_ACCEPTED 

1752 ) 

1753 } 

1754 } 

1755 ], 

1756 "widgets": [ 

1757 "subject_tree" 

1758 ], 

1759 "contexts" : { 

1760 "associate_editor" : { 

1761 "validate" : [ 

1762 "required" 

1763 ] 

1764 } 

1765 } 

1766 } 

1767 

1768 # ~~->$ Notes:FormField~~ 

1769 NOTES = { 

1770 "name" : "notes", 

1771 "input": "group", 

1772 "label": "Notes", 

1773 "repeatable" : { 

1774 "initial" : 1, 

1775 "add_button_placement" : "top" 

1776 }, 

1777 "subfields": [ 

1778 "note_date", 

1779 "note", 

1780 "note_id" 

1781 ], 

1782 "template": "application_form/_list.html", 

1783 "entry_template": "application_form/_entry_group.html", 

1784 "widgets": [ 

1785 {"infinite_repeat" : {"enable_on_repeat" : ["textarea"]}}, 

1786 "note_modal" 

1787 ], 

1788 "merge_disabled" : "merge_disabled_notes", 

1789 "contexts" : { 

1790 "admin" : { 

1791 "widgets": [ 

1792 {"infinite_repeat": {"enable_on_repeat": ["textarea"], "allow_delete" : True}}, 

1793 "note_modal" 

1794 ] 

1795 } 

1796 } 

1797 } 

1798 

1799 # ~~->$ Note:FormField~~ 

1800 NOTE = { 

1801 "subfield": True, 

1802 "name": "note", 

1803 "group": "notes", 

1804 "input": "textarea", 

1805 "disabled": True 

1806 } 

1807 

1808 # ~~->$ NoteDate:FormField~~ 

1809 NOTE_DATE = { 

1810 "subfield": True, 

1811 "name" : "note_date", 

1812 "group": "notes", 

1813 "input": "text", 

1814 "disabled": True 

1815 } 

1816 

1817 # ~~->$ NoteID:FormField~~ 

1818 NOTE_ID = { 

1819 "subfield" : True, 

1820 "name": "note_id", 

1821 "group": "notes", 

1822 "input": "hidden" 

1823 } 

1824 

1825 # ~~->$ OptionalValidation:FormField~~ 

1826 OPTIONAL_VALIDATION = { 

1827 "name" : "make_all_fields_optional", 

1828 "label" : "Allow save without validation", 

1829 "input" : "checkbox", 

1830 "widget" : { 

1831 "optional_validation" 

1832 } 

1833 } 

1834 

1835 # Bulk Edit fields (that couldn't be overriden in the normal way) 

1836 # ~~->$ BulkDOAJSeal:FormField~~ 

1837 BULK_DOAJ_SEAL = { 

1838 "name": "change_doaj_seal", 

1839 "label": 'Award the Seal', 

1840 "input": "select", 

1841 "default" : "", 

1842 "options" :[ 

1843 {"value": "", "display" : "Leave unchanged"}, 

1844 {"value" : "True", "display" : "Yes"}, 

1845 {"value" : "False", "display" : "No"} 

1846 ], 

1847 } 

1848 

1849 

1850########################################################## 

1851# Define our fieldsets 

1852########################################################## 

1853 

1854class FieldSetDefinitions: 

1855 #~~->$ BasicCompliance:FieldSet~~ 

1856 BASIC_COMPLIANCE = { 

1857 "name": "basic_compliance", 

1858 "label": "Open access compliance", 

1859 "fields": [ 

1860 FieldDefinitions.BOAI["name"], 

1861 FieldDefinitions.OA_STATEMENT_URL["name"], 

1862 FieldDefinitions.OA_START["name"] 

1863 ] 

1864 } 

1865 

1866 # ~~->$ AboutJournal:FieldSet~~ 

1867 ABOUT_THE_JOURNAL = { 

1868 "name": "about_the_journal", 

1869 "label": "About the journal", 

1870 "fields": [ 

1871 FieldDefinitions.TITLE["name"], 

1872 FieldDefinitions.ALTERNATIVE_TITLE["name"], 

1873 FieldDefinitions.JOURNAL_URL["name"], 

1874 FieldDefinitions.PISSN["name"], 

1875 FieldDefinitions.EISSN["name"], 

1876 FieldDefinitions.KEYWORDS["name"], 

1877 FieldDefinitions.LANGUAGE["name"] 

1878 ] 

1879 } 

1880 

1881 # ~~->$ Publisher:FieldSet~~ 

1882 PUBLISHER = { 

1883 "name": "publisher", 

1884 "label": "Publisher", 

1885 "fields": [ 

1886 FieldDefinitions.PUBLISHER_NAME["name"], 

1887 FieldDefinitions.PUBLISHER_COUNTRY["name"], 

1888 ] 

1889 } 

1890 

1891 # ~~->$ Institution:FieldSet~~ 

1892 SOCIETY_OR_INSTITUTION = { 

1893 "name": "society_or_institution", 

1894 "label": "Society or institution, if applicable", 

1895 "fields": [ 

1896 FieldDefinitions.INSTITUTION_NAME["name"], 

1897 FieldDefinitions.INSTITUTION_COUNTRY["name"] 

1898 ] 

1899 } 

1900 

1901 # ~~->$ Licensing:FieldSet~~ 

1902 LICENSING = { 

1903 "name": "licensing", 

1904 "label": "Licensing", 

1905 "fields": [ 

1906 FieldDefinitions.LICENSE["name"], 

1907 FieldDefinitions.LICENSE_ATTRIBUTES["name"], 

1908 FieldDefinitions.LICENSE_TERMS_URL["name"] 

1909 ] 

1910 } 

1911 

1912 # ~~->$ EmbeddedLicense:FieldSet~~ 

1913 EMBEDDED_LICENSING = { 

1914 "name": "embedded_licensing", 

1915 "label": "Embedded licenses", 

1916 "fields": [ 

1917 FieldDefinitions.LICENSE_DISPLAY["name"], 

1918 FieldDefinitions.LICENSE_DISPLAY_EXAMPLE_URL["name"] 

1919 ] 

1920 } 

1921 

1922 # ~~->$ Copyright:FieldSet~~ 

1923 COPYRIGHT = { 

1924 "name": "copyright", 

1925 "label": "Copyright", 

1926 "fields": [ 

1927 FieldDefinitions.COPYRIGHT_AUTHOR_RETAINS["name"], 

1928 FieldDefinitions.COPYRIGHT_URL["name"] 

1929 ] 

1930 } 

1931 

1932 # ~~->$ PeerReview:FieldSet~~ 

1933 PEER_REVIEW = { 

1934 "name": "peer_review", 

1935 "label": "Peer review", 

1936 "fields": [ 

1937 FieldDefinitions.REVIEW_PROCESS["name"], 

1938 FieldDefinitions.REVIEW_PROCESS_OTHER["name"], 

1939 FieldDefinitions.REVIEW_URL["name"] 

1940 ] 

1941 } 

1942 

1943 # ~~->$ Plagiarism:FieldSet~~ 

1944 PLAGIARISM = { 

1945 "name": "plagiarism", 

1946 "label": "Plagiarism", 

1947 "fields": [ 

1948 FieldDefinitions.PLAGIARISM_DETECTION["name"], 

1949 FieldDefinitions.PLAGIARISM_URL["name"] 

1950 ] 

1951 } 

1952 

1953 # ~~->$ Editorial:FieldSet~~ 

1954 EDITORIAL = { 

1955 "name": "editorial", 

1956 "label": "Editorial", 

1957 "fields": [ 

1958 FieldDefinitions.AIMS_SCOPE_URL["name"], 

1959 FieldDefinitions.EDITORIAL_BOARD_URL["name"], 

1960 FieldDefinitions.AUTHOR_INSTRUCTIONS_URL["name"], 

1961 FieldDefinitions.PUBLICATION_TIME_WEEKS["name"] 

1962 ] 

1963 } 

1964 

1965 # ~~->$ APC:FieldSet~~ 

1966 APC = { 

1967 "name": "apc", 

1968 "label": "Publication fees", 

1969 "fields": [ 

1970 FieldDefinitions.APC["name"], 

1971 FieldDefinitions.APC_CHARGES["name"], 

1972 FieldDefinitions.APC_CURRENCY["name"], 

1973 FieldDefinitions.APC_MAX["name"], 

1974 FieldDefinitions.APC_URL["name"] 

1975 ] 

1976 } 

1977 

1978 # ~~->$ Waivers:FieldSet~~ 

1979 APC_WAIVERS = { 

1980 "name": "apc_waivers", 

1981 "label": "Publication fee waivers", 

1982 "fields": [ 

1983 FieldDefinitions.HAS_WAIVER["name"], 

1984 FieldDefinitions.WAIVER_URL["name"] 

1985 ] 

1986 } 

1987 

1988 # ~~->$ OtherFees:FieldSet~~ 

1989 OTHER_FEES = { 

1990 "name": "other_fees", 

1991 "label": "Other fees", 

1992 "fields": [ 

1993 FieldDefinitions.HAS_OTHER_CHARGES["name"], 

1994 FieldDefinitions.OTHER_CHARGES_URL["name"] 

1995 ] 

1996 } 

1997 

1998 # ~~->$ ArchivingPolicy:FieldSet~~ 

1999 ARCHIVING_POLICY = { 

2000 "name": "archiving_policy", 

2001 "label": "Archiving policy", 

2002 "fields": [ 

2003 FieldDefinitions.PRESERVATION_SERVICE["name"], 

2004 FieldDefinitions.PRESERVATION_SERVICE_LIBRARY["name"], 

2005 FieldDefinitions.PRESERVATION_SERVICE_OTHER["name"], 

2006 FieldDefinitions.PRESERVATION_SERVICE_URL["name"] 

2007 ] 

2008 } 

2009 

2010 # ~~->$ RepositoryPolicy:FieldSet~~ 

2011 REPOSITORY_POLICY = { 

2012 "name": "deposit_policy", 

2013 "label": "Repository policy", 

2014 "fields": [ 

2015 FieldDefinitions.DEPOSIT_POLICY["name"], 

2016 FieldDefinitions.DEPOSIT_POLICY_OTHER["name"], 

2017 FieldDefinitions.DEPOSIT_POLICY_URL["name"] 

2018 ] 

2019 } 

2020 

2021 # ~~->$ UniqueIdentifiers:FieldSet~~ 

2022 UNIQUE_IDENTIFIERS = { 

2023 "name": "unique_identifiers", 

2024 "label": "Unique identifiers & structured data", 

2025 "fields": [ 

2026 FieldDefinitions.PERSISTENT_IDENTIFIERS["name"], 

2027 FieldDefinitions.PERSISTENT_IDENTIFIERS_OTHER["name"], 

2028 FieldDefinitions.ORCID_IDS["name"], 

2029 FieldDefinitions.OPEN_CITATIONS["name"] 

2030 ] 

2031 } 

2032 

2033 # ~~->$ Seal:FieldSet~~ 

2034 SEAL = { 

2035 "name": "seal", 

2036 "label": "Award the seal", 

2037 "fields": [ 

2038 FieldDefinitions.DOAJ_SEAL["name"] 

2039 ] 

2040 } 

2041 

2042 # ~~->$ QuickReject:FieldSet~~ 

2043 # ~~^-> QuickReject:Feature~~ 

2044 QUICK_REJECT = { 

2045 "name": "quick_reject", 

2046 "label": "Quick reject", 

2047 "fields": [ 

2048 FieldDefinitions.QUICK_REJECT["name"], 

2049 FieldDefinitions.QUICK_REJECT_DETAILS["name"] 

2050 ] 

2051 } 

2052 

2053 # ~~->$ Reassign:FieldSet~~ 

2054 REASSIGN = { 

2055 "name": "reassign", 

2056 "label": "Re-assign publisher account", 

2057 "fields": [ 

2058 FieldDefinitions.OWNER["name"] 

2059 ] 

2060 } 

2061 

2062 # ~~->$ Status:FieldSet~~ 

2063 STATUS = { 

2064 "name": "status", 

2065 "label": "Status", 

2066 "fields": [ 

2067 FieldDefinitions.APPLICATION_STATUS["name"] 

2068 ] 

2069 } 

2070 

2071 # ~~->$ Reviewers:FieldSet~~ 

2072 REVIEWERS = { 

2073 "name": "reviewers", 

2074 "label": "Assign for review", 

2075 "fields": [ 

2076 FieldDefinitions.EDITOR_GROUP["name"], 

2077 FieldDefinitions.EDITOR["name"] 

2078 ] 

2079 } 

2080 

2081 # ~~->$ Continuations:FieldSet~~ 

2082 # ~~^-> Continuations:Feature~~ 

2083 CONTINUATIONS = { 

2084 "name": "continuations", 

2085 "label": "Continuations", 

2086 "fields": [ 

2087 FieldDefinitions.CONTINUES["name"], 

2088 FieldDefinitions.CONTINUED_BY["name"], 

2089 FieldDefinitions.DISCONTINUED_DATE["name"] 

2090 ] 

2091 } 

2092 

2093 # ~~->$ Subject:FieldSet~~ 

2094 SUBJECT = { 

2095 "name": "subject", 

2096 "label": "Subject classification", 

2097 "fields": [ 

2098 FieldDefinitions.SUBJECT["name"] 

2099 ] 

2100 } 

2101 

2102 # ~~->$ Notes:FieldSet~~ 

2103 NOTES = { 

2104 "name": "notes", 

2105 "label": "Notes", 

2106 "fields": [ 

2107 FieldDefinitions.NOTES["name"], 

2108 FieldDefinitions.NOTE["name"], 

2109 FieldDefinitions.NOTE_DATE["name"], 

2110 FieldDefinitions.NOTE_ID["name"] 

2111 ] 

2112 } 

2113 

2114 # ~~->$ OptionalValidation:FieldSet~~ 

2115 OPTIONAL_VALIDATION = { 

2116 "name": "optional_validation", 

2117 "label": "Allow save without validation", 

2118 "fields" : [ 

2119 FieldDefinitions.OPTIONAL_VALIDATION["name"] 

2120 ] 

2121 } 

2122 

2123 # ~~->$ BulkEdit:FieldSet~~ 

2124 # ~~^-> BulkEdit:Feature~~ 

2125 BULK_EDIT = { 

2126 "name" : "bulk_edit", 

2127 "label" : "Bulk edit", 

2128 "fields" : [ 

2129 FieldDefinitions.PUBLISHER_NAME["name"], 

2130 FieldDefinitions.BULK_DOAJ_SEAL["name"], 

2131 FieldDefinitions.PUBLISHER_COUNTRY["name"], 

2132 FieldDefinitions.OWNER["name"] 

2133 ] 

2134 } 

2135 

2136 

2137########################################################### 

2138# Define our Contexts 

2139########################################################### 

2140 

2141class ApplicationContextDefinitions: 

2142 #~~->$ NewApplication:FormContext~~ 

2143 #~~^-> ApplicationForm:Crosswalk~~ 

2144 #~~^-> NewApplication:FormProcessor~~ 

2145 PUBLIC = { 

2146 "name": "public", 

2147 "fieldsets": [ 

2148 FieldSetDefinitions.BASIC_COMPLIANCE["name"], 

2149 FieldSetDefinitions.ABOUT_THE_JOURNAL["name"], 

2150 FieldSetDefinitions.PUBLISHER["name"], 

2151 FieldSetDefinitions.SOCIETY_OR_INSTITUTION["name"], 

2152 FieldSetDefinitions.LICENSING["name"], 

2153 FieldSetDefinitions.EMBEDDED_LICENSING["name"], 

2154 FieldSetDefinitions.COPYRIGHT["name"], 

2155 FieldSetDefinitions.PEER_REVIEW["name"], 

2156 FieldSetDefinitions.PLAGIARISM["name"], 

2157 FieldSetDefinitions.EDITORIAL["name"], 

2158 FieldSetDefinitions.APC["name"], 

2159 FieldSetDefinitions.APC_WAIVERS["name"], 

2160 FieldSetDefinitions.OTHER_FEES["name"], 

2161 FieldSetDefinitions.ARCHIVING_POLICY["name"], 

2162 FieldSetDefinitions.REPOSITORY_POLICY["name"], 

2163 FieldSetDefinitions.UNIQUE_IDENTIFIERS["name"] 

2164 ], 

2165 "templates": { 

2166 "form" : "application_form/public_application.html", 

2167 "default_field" : "application_form/_field.html", 

2168 "default_group" : "application_form/_group.html" 

2169 }, 

2170 "crosswalks": { 

2171 "obj2form": ApplicationFormXWalk.obj2form, 

2172 "form2obj": ApplicationFormXWalk.form2obj 

2173 }, 

2174 "processor": application_processors.NewApplication, 

2175 } 

2176 

2177 # ~~->$ UpdateRequest:FormContext~~ 

2178 # ~~^-> NewApplication:FormContext~~ 

2179 # ~~^-> UpdateRequest:FormProcessor~~ 

2180 UPDATE = deepcopy(PUBLIC) 

2181 UPDATE["name"] = "update_request" 

2182 UPDATE["processor"] = application_processors.PublisherUpdateRequest 

2183 UPDATE["templates"]["form"] = "application_form/publisher_update_request.html" 

2184 

2185 # ~~->$ ReadOnlyApplication:FormContext~~ 

2186 # ~~^-> NewApplication:FormContext~~ 

2187 READ_ONLY = deepcopy(PUBLIC) 

2188 READ_ONLY["name"] = "application_read_only" 

2189 READ_ONLY["processor"] = application_processors.NewApplication # FIXME: enter the real processor 

2190 READ_ONLY["templates"]["form"] = "application_form/readonly_application.html" 

2191 

2192 # ~~->$ AssociateEditorApplication:FormContext~~ 

2193 # ~~^-> NewApplication:FormContext~~ 

2194 # ~~^-> AssociateEditorApplication:FormProcessor~~ 

2195 ASSOCIATE = deepcopy(PUBLIC) 

2196 ASSOCIATE["name"] = "associate_editor" 

2197 ASSOCIATE["fieldsets"] += [ 

2198 FieldSetDefinitions.STATUS["name"], 

2199 FieldSetDefinitions.SUBJECT["name"], 

2200 FieldSetDefinitions.NOTES["name"] 

2201 ] 

2202 ASSOCIATE["processor"] = application_processors.AssociateApplication 

2203 ASSOCIATE["templates"]["form"] = "application_form/assed_application.html" 

2204 

2205 # ~~->$ EditorApplication:FormContext~~ 

2206 # ~~^-> NewApplication:FormContext~~ 

2207 # ~~^-> EditorApplication:FormProcessor~~ 

2208 EDITOR = deepcopy(PUBLIC) 

2209 EDITOR["name"] = "editor" 

2210 EDITOR["fieldsets"] += [ 

2211 FieldSetDefinitions.STATUS["name"], 

2212 FieldSetDefinitions.REVIEWERS["name"], 

2213 FieldSetDefinitions.SUBJECT["name"], 

2214 FieldSetDefinitions.NOTES["name"] 

2215 ] 

2216 EDITOR["processor"] = application_processors.EditorApplication 

2217 EDITOR["templates"]["form"] = "application_form/editor_application.html" 

2218 

2219 # ~~->$ ManEdApplication:FormContext~~ 

2220 # ~~^-> NewApplication:FormContext~~ 

2221 # ~~^-> ManEdApplication:FormProcessor~~ 

2222 MANED = deepcopy(PUBLIC) 

2223 MANED["name"] = "admin" 

2224 MANED["fieldsets"] += [ 

2225 FieldSetDefinitions.SEAL["name"], 

2226 FieldSetDefinitions.QUICK_REJECT["name"], 

2227 FieldSetDefinitions.REASSIGN["name"], 

2228 FieldSetDefinitions.STATUS["name"], 

2229 FieldSetDefinitions.REVIEWERS["name"], 

2230 FieldSetDefinitions.CONTINUATIONS["name"], 

2231 FieldSetDefinitions.SUBJECT["name"], 

2232 FieldSetDefinitions.NOTES["name"] 

2233 ] 

2234 MANED["processor"] = application_processors.AdminApplication 

2235 MANED["templates"]["form"] = "application_form/maned_application.html" 

2236 

2237 

2238class JournalContextDefinitions: 

2239 # ~~->$ ReadOnlyJournal:FormContext~~ 

2240 # ~~^-> JournalForm:Crosswalk~~ 

2241 # ~~^-> ReadOnlyJournal:FormProcessor~~ 

2242 READ_ONLY = { 

2243 "name": "readonly", 

2244 "fieldsets": [ 

2245 FieldSetDefinitions.BASIC_COMPLIANCE["name"], 

2246 FieldSetDefinitions.ABOUT_THE_JOURNAL["name"], 

2247 FieldSetDefinitions.PUBLISHER["name"], 

2248 FieldSetDefinitions.SOCIETY_OR_INSTITUTION["name"], 

2249 FieldSetDefinitions.LICENSING["name"], 

2250 FieldSetDefinitions.EMBEDDED_LICENSING["name"], 

2251 FieldSetDefinitions.COPYRIGHT["name"], 

2252 FieldSetDefinitions.PEER_REVIEW["name"], 

2253 FieldSetDefinitions.PLAGIARISM["name"], 

2254 FieldSetDefinitions.EDITORIAL["name"], 

2255 FieldSetDefinitions.APC["name"], 

2256 FieldSetDefinitions.APC_WAIVERS["name"], 

2257 FieldSetDefinitions.OTHER_FEES["name"], 

2258 FieldSetDefinitions.ARCHIVING_POLICY["name"], 

2259 FieldSetDefinitions.REPOSITORY_POLICY["name"], 

2260 FieldSetDefinitions.UNIQUE_IDENTIFIERS["name"] 

2261 ], 

2262 "templates": { 

2263 "form" : "application_form/readonly_journal.html", 

2264 "default_field" : "application_form/_field.html", 

2265 "default_group" : "application_form/_group.html" 

2266 }, 

2267 "crosswalks": { 

2268 "obj2form": JournalFormXWalk.obj2form, 

2269 "form2obj": JournalFormXWalk.form2obj 

2270 }, 

2271 "processor": application_processors.ReadOnlyJournal 

2272 } 

2273 

2274 # ~~->$ AssEditorJournal:FormContext~~ 

2275 # ~~^-> ReadOnlyJournal:FormContext~~ 

2276 # ~~^-> AssEdJournal:FormProcessor~~ 

2277 ASSOCIATE = deepcopy(READ_ONLY) 

2278 ASSOCIATE["fieldsets"] += [ 

2279 FieldSetDefinitions.SUBJECT["name"], 

2280 FieldSetDefinitions.NOTES["name"] 

2281 ] 

2282 ASSOCIATE["name"] = "associate_editor" 

2283 ASSOCIATE["processor"] = application_processors.AssEdJournalReview 

2284 ASSOCIATE["templates"]["form"] = "application_form/assed_journal.html" 

2285 

2286 # ~~->$ EditorJournal:FormContext~~ 

2287 # ~~^-> AssEdJournal:FormContext~~ 

2288 # ~~^-> EditorJournal:FormProcessor~~ 

2289 EDITOR = deepcopy(ASSOCIATE) 

2290 EDITOR["name"] = "editor" 

2291 EDITOR["fieldsets"] += [ 

2292 FieldSetDefinitions.REVIEWERS["name"] 

2293 ] 

2294 EDITOR["processor"] = application_processors.EditorJournalReview 

2295 EDITOR["templates"]["form"] = "application_form/editor_journal.html" 

2296 

2297 # ~~->$ ManEdJournal:FormContext~~ 

2298 # ~~^-> EditorJournal:FormContext~~ 

2299 # ~~^-> ManEdJournal:FormProcessor~~ 

2300 MANED = deepcopy(EDITOR) 

2301 MANED["name"] = "admin" 

2302 MANED["fieldsets"] += [ 

2303 FieldSetDefinitions.REASSIGN["name"], 

2304 FieldSetDefinitions.OPTIONAL_VALIDATION["name"], 

2305 FieldSetDefinitions.SEAL["name"], 

2306 FieldSetDefinitions.CONTINUATIONS["name"] 

2307 ] 

2308 MANED["processor"] = application_processors.ManEdJournalReview 

2309 MANED["templates"]["form"] = "application_form/maned_journal.html" 

2310 

2311 # ~~->$ BulkEditJournal:FormContext~~ 

2312 # ~~^-> JournalForm:Crosswalk~~ 

2313 # ~~^-> ManEdJournal:FormProcessor~~ 

2314 BULK_EDIT = { 

2315 "name" : "bulk_edit", 

2316 "fieldsets" : [ 

2317 FieldSetDefinitions.BULK_EDIT["name"] 

2318 ], 

2319 "templates": { 

2320 "form" : "application_form/maned_journal_bulk_edit.html", 

2321 "default_field" : "application_form/_field.html", 

2322 "default_group" : "application_form/_group.html" 

2323 }, 

2324 "crosswalks": { 

2325 "obj2form": JournalFormXWalk.obj2form, 

2326 "form2obj": JournalFormXWalk.form2obj 

2327 }, 

2328 "processor": application_processors.ManEdBulkEdit 

2329 } 

2330 

2331####################################################### 

2332# Gather all of our form information in one place 

2333####################################################### 

2334 

2335APPLICATION_FORMS = { 

2336 "contexts": { 

2337 ApplicationContextDefinitions.PUBLIC["name"]: ApplicationContextDefinitions.PUBLIC, 

2338 ApplicationContextDefinitions.UPDATE["name"]: ApplicationContextDefinitions.UPDATE, 

2339 ApplicationContextDefinitions.READ_ONLY["name"]: ApplicationContextDefinitions.READ_ONLY, 

2340 ApplicationContextDefinitions.ASSOCIATE["name"]: ApplicationContextDefinitions.ASSOCIATE, 

2341 ApplicationContextDefinitions.EDITOR["name"]: ApplicationContextDefinitions.EDITOR, 

2342 ApplicationContextDefinitions.MANED["name"]: ApplicationContextDefinitions.MANED 

2343 }, 

2344 "fieldsets": {v['name']: v for k, v in FieldSetDefinitions.__dict__.items() if not k.startswith('_')}, 

2345 "fields": {v['name']: v for k, v in FieldDefinitions.__dict__.items() if not k.startswith('_')} 

2346} 

2347 

2348 

2349JOURNAL_FORMS = { 

2350 "contexts": { 

2351 JournalContextDefinitions.READ_ONLY["name"]: JournalContextDefinitions.READ_ONLY, 

2352 JournalContextDefinitions.BULK_EDIT["name"]: JournalContextDefinitions.BULK_EDIT, 

2353 JournalContextDefinitions.ASSOCIATE["name"]: JournalContextDefinitions.ASSOCIATE, 

2354 JournalContextDefinitions.EDITOR["name"]: JournalContextDefinitions.EDITOR, 

2355 JournalContextDefinitions.MANED["name"]: JournalContextDefinitions.MANED 

2356 }, 

2357 "fieldsets": APPLICATION_FORMS["fieldsets"], 

2358 "fields": APPLICATION_FORMS["fields"] 

2359} 

2360 

2361 

2362####################################################### 

2363# Options lists 

2364####################################################### 

2365 

2366def iso_country_list(field, formualic_context_name): 

2367 #~~-> Countries:Data~~ 

2368 cl = [{"display" : " ", "value" : ""}] 

2369 for v, d in country_options: 

2370 cl.append({"display": d, "value": v}) 

2371 return cl 

2372 

2373 

2374def iso_language_list(field, formulaic_context_name): 

2375 # ~~-> Languages:Data~~ 

2376 cl = [{"display" : " ", "value" : ""}] 

2377 for v, d in language_options: 

2378 cl.append({"display": d, "value": v}) 

2379 return cl 

2380 

2381 

2382def iso_currency_list(field, formulaic_context_name): 

2383 # ~~-> Currencies:Data~~ 

2384 cl = [{"display" : " ", "value" : ""}] 

2385 quick_pick = [] 

2386 for v, d in currency_options: 

2387 if v in ["GBP", "USD", "EUR"]: 

2388 quick_pick.append({"display": d, "value": v}) 

2389 cl.append({"display": d, "value": v}) 

2390 if len(quick_pick) > 0: 

2391 cl = quick_pick + cl 

2392 return cl 

2393 

2394 

2395def quick_reject(field, formulaic_context_name): 

2396 # ~~-> QuickReject:Feature~~ 

2397 return [{"display": "Other", "value" : ""}] + [{'display': v, 'value': v} for v in app.config.get('QUICK_REJECT_REASONS', [])] 

2398 

2399 

2400def application_statuses(field, formulaic_context): 

2401 # ~~->$ ApplicationStatus:Workflow~~ 

2402 _application_status_base = [ # This is all the Associate Editor sees 

2403 ('', ' '), 

2404 (constants.APPLICATION_STATUS_PENDING, 'Pending'), 

2405 (constants.APPLICATION_STATUS_IN_PROGRESS, 'In Progress'), 

2406 (constants.APPLICATION_STATUS_COMPLETED, 'Completed') 

2407 ] 

2408 

2409 _application_status_admin = _application_status_base + [ 

2410 (constants.APPLICATION_STATUS_UPDATE_REQUEST, 'Update Request'), 

2411 (constants.APPLICATION_STATUS_REVISIONS_REQUIRED, 'Revisions Required'), 

2412 (constants.APPLICATION_STATUS_ON_HOLD, 'On Hold'), 

2413 (constants.APPLICATION_STATUS_READY, 'Ready'), 

2414 (constants.APPLICATION_STATUS_REJECTED, 'Rejected'), 

2415 (constants.APPLICATION_STATUS_ACCEPTED, 'Accepted') 

2416 ] 

2417 

2418 _application_status_editor = _application_status_base + [ 

2419 (constants.APPLICATION_STATUS_READY, 'Ready'), 

2420 ] 

2421 

2422 formulaic_context_name = None 

2423 if formulaic_context is not None: 

2424 formulaic_context_name = formulaic_context.name 

2425 

2426 status_list = [] 

2427 if formulaic_context_name is None or formulaic_context_name == "admin": 

2428 status_list = _application_status_admin 

2429 elif formulaic_context_name == "editor": 

2430 status_list = _application_status_editor 

2431 elif formulaic_context_name == "accepted": 

2432 status_list = [(constants.APPLICATION_STATUS_ACCEPTED, 'Accepted')] # just the one status - Accepted 

2433 else: 

2434 status_list = _application_status_base 

2435 

2436 return [{'display': d, 'value': v} for (v, d) in status_list] 

2437 

2438 

2439def editor_choices(field, formulaic_context): 

2440 """ 

2441 Set the editor field choices from a given editor group name 

2442 ~~->EditorGroup:Model~~ 

2443 """ 

2444 egf = formulaic_context.get("editor_group") 

2445 wtf = egf.wtfield 

2446 if wtf is None: 

2447 return [{"display" : "", "value" : ""}] 

2448 

2449 editor_group_name = wtf.data 

2450 if editor_group_name is None: 

2451 return [{"display" : "", "value" : ""}] 

2452 else: 

2453 eg = EditorGroup.pull_by_key("name", editor_group_name) 

2454 if eg is not None: 

2455 editors = [eg.editor] 

2456 editors += eg.associates 

2457 editors = list(set(editors)) 

2458 return [{"value" : "", "display" : "No editor assigned"}] + [{"value" : editor, "display" : editor} for editor in editors] 

2459 else: 

2460 return [{"display" : "", "value" : ""}] 

2461 

2462####################################################### 

2463## Conditional disableds 

2464####################################################### 

2465 

2466def application_status_disabled(field, formulaic_context): 

2467 choices = application_statuses(field, formulaic_context) 

2468 field_value = field.wtfield.data 

2469 return field_value not in [c.get("value") for c in choices] 

2470 

2471 

2472####################################################### 

2473## Merge disabled 

2474####################################################### 

2475 

2476def merge_disabled_notes(notes_group, original_form): 

2477 # ~~->Notes:Feature~~ 

2478 merged = [] 

2479 wtf = notes_group.wtfield 

2480 for entry in wtf.entries: 

2481 if entry.data.get("note") != "" or entry.data.get("note_id") != "": 

2482 merged.append(entry.data) 

2483 for entry in original_form.notes.entries: 

2484 d = entry.data 

2485 for m in merged: 

2486 if m.get("note_id") != "" and m.get("note_id") == entry.data.get("note_id"): 

2487 # keep = False 

2488 if m.get("note") == "": 

2489 m["note"] = entry.data.get("note") 

2490 m["note_date"] = entry.data.get("note_date") 

2491 break 

2492 

2493 while True: 

2494 try: 

2495 wtf.pop_entry() 

2496 except IndexError: 

2497 break 

2498 

2499 for m in merged: 

2500 wtf.append_entry(m) 

2501 

2502####################################################### 

2503# Validation features 

2504####################################################### 

2505 

2506class ReservedUsernamesBuilder: 

2507 """ 

2508 ~~->$ ReservedUsernames:FormValidator~~ 

2509 """ 

2510 @staticmethod 

2511 def render(settings, html_attrs): 

2512 return 

2513 

2514 @staticmethod 

2515 def wtforms(field, settings): 

2516 return ReservedUsernames() 

2517 

2518 

2519class OwnerExistsBuilder: 

2520 """ 

2521 ~~->$ OwnerExists:FormValidator~~ 

2522 """ 

2523 @staticmethod 

2524 def render(settings, html_attrs): 

2525 return 

2526 

2527 @staticmethod 

2528 def wtforms(field, settings): 

2529 return OwnerExists() 

2530 

2531 

2532class RequiredBuilder: 

2533 """ 

2534 ~~->$ Required:FormValidator~~ 

2535 """ 

2536 @staticmethod 

2537 def render(settings, html_attrs): 

2538 html_attrs["required"] = "" 

2539 if "message" in settings: 

2540 html_attrs["data-parsley-required-message"] = "<p><small>" + settings["message"] + "</small></p>" 

2541 else: 

2542 html_attrs["data-parsley-required-message"] = "<p><small>" + "This answer is required" + "</p></small>" 

2543 html_attrs["data-parsley-validate-if-empty"] = "true" 

2544 

2545 @staticmethod 

2546 def wtforms(field, settings): 

2547 return CustomRequired(message=settings.get("message")) 

2548 

2549 

2550class IsURLBuilder: 

2551 # ~~->$ IsURL:FormValidator~~ 

2552 msg = "<p><small>" + "Please enter a valid URL. It should start with http or https" + "</p></small>" 

2553 

2554 @staticmethod 

2555 def render(settings, html_attrs): 

2556 html_attrs["type"] = "url" 

2557 html_attrs["pattern"] = regex.HTTP_URL 

2558 html_attrs["data-parsley-pattern"] = regex.HTTP_URL 

2559 html_attrs["data-parsley-pattern-message"] = IsURLBuilder.msg 

2560 

2561 @staticmethod 

2562 def wtforms(field, settings): 

2563 return HTTPURL(message=settings.get('message', IsURLBuilder.msg)) 

2564 

2565 

2566class IntRangeBuilder: 

2567 """ 

2568 ~~->$ IntRange:FormValidator~~ 

2569 ~~^-> NumberRange:FormValidator~~ 

2570 """ 

2571 @staticmethod 

2572 def render(settings, html_attrs): 

2573 html_attrs["data-parsley-type"] = "digits" 

2574 default_msg = "" 

2575 if "gte" in settings and "lte" in settings: 

2576 html_attrs["data-parsley-range"] = "[" + str(settings.get("gte")) + ", " + str(settings.get("lte")) + "]" 

2577 default_msg = "This value should be between " + str(settings.get("gte")) + " and " + str(settings.get("lte")) 

2578 else: 

2579 if "gte" in settings: 

2580 html_attrs["data-parsley-min"] = settings.get("gte") 

2581 default_msg = "This value should be bigger than " + str(settings.get("gte")) 

2582 if "lte" in settings: 

2583 html_attrs["data-parsley-max"] = settings.get("lte") 

2584 default_msg = "This value should be smaller than " + str(settings.get("gte")) 

2585 html_attrs["data-parsley-range-message"] = "<p><small>" + settings.get("message", default_msg) + "</p></small>" 

2586 

2587 @staticmethod 

2588 def wtforms(field, settings): 

2589 min = settings.get("gte") 

2590 max = settings.get("lte") 

2591 kwargs = {} 

2592 if min is not None: 

2593 kwargs["min"] = min 

2594 if max is not None: 

2595 kwargs["max"] = max 

2596 return validators.NumberRange(**kwargs) 

2597 

2598 

2599class MaxTagsBuilder: 

2600 """ 

2601 ~~->$ MaxLen:FormValidator~~ 

2602 """ 

2603 @staticmethod 

2604 def wtforms(field, settings): 

2605 max = settings.get("max") 

2606 message = settings.get("message") if "message" in settings else 'You can only enter up to {x} keywords.'.format(x=max) 

2607 return MaxLen(max, message=message) 

2608 

2609 

2610class StopWordsBuilder: 

2611 """ 

2612 ~~->$ StopWords:FormValidator~~ 

2613 """ 

2614 @staticmethod 

2615 def wtforms(field, settings): 

2616 stopwords = settings.get("disallowed", []) 

2617 return StopWords(stopwords) 

2618 

2619 

2620class ISSNInPublicDOAJBuilder: 

2621 """ 

2622 ~~->$ ISSNInPublicDOAJ:FormValidator~~ 

2623 """ 

2624 @staticmethod 

2625 def render(settings, html_attrs): 

2626 # FIXME: not yet implemented in the front end, so setting here is speculative 

2627 html_attrs["data-parsley-issn-in-public-doaj"] = "" 

2628 

2629 @staticmethod 

2630 def wtforms(field, settings): 

2631 return ISSNInPublicDOAJ(message=settings.get("message")) 

2632 

2633 

2634class JournalURLInPublicDOAJBuilder: 

2635 # ~~->$ JournalURLInPublicDOAJ:FormValidator~~ 

2636 @staticmethod 

2637 def render(settings, html_attrs): 

2638 # FIXME: not yet implemented in the front end, so setting here is speculative 

2639 html_attrs["data-parsley-journal-url-in-public-doaj"] = "" 

2640 

2641 @staticmethod 

2642 def wtforms(field, settings): 

2643 return JournalURLInPublicDOAJ(message=settings.get("message")) 

2644 

2645 

2646class NoScriptTagBuilder: 

2647 # ~~->$ NoScriptTag:FormValidator 

2648 @staticmethod 

2649 def render(settings, html_attrs): 

2650 html_attrs["data-parsley-no-script-tag"] = "" 

2651 if "message" in settings: 

2652 html_attrs["data-parsley-noScriptTag-message"] = "<p><small>" + settings["message"] + "</small></p>" 

2653 else: 

2654 html_attrs["data-parsley-no-script-tag-message"] = "<p><small>" + "No script tags allowed" + "</p></small>" 

2655 

2656 @staticmethod 

2657 def wtforms(field, settings): 

2658 return NoScriptTag(settings.get("message", "No script tags allowed")) 

2659 

2660 

2661class OptionalIfBuilder: 

2662 # ~~->$ OptionalIf:FormValidator~~ 

2663 @staticmethod 

2664 def render(settings, html_attrs): 

2665 html_attrs["data-parsley-validate-if-empty"] = "true" 

2666 html_attrs["data-parsley-optional-if"] = settings.get("field") 

2667 html_attrs["data-parsley-optional-if-message"] = "<p><small>" + settings.get("message") + "</p></small>" 

2668 

2669 @staticmethod 

2670 def wtforms(field, settings): 

2671 return OptionalIf(settings.get("field") or field, settings.get("message"), settings.get("values", [])) 

2672 

2673 

2674class IsISSNBuilder: 

2675 # ~~->$ IsISSN:FormValidator~~ 

2676 @staticmethod 

2677 def render(settings, html_attrs): 

2678 html_attrs["pattern"] = ISSN 

2679 html_attrs["data-parsley-pattern"] = ISSN 

2680 html_attrs["data-parsley-pattern-message"] = settings.get("message") 

2681 

2682 @staticmethod 

2683 def wtforms(field, settings): 

2684 return validators.Regexp(regex=ISSN_COMPILED, message=settings.get("message")) 

2685 

2686 

2687class IsISSNListBuilder: 

2688 # ~~->$ IsISSNList:FormValidator~~ 

2689 @staticmethod 

2690 def render(settings, html_attrs): 

2691 html_attrs["data-parsley-entry-pattern"] = ISSN 

2692 

2693 @staticmethod 

2694 def wtforms(field, settings): 

2695 return RegexpOnTagList(regex=ISSN_COMPILED, message=settings.get("message")) 

2696 

2697 

2698class DifferentToBuilder: 

2699 # ~~->$ DifferentTo:FormValidator~~ 

2700 @staticmethod 

2701 def render(settings, html_attrs): 

2702 html_attrs["data-parsley-different-to"] = settings.get("field") 

2703 

2704 @staticmethod 

2705 def wtforms(field, settings): 

2706 return DifferentTo(settings.get("field") or field, settings.get("ignore_empty", True), settings.get("message")) 

2707 

2708 

2709class RequiredIfBuilder: 

2710 # ~~->$ RequiredIf:FormValidator~~ 

2711 @staticmethod 

2712 def render(settings, html_attrs): 

2713 val = settings.get("value") 

2714 if isinstance(val, list): 

2715 val = ",".join(val) 

2716 

2717 html_attrs["data-parsley-validate-if-empty"] = "true" 

2718 html_attrs["data-parsley-required-if"] = val 

2719 html_attrs["data-parsley-required-if-field"] = settings.get("field") 

2720 if "message" in settings: 

2721 html_attrs["data-parsley-required-if-message"] = "<p><small>" + settings["message"] + "</small></p>" 

2722 else: 

2723 html_attrs["data-parsley-required-if-message"] = "<p><small>" + "This answer is required" + "</small></p>" 

2724 

2725 @staticmethod 

2726 def wtforms(field, settings): 

2727 return RequiredIfOtherValue(settings.get("field") or field, settings.get("value"), settings.get("message")) 

2728 

2729 

2730class OnlyIfBuilder: 

2731 # ~~->$ OnlyIf:FormValidator~~ 

2732 @staticmethod 

2733 def render(settings, html_attrs): 

2734 html_attrs["data-parsley-only-if"] = ",".join([f["field"] for f in settings.get("fields", [])]) 

2735 for f in settings.get('fields'): 

2736 if "value" in f: 

2737 html_attrs["data-parsley-only-if-value_" + f["field"]] = f["value"] 

2738 if "not" in f: 

2739 html_attrs["data-parsley-only-if-not_" + f["field"]] = f["not"] 

2740 if "or" in f: 

2741 html_attrs["data-parsley-only-if-or_" + f["field"]] = ",".join(f["or"]) 

2742 html_attrs["data-parsley-only-if-message"] = settings.get("message") 

2743 

2744 @staticmethod 

2745 def wtforms(fields, settings): 

2746 return OnlyIf(settings.get('fields') or fields, settings.get('message')) 

2747 

2748 

2749class NotIfBuildier: 

2750 # ~~->$ NotIf:FormValidator~~ 

2751 @staticmethod 

2752 def render(settings, html_attrs): 

2753 html_attrs["data-parsley-not-if"] = ",".join([f.get("field") for f in settings.get("fields", [])]) 

2754 if settings.get("message"): 

2755 html_attrs["data-parsley-not-if-message"] = settings.get("message") 

2756 

2757 @staticmethod 

2758 def wtforms(fields, settings): 

2759 return NotIf(settings.get('fields') or fields, settings.get('message')) 

2760 

2761 

2762class GroupMemberBuilder: 

2763 # ~~->$ GroupMember:FormValidator~~ 

2764 @staticmethod 

2765 def render(settings, html_attrs): 

2766 # FIXME: front end validator for this does not yet exist (do we have an existing one from formcontext?) 

2767 html_attrs["data-parsley-group-member-field"] = settings.get("group_field") 

2768 

2769 @staticmethod 

2770 def wtforms(field, settings): 

2771 return GroupMember(settings.get('group_field') or field) 

2772 

2773 

2774class RequiredValueBuilder: 

2775 # ~~->$ RequiredValue:FormValidator~~ 

2776 @staticmethod 

2777 def render(settings, html_attrs): 

2778 html_attrs["data-parsley-requiredvalue"] = settings.get("value") 

2779 

2780 @staticmethod 

2781 def wtforms(field, settings): 

2782 return RequiredValue(settings.get("value"), settings.get("message")) 

2783 

2784 

2785class BigEndDateBuilder: 

2786 # ~~->$ BigEndDate:FormValidator~~ 

2787 @staticmethod 

2788 def render(settings, html_attrs): 

2789 html_attrs["data-parsley-pattern"] = "\d{4}-\d{2}-\d{2}" 

2790 html_attrs["data-parsley-pattern-message"] = settings.get("message") 

2791 

2792 @staticmethod 

2793 def wtforms(field, settings): 

2794 return BigEndDate(settings.get("message")) 

2795 

2796class YearBuilder: 

2797 @staticmethod 

2798 def render(settings, html_attrs): 

2799 html_attrs["data-parsley-year"] = app.config.get('MINIMAL_OA_START_DATE', 1900) 

2800 html_attrs["data-parsley-year-message"] = "<p><small>" + settings["message"] + "</small></p>" 

2801 

2802 def wtforms(field, settings): 

2803 return Year(settings.get("message")) 

2804 

2805 

2806######################################################### 

2807# Crosswalks 

2808######################################################### 

2809 

2810PYTHON_FUNCTIONS = { 

2811 "options": { 

2812 "iso_country_list": iso_country_list, 

2813 "iso_language_list": iso_language_list, 

2814 "iso_currency_list": iso_currency_list, 

2815 "quick_reject" : quick_reject, 

2816 "application_statuses" : application_statuses, 

2817 "editor_choices" : editor_choices 

2818 }, 

2819 "disabled" : { 

2820 "application_status_disabled" : application_status_disabled 

2821 }, 

2822 "merge_disabled" : { 

2823 "merge_disabled_notes" : merge_disabled_notes 

2824 }, 

2825 "validate": { 

2826 "render": { 

2827 "required": RequiredBuilder.render, 

2828 "is_url": IsURLBuilder.render, 

2829 "int_range": IntRangeBuilder.render, 

2830 "issn_in_public_doaj": ISSNInPublicDOAJBuilder.render, 

2831 "journal_url_in_public_doaj" : JournalURLInPublicDOAJBuilder.render, 

2832 "optional_if": OptionalIfBuilder.render, 

2833 "is_issn": IsISSNBuilder.render, 

2834 "is_issn_list": IsISSNListBuilder.render, 

2835 "different_to": DifferentToBuilder.render, 

2836 "required_if": RequiredIfBuilder.render, 

2837 "only_if" : OnlyIfBuilder.render, 

2838 "group_member" : GroupMemberBuilder.render, 

2839 "not_if" : NotIfBuildier.render, 

2840 "required_value" : RequiredValueBuilder.render, 

2841 "bigenddate": BigEndDateBuilder.render, 

2842 "no_script_tag": NoScriptTagBuilder.render, 

2843 "year": YearBuilder.render 

2844 }, 

2845 "wtforms": { 

2846 "required": RequiredBuilder.wtforms, 

2847 "is_url": IsURLBuilder.wtforms, 

2848 "max_tags": MaxTagsBuilder.wtforms, 

2849 "int_range": IntRangeBuilder.wtforms, 

2850 "stop_words": StopWordsBuilder.wtforms, 

2851 "issn_in_public_doaj": ISSNInPublicDOAJBuilder.wtforms, 

2852 "journal_url_in_public_doaj" : JournalURLInPublicDOAJBuilder.wtforms, 

2853 "optional_if": OptionalIfBuilder.wtforms, 

2854 "is_issn": IsISSNBuilder.wtforms, 

2855 "is_issn_list": IsISSNListBuilder.wtforms, 

2856 "different_to": DifferentToBuilder.wtforms, 

2857 "required_if": RequiredIfBuilder.wtforms, 

2858 "only_if" : OnlyIfBuilder.wtforms, 

2859 "group_member" : GroupMemberBuilder.wtforms, 

2860 "not_if" : NotIfBuildier.wtforms, 

2861 "required_value" : RequiredValueBuilder.wtforms, 

2862 "bigenddate": BigEndDateBuilder.wtforms, 

2863 "reserved_usernames" : ReservedUsernamesBuilder.wtforms, 

2864 "owner_exists" : OwnerExistsBuilder.wtforms, 

2865 "no_script_tag": NoScriptTagBuilder.wtforms, 

2866 "year": YearBuilder.wtforms, 

2867 } 

2868 } 

2869} 

2870 

2871JAVASCRIPT_FUNCTIONS = { 

2872 "clickable_url": "formulaic.widgets.newClickableUrl", # ~~-> ClickableURL:FormWidget~~ 

2873 "clickable_owner": "formulaic.widgets.newClickableOwner", # ~~-> ClickableOwner:FormWidget~~ 

2874 "select": "formulaic.widgets.newSelect", # ~~-> SelectBox:FormWidget~~ 

2875 "taglist": "formulaic.widgets.newTagList", # ~~-> TagList:FormWidget~~ 

2876 "tagentry" : "formulaic.widgets.newTagEntry", # ~~-> TagEntry:FormWidget~~ 

2877 "multiple_field": "formulaic.widgets.newMultipleField", # ~~-> MultiField:FormWidget~~ 

2878 "infinite_repeat": "formulaic.widgets.newInfiniteRepeat", # ~~-> InfiniteRepeat:FormWidget~~ 

2879 "autocomplete": "formulaic.widgets.newAutocomplete", # ~~-> Autocomplete:FormWidget~~ 

2880 "subject_tree" : "formulaic.widgets.newSubjectTree", # ~~-> SubjectTree:FormWidget~~ 

2881 "full_contents" : "formulaic.widgets.newFullContents", # ~~^->FullContents:FormWidget~~ 

2882 "load_editors" : "formulaic.widgets.newLoadEditors", # ~~-> LoadEditors:FormWidget~~ 

2883 "trim_whitespace" : "formulaic.widgets.newTrimWhitespace", # ~~-> TrimWhitespace:FormWidget~~ 

2884 "note_modal" : "formulaic.widgets.newNoteModal" # ~~-> NoteModal:FormWidget~~ 

2885} 

2886 

2887 

2888############################################################## 

2889# A couple of convenient widgets for WTForms rendering 

2890############################################################## 

2891 

2892class NumberWidget(widgets.Input): 

2893 input_type = 'number' 

2894 

2895 

2896class ListWidgetWithSubfields(object): 

2897 """ 

2898 Renders a list of fields as a `ul` or `ol` list. 

2899 

2900 This is used for fields which encapsulate many inner fields as subfields. 

2901 The widget will try to iterate the field to get access to the subfields and 

2902 call them to render them. 

2903 

2904 If `prefix_label` is set, the subfield's label is printed before the field, 

2905 otherwise afterwards. The latter is useful for iterating radios or 

2906 checkboxes. 

2907 """ 

2908 

2909 def __init__(self, html_tag='ul', prefix_label=False): 

2910 assert html_tag in ('ol', 'ul') 

2911 self.html_tag = html_tag 

2912 self.prefix_label = prefix_label 

2913 

2914 def __call__(self, field, **kwargs): 

2915 # kwargs.setdefault('id', field.id) 

2916 fl = kwargs.pop("formulaic", None) 

2917 html = ['<%s %s>' % (self.html_tag, html_params(**kwargs))] 

2918 for subfield in field: 

2919 if self.prefix_label: 

2920 html.append('<li tabindex=0>%s %s' % (subfield.label, subfield(**kwargs))) 

2921 else: 

2922 html.append('<li tabindex=0>%s %s' % (subfield(**kwargs), subfield.label)) 

2923 

2924 html.append("</li>") 

2925 

2926 html.append('</%s>' % self.html_tag) 

2927 return HTMLString(''.join(html)) 

2928 

2929########################################################## 

2930# Mapping from configurations to WTForms builders 

2931########################################################## 

2932 

2933class RadioBuilder(WTFormsBuilder): 

2934 @staticmethod 

2935 def match(field): 

2936 return field.get("input") == "radio" 

2937 

2938 @staticmethod 

2939 def wtform(formulaic_context, field, wtfargs): 

2940 wtfargs["widget"] = ListWidgetWithSubfields() 

2941 return UnconstrainedRadioField(**wtfargs) 

2942 

2943 

2944class MultiCheckboxBuilder(WTFormsBuilder): 

2945 @staticmethod 

2946 def match(field): 

2947 return field.get("input") == "checkbox" and \ 

2948 (len(field.get("options", [])) > 0 or field.get("options_fn") is not None) 

2949 

2950 @staticmethod 

2951 def wtform(formulaic_context, field, wtfargs): 

2952 wtfargs["option_widget"] = widgets.CheckboxInput() 

2953 wtfargs["widget"] = ListWidgetWithSubfields() 

2954 return SelectMultipleField(**wtfargs) 

2955 

2956 

2957class SingleCheckboxBuilder(WTFormsBuilder): 

2958 @staticmethod 

2959 def match(field): 

2960 return field.get("input") == "checkbox" and len(field.get("options", [])) == 0 and field.get( 

2961 "options_fn") is None 

2962 

2963 @staticmethod 

2964 def wtform(formulaic_context, field, wtfargs): 

2965 return BooleanField(**wtfargs) 

2966 

2967 

2968class SelectBuilder(WTFormsBuilder): 

2969 @staticmethod 

2970 def match(field): 

2971 return field.get("input") == "select" and not field.get("multiple", False) 

2972 

2973 @staticmethod 

2974 def wtform(formulaic_context, field, wtfargs): 

2975 sf = SelectField(**wtfargs) 

2976 if "repeatable" in field: 

2977 sf = FieldList(sf, min_entries=field.get("repeatable", {}).get("initial", 1)) 

2978 

2979 return sf 

2980 

2981 

2982class MultiSelectBuilder(WTFormsBuilder): 

2983 @staticmethod 

2984 def match(field): 

2985 return field.get("input") == "select" and field.get("multiple", False) 

2986 

2987 @staticmethod 

2988 def wtform(formulaic_context, field, wtfargs): 

2989 return SelectMultipleField(**wtfargs) 

2990 

2991 

2992class TextBuilder(WTFormsBuilder): 

2993 @staticmethod 

2994 def match(field): 

2995 return field.get("input") == "text" 

2996 

2997 @staticmethod 

2998 def wtform(formulaic_context, field, wtfargs): 

2999 if "filters" not in wtfargs: 

3000 wtfargs["filters"] = (lambda x: x.strip() if x is not None else x,) 

3001 sf = StringField(**wtfargs) 

3002 if "repeatable" in field: 

3003 sf = FieldList(sf, min_entries=field.get("repeatable", {}).get("initial", 1)) 

3004 return sf 

3005 

3006 

3007class TextAreaBuilder(WTFormsBuilder): 

3008 @staticmethod 

3009 def match(field): 

3010 return field.get("input") == "textarea" 

3011 

3012 @staticmethod 

3013 def wtform(formulaic_context, field, wtfargs): 

3014 sf = TextAreaField(**wtfargs) 

3015 if "repeatable" in field: 

3016 sf = FieldList(sf, min_entries=field.get("repeatable", {}).get("initial", 1)) 

3017 return sf 

3018 

3019 

3020class TagListBuilder(WTFormsBuilder): 

3021 @staticmethod 

3022 def match(field): 

3023 return field.get("input") == "taglist" 

3024 

3025 @staticmethod 

3026 def wtform(formulaic_context, field, wtfargs): 

3027 return TagListField(**wtfargs) 

3028 

3029 

3030class IntegerBuilder(WTFormsBuilder): 

3031 @staticmethod 

3032 def match(field): 

3033 return field.get("input") == "number" and field.get("datatype") == "integer" 

3034 

3035 @staticmethod 

3036 def wtform(formulaic_context, field, wtfargs): 

3037 wtfargs["widget"] = NumberWidget() 

3038 return IntegerField(**wtfargs) 

3039 

3040 

3041# TODO: multiple group doesn't work 

3042class GroupBuilder(WTFormsBuilder): 

3043 @staticmethod 

3044 def match(field): 

3045 return field.get("input") == "group" and field.get("repeatable") is None 

3046 

3047 @staticmethod 

3048 def wtform(formulaic_context, field, wtfargs): 

3049 fields = [formulaic_context.get(subfield) for subfield in field.get("subfields", [])] 

3050 klazz = formulaic_context.make_wtform_class(fields) 

3051 return NestedFormField(klazz) 

3052 

3053 

3054class GroupListBuilder(WTFormsBuilder): 

3055 @staticmethod 

3056 def match(field): 

3057 return field.get("input") == "group" and field.get("repeatable") is not None 

3058 

3059 @staticmethod 

3060 def wtform(formulaic_context, field, wtfargs): 

3061 ff = GroupBuilder.wtform(formulaic_context, field, wtfargs) 

3062 repeat_cfg = field.get("repeatable", {}) 

3063 return FieldList(ff, min_entries=repeat_cfg.get("initial", 1)) 

3064 

3065 

3066class HiddenFieldBuilder(WTFormsBuilder): 

3067 @staticmethod 

3068 def match(field): 

3069 return field.get("input") == "hidden" 

3070 

3071 @staticmethod 

3072 def wtform(formulaic_context, field, wtfargs): 

3073 return HiddenField(**wtfargs) 

3074 

3075 

3076 

3077WTFORMS_BUILDERS = [ 

3078 RadioBuilder, 

3079 MultiCheckboxBuilder, 

3080 SingleCheckboxBuilder, 

3081 SelectBuilder, 

3082 MultiSelectBuilder, 

3083 TextBuilder, 

3084 TextAreaBuilder, 

3085 TagListBuilder, 

3086 IntegerBuilder, 

3087 GroupBuilder, 

3088 GroupListBuilder, 

3089 HiddenFieldBuilder 

3090] 

3091 

3092 

3093ApplicationFormFactory = Formulaic(APPLICATION_FORMS, WTFORMS_BUILDERS, function_map=PYTHON_FUNCTIONS, javascript_functions=JAVASCRIPT_FUNCTIONS) 

3094JournalFormFactory = Formulaic(JOURNAL_FORMS, WTFORMS_BUILDERS, function_map=PYTHON_FUNCTIONS, javascript_functions=JAVASCRIPT_FUNCTIONS) 

3095 

3096 

3097if __name__ == "__main__": 

3098 """ 

3099 Running this file from the command line enables you to output documentation for a given form context. 

3100 

3101 See `docs/forms.sh` for where this is used 

3102 

3103 To create the documentation you can call this file with 3 arguments: 

3104 

3105 -t - the object type to output. Either 'journal' or 'application' 

3106 -c - the form context. Will be one of the contexts defined elsewhere in this file, which may be specific to the 

3107 object type. For example, 'admin' or 'editor' 

3108 -o - the path to the file where to output the result 

3109 

3110 The output is a CSV which lists the following information: 

3111 

3112 * Form Position - the position in the form. Felds are listed in order 

3113 * Field Name - the form field name 

3114 * Label - the form field label 

3115 * Input Type - what kind of input (e.g. radio, text) 

3116 * Options - the express options allowed, or the name of the function which generates the options 

3117 * Disabled? - is the field disabled in this context 

3118 * Fieldset ID - the ID (from this file) of the fieldset that this field is part of 

3119 """ 

3120 import argparse 

3121 

3122 parser = argparse.ArgumentParser() 

3123 parser.add_argument("-t", "--type", help="object type to output") 

3124 parser.add_argument("-c", "--context", help="context to output") 

3125 parser.add_argument("-o", "--out", help="output file path") 

3126 args = parser.parse_args() 

3127 

3128 if not args.out: 

3129 print("Please specify an output file path with the -o option") 

3130 parser.print_help() 

3131 exit() 

3132 

3133 if not args.context: 

3134 print("Please specify a context to output") 

3135 parser.print_help() 

3136 exit() 

3137 

3138 if not args.type: 

3139 print("Please specify a type to output") 

3140 parser.print_help() 

3141 exit() 

3142 

3143 fc = None 

3144 if args.type == "journal": 

3145 fc = JournalFormFactory.context(args.context) 

3146 elif args.type == "application": 

3147 fc = ApplicationFormFactory.context(args.context) 

3148 

3149 if fc is not None: 

3150 fc.to_summary_csv(args.out) 

3151 else: 

3152 print("You did not enter a valid type. Use one of 'journal' or 'application'")