Coverage for portality/models/v2/bibjson.py: 93%

667 statements  

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

1from portality.lib.seamless import SeamlessMixin, to_utf8_unicode 

2from portality.models.v2 import shared_structs 

3from portality import datasets 

4from portality.lib import coerce 

5 

6class JournalLikeBibJSON(SeamlessMixin): 

7 

8 __SEAMLESS_STRUCT__ = shared_structs.JOURNAL_BIBJSON.get("structs", {}).get("bibjson") 

9 

10 __SEAMLESS_COERCE__ = coerce.COERCE_MAP 

11 

12 # constructor 

13 def __init__(self, bibjson=None, **kwargs): 

14 super(JournalLikeBibJSON, self).__init__(raw=bibjson, **kwargs) 

15 

16 @property 

17 def data(self): 

18 return self.__seamless__.data 

19 

20 #################################################### 

21 # Current getters and setters 

22 

23 @property 

24 def alternative_title(self): 

25 return self.__seamless__.get_single("alternative_title") 

26 

27 @alternative_title.setter 

28 def alternative_title(self, val): 

29 self.__seamless__.set_with_struct("alternative_title", val) 

30 

31 @property 

32 def boai(self): 

33 return self.__seamless__.get_single("boai") 

34 

35 @boai.setter 

36 def boai(self, val): 

37 self.__seamless__.set_with_struct("boai", val) 

38 

39 @property 

40 def discontinued_date(self): 

41 return self.__seamless__.get_single("discontinued_date") 

42 

43 @discontinued_date.setter 

44 def discontinued_date(self, val): 

45 self.__seamless__.set_with_struct("discontinued_date", val) 

46 

47 @discontinued_date.deleter 

48 def discontinued_date(self): 

49 self.__seamless__.delete("discontinued_date") 

50 

51 @property 

52 def discontinued_datestamp(self): 

53 return self.__seamless__.get_single("discontinued_date", coerce=coerce.to_datestamp()) 

54 

55 @property 

56 def eissn(self): 

57 return self.__seamless__.get_single("eissn") 

58 

59 @eissn.setter 

60 def eissn(self, val): 

61 self.__seamless__.set_with_struct("eissn", val) 

62 

63 @eissn.deleter 

64 def eissn(self): 

65 self.__seamless__.delete("eissn") 

66 

67 @property 

68 def pissn(self): 

69 return self.__seamless__.get_single("pissn") 

70 

71 @pissn.setter 

72 def pissn(self, val): 

73 self.__seamless__.set_with_struct("pissn", val) 

74 

75 @pissn.deleter 

76 def pissn(self): 

77 self.__seamless__.delete("pissn") 

78 

79 @property 

80 def oa_start(self): 

81 return self.__seamless__.get_single("oa_start") 

82 

83 @oa_start.setter 

84 def oa_start(self, val): 

85 self.__seamless__.set_with_struct("oa_start", val) 

86 

87 @oa_start.deleter 

88 def oa_start(self): 

89 self.__seamless__.delete("oa_start") 

90 

91 @property 

92 def publication_time_weeks(self): 

93 return self.__seamless__.get_single("publication_time_weeks") 

94 

95 @publication_time_weeks.setter 

96 def publication_time_weeks(self, weeks): 

97 self.__seamless__.set_with_struct("publication_time_weeks", weeks) 

98 

99 @property 

100 def title(self): 

101 return self.__seamless__.get_single("title") 

102 

103 @title.setter 

104 def title(self, val): 

105 self.__seamless__.set_with_struct("title", val) 

106 

107 @property 

108 def is_replaced_by(self): 

109 return self.__seamless__.get_list("is_replaced_by") 

110 

111 @is_replaced_by.setter 

112 def is_replaced_by(self, val): 

113 self.__seamless__.set_with_struct("is_replaced_by", val) 

114 

115 @is_replaced_by.deleter 

116 def is_replaced_by(self): 

117 self.__seamless__.delete("is_replaced_by") 

118 

119 def add_is_replaced_by(self, val): 

120 self.__seamless__.add_to_list_with_struct("is_replaced_by", val) 

121 

122 @property 

123 def keywords(self): 

124 return self.__seamless__.get_list("keywords") 

125 

126 def add_keyword(self, keyword): 

127 if keyword is not None: 

128 self.__seamless__.add_to_list_with_struct("keywords", keyword.lower()) 

129 

130 @keywords.setter 

131 def keywords(self, keywords): 

132 self.__seamless__.set_with_struct("keywords", keywords) 

133 

134 @property 

135 def language(self): 

136 return self.__seamless__.get_list("language") 

137 

138 @language.setter 

139 def language(self, language): 

140 self.__seamless__.set_with_struct("language", language) 

141 

142 def add_language(self, language): 

143 self.__seamless__.add_to_list_with_struct("language", language) 

144 

145 @property 

146 def licenses(self): 

147 return self.__seamless__.get_list("license") 

148 

149 @property 

150 def licences(self): 

151 return self.licenses 

152 

153 def add_licence(self, license_type, url=None, by=None, sa=None, nc=None, nd=None): 

154 self.add_license(license_type, url, by, sa, nc, nd) 

155 

156 def add_license(self, license_type, url=None, by=None, sa=None, nc=None, nd=None): 

157 lobj = {"type": license_type} 

158 if url is not None: 

159 lobj["url"] = url 

160 if by is not None: 

161 lobj["BY"] = by 

162 if sa is not None: 

163 lobj["SA"] = sa 

164 if nc is not None: 

165 lobj["NC"] = nc 

166 if nd is not None: 

167 lobj["ND"] = nd 

168 

169 self.__seamless__.add_to_list_with_struct("license", lobj) 

170 

171 def remove_licenses(self): 

172 self.__seamless__.delete("license") 

173 

174 @property 

175 def replaces(self): 

176 return self.__seamless__.get_list("replaces") 

177 

178 @replaces.setter 

179 def replaces(self, val): 

180 self.__seamless__.set_with_struct("replaces", val) 

181 

182 @replaces.deleter 

183 def replaces(self): 

184 self.__seamless__.delete("replaces") 

185 

186 def add_replaces(self, val): 

187 self.__seamless__.add_to_list_with_struct("replaces", val) 

188 

189 @property 

190 def subject(self): 

191 return self.__seamless__.get_list("subject") 

192 

193 @subject.setter 

194 def subject(self, subjects): 

195 self.__seamless__.set_with_struct("subject", subjects) 

196 

197 @subject.deleter 

198 def subject(self): 

199 self.__seamless__.delete("subject") 

200 

201 def add_subject(self, scheme, term, code=None): 

202 sobj = {"scheme": scheme, "term": term} 

203 if code is not None: 

204 sobj["code"] = code 

205 self.__seamless__.add_to_list_with_struct("subject", sobj) 

206 

207 @property 

208 def apc(self): 

209 return self.__seamless__.get_list("apc.max") 

210 

211 def add_apc(self, currency, price): 

212 self.__seamless__.add_to_list_with_struct("apc.max", {"currency": currency, "price" : price}) 

213 self.__seamless__.set_with_struct("apc.has_apc", True) 

214 

215 @property 

216 def apc_url(self): 

217 return self.__seamless__.get_single("apc.url") 

218 

219 @apc_url.setter 

220 def apc_url(self, url): 

221 self.__seamless__.set_with_struct("apc.url", url) 

222 

223 @property 

224 def has_apc(self): 

225 return self.__seamless__.get_single("apc.has_apc") 

226 

227 @has_apc.setter 

228 def has_apc(self, val): 

229 self.__seamless__.set_with_struct("apc.has_apc", val) 

230 

231 @property 

232 def article_license_display(self): 

233 return self.__seamless__.get_list("article.license_display") 

234 

235 @article_license_display.setter 

236 def article_license_display(self, val): 

237 self.__seamless__.set_with_struct("article.license_display", val) 

238 

239 # I've taken this out but left the commented code here to remind us. It used to be that you could 

240 # have multiple license displays, but now you can't. The data model still allows for it, but the 

241 # model should not, unless we reverse that decision at some point in the future 

242 # def add_article_license_display(self, val): 

243 # self.__seamless__.add_to_list_with_struct("article.license_display", val) 

244 

245 @property 

246 def article_license_display_example_url(self): 

247 return self.__seamless__.get_single("article.license_display_example_url") 

248 

249 @article_license_display_example_url.setter 

250 def article_license_display_example_url(self, url): 

251 self.__seamless__.set_with_struct("article.license_display_example_url", url) 

252 

253 @property 

254 def article_orcid(self): 

255 return self.__seamless__.get_single("article.orcid") 

256 

257 @article_orcid.setter 

258 def article_orcid(self, val): 

259 self.__seamless__.set_with_struct("article.orcid", val) 

260 

261 @property 

262 def article_i4oc_open_citations(self): 

263 return self.__seamless__.get_single("article.i4oc_open_citations") 

264 

265 @article_i4oc_open_citations.setter 

266 def article_i4oc_open_citations(self, val): 

267 self.__seamless__.set_with_struct("article.i4oc_open_citations", val) 

268 

269 @property 

270 def author_retains_copyright(self): 

271 return self.__seamless__.get_single("copyright.author_retains") 

272 

273 @author_retains_copyright.setter 

274 def author_retains_copyright(self, val): 

275 self.__seamless__.set_single("copyright.author_retains", val) 

276 

277 @property 

278 def copyright_url(self): 

279 return self.__seamless__.get_single("copyright.url") 

280 

281 @copyright_url.setter 

282 def copyright_url(self, url): 

283 self.__seamless__.set_with_struct("copyright.url", url) 

284 

285 @property 

286 def deposit_policy(self): 

287 return self.__seamless__.get_list("deposit_policy.service") 

288 

289 @deposit_policy.setter 

290 def deposit_policy(self, policies): 

291 self.__seamless__.set_with_struct("deposit_policy.service", policies) 

292 if len(policies) > 0: 

293 self.__seamless__.set_with_struct("deposit_policy.has_policy", True) 

294 

295 def add_deposit_policy(self, policy): 

296 self.__seamless__.add_to_list_with_struct("deposit_policy.service", policy) 

297 self.__seamless__.set_with_struct("deposit_policy.has_policy", True) 

298 

299 @property 

300 def has_deposit_policy(self): 

301 return self.__seamless__.get_single("deposit_policy.has_policy") 

302 

303 @has_deposit_policy.setter 

304 def has_deposit_policy(self, val): 

305 self.__seamless__.set_with_struct("deposit_policy.has_policy", val) 

306 

307 @property 

308 def deposit_policy_url(self): 

309 return self.__seamless__.get_single("deposit_policy.url") 

310 

311 @deposit_policy_url.setter 

312 def deposit_policy_url(self, url): 

313 self.__seamless__.set_with_struct("deposit_policy.url", url) 

314 

315 def set_unregistered_journal_policy(self, url): 

316 self.deposit_policy_url = url 

317 self.has_deposit_policy = True 

318 

319 def set_editorial_review(self, process, review_url, board_url=None): 

320 self.__seamless__.set_with_struct("editorial.review_process", process) 

321 self.__seamless__.set_with_struct("editorial.review_url", review_url) 

322 if board_url is not None: 

323 self.__seamless__.set_with_struct("editorial.board_url", board_url) 

324 

325 def add_editorial_review_process(self, process): 

326 self.__seamless__.add_to_list_with_struct("editorial.review_process", process) 

327 

328 @property 

329 def editorial_review_process(self): 

330 return self.__seamless__.get_list("editorial.review_process") 

331 

332 @property 

333 def editorial_review_url(self): 

334 return self.__seamless__.get_single("editorial.review_url") 

335 

336 @editorial_review_url.setter 

337 def editorial_review_url(self, url): 

338 self.__seamless__.set_with_struct("editorial.review_url", url) 

339 

340 @property 

341 def editorial_board_url(self): 

342 return self.__seamless__.get_single("editorial.board_url") 

343 

344 @editorial_board_url.setter 

345 def editorial_board_url(self, url): 

346 self.__seamless__.set_with_struct("editorial.board_url", url) 

347 

348 @property 

349 def institution_name(self): 

350 return self.__seamless__.get_single("institution.name") 

351 

352 @institution_name.setter 

353 def institution_name(self, val): 

354 self.__seamless__.set_with_struct("institution.name", val) 

355 

356 @property 

357 def institution_country(self): 

358 return self.__seamless__.get_single("institution.country") 

359 

360 @institution_country.setter 

361 def institution_country(self, country): 

362 self.__seamless__.set_with_struct("institution.country", country) 

363 

364 @property 

365 def has_other_charges(self): 

366 return self.__seamless__.get_single("other_charges.has_other_charges") 

367 

368 @has_other_charges.setter 

369 def has_other_charges(self, val): 

370 self.__seamless__.set_with_struct("other_charges.has_other_charges", val) 

371 

372 @property 

373 def other_charges_url(self): 

374 return self.__seamless__.get_single("other_charges.url") 

375 

376 @other_charges_url.setter 

377 def other_charges_url(self, url): 

378 self.__seamless__.set_with_struct("other_charges.url", url) 

379 

380 @property 

381 def pid_scheme(self): 

382 return self.__seamless__.get_list("pid_scheme.scheme") 

383 

384 @pid_scheme.setter 

385 def pid_scheme(self, schemes): 

386 self.__seamless__.set_with_struct("pid_scheme.scheme", schemes) 

387 if len(schemes) > 0: 

388 self.__seamless__.set_with_struct("pid_scheme.has_pid_scheme", True) 

389 else: 

390 self.__seamless__.set_with_struct("pid_scheme.has_pid_scheme", False) 

391 

392 def add_pid_scheme(self, scheme): 

393 self.__seamless__.add_to_list_with_struct("pid_scheme.scheme", scheme) 

394 self.__seamless__.set_with_struct("pid_scheme.has_pid_scheme", True) 

395 

396 @property 

397 def has_pid_scheme(self): 

398 return self.__seamless__.get_single("pid_scheme.has_pid_scheme") 

399 

400 @has_pid_scheme.setter 

401 def has_pid_scheme(self, val): 

402 self.__seamless__.set_with_struct("pid_scheme.has_pid_scheme", val) 

403 

404 def set_plagiarism_detection(self, url, has_detection=True): 

405 self.__seamless__.set_with_struct("plagiarism.detection", has_detection) 

406 self.__seamless__.set_with_struct("plagiarism.url", url) 

407 

408 @property 

409 def plagiarism_detection(self): 

410 return self.__seamless__.get_single("plagiarism.detection") 

411 

412 @property 

413 def plagiarism_url(self): 

414 return self.__seamless__.get_single("plagiarism.url") 

415 

416 @plagiarism_url.setter 

417 def plagiarism_url(self, url): 

418 self.__seamless__.set_with_struct("plagiarism.url", url) 

419 

420 @property 

421 def preservation(self): 

422 return self.__seamless__.get_single("preservation") 

423 

424 @property 

425 def preservation_services(self): 

426 pres = self.preservation 

427 if pres is None: 

428 return [] 

429 if "service" in pres: 

430 return pres["service"] 

431 else: 

432 return [] 

433 

434 @property 

435 def preservation_library(self): 

436 pres = self.preservation 

437 if pres is None: 

438 return None 

439 if "national_library" in pres: 

440 return pres["national_library"] 

441 return None 

442 

443 @property 

444 def preservation_summary(self): 

445 summary = [] 

446 summary += self.preservation_services 

447 libs = self.preservation_library 

448 if libs is not None: 

449 for lib in libs: 

450 summary.append(["A national library", lib]) 

451 return summary 

452 

453 def add_preservation_library(self, library): 

454 self.__seamless__.add_to_list_with_struct("preservation.national_library", library) 

455 self.has_preservation = True 

456 

457 def set_preservation(self, services, policy_url): 

458 obj = {} 

459 known = [] 

460 for p in services: 

461 if isinstance(p, list): 

462 k, v = p 

463 if k.lower() == "a national library": 

464 if "national_library" in obj: 

465 obj["national_library"].append(v) 

466 else: 

467 obj["national_library"] = [v] 

468 else: 

469 known.append(p) 

470 if len(known) > 0: 

471 obj["service"] = known 

472 if policy_url is not None: 

473 obj["url"] = policy_url 

474 

475 self.__seamless__.set_with_struct("preservation", obj) 

476 

477 if self.preservation_services is not None or self.preservation_library is not None: 

478 self.has_preservation = True 

479 

480 def add_preservation(self, services=None, libraries=None): 

481 if services is not None: 

482 if not isinstance(services, list): 

483 services = [services] 

484 for s in services: 

485 self.__seamless__.add_to_list_with_struct("preservation.service", s) 

486 if libraries is not None: 

487 if not isinstance(libraries, list): 

488 libraries = [libraries] 

489 for l in libraries: 

490 self.__seamless__.add_to_list_with_struct("preservation.national_library", l) 

491 if self.preservation_services is not None or self.preservation_library is not None: 

492 self.has_preservation = True 

493 

494 @property 

495 def has_preservation(self): 

496 return self.__seamless__.get_single("preservation.has_preservation") 

497 

498 @has_preservation.setter 

499 def has_preservation(self, has_preservation): 

500 self.__seamless__.set_single("preservation.has_preservation", has_preservation) 

501 

502 @property 

503 def preservation_url(self): 

504 return self.__seamless__.get_single("preservation.url") 

505 

506 @preservation_url.setter 

507 def preservation_url(self, url): 

508 self.__seamless__.set_with_struct("preservation.url", url) 

509 

510 @property 

511 def publisher_name(self): 

512 return self.__seamless__.get_single("publisher.name") 

513 

514 @publisher_name.setter 

515 def publisher_name(self, val): 

516 self.__seamless__.set_with_struct("publisher.name", val) 

517 

518 @property 

519 def publisher_country(self): 

520 return self.__seamless__.get_single("publisher.country") 

521 

522 @publisher_country.setter 

523 def publisher_country(self, country): 

524 self.__seamless__.set_with_struct("publisher.country", country) 

525 

526 @property 

527 def review_process(self): 

528 return self.__seamless__.get_list("editorial.review_proccess") 

529 

530 @review_process.setter 

531 def review_process(self, review_process): 

532 self.__seamless__.add_to_list_with_struct("editorial.review_process", review_process) 

533 

534 @property 

535 def review_process_url(self): 

536 return self.__seamless__.editorial.review_url 

537 

538 @review_process_url.setter 

539 def review_process_url(self, url): 

540 self.__seamless__.set_with_struct("editorial.review_url", url) 

541 

542 @property 

543 def oa_statement_url(self): 

544 return self.__seamless__.get_single("ref.oa_statement") 

545 

546 @oa_statement_url.setter 

547 def oa_statement_url(self, url): 

548 self.__seamless__.set_with_struct("ref.oa_statement", url) 

549 

550 @property 

551 def journal_url(self): 

552 return self.__seamless__.get_single("ref.journal") 

553 

554 @journal_url.setter 

555 def journal_url(self, url): 

556 self.__seamless__.set_with_struct("ref.journal", url) 

557 

558 @property 

559 def aims_scope_url(self): 

560 return self.__seamless__.get_single("ref.aims_scope") 

561 

562 @aims_scope_url.setter 

563 def aims_scope_url(self, url): 

564 self.__seamless__.set_with_struct("ref.aims_scope", url) 

565 

566 @property 

567 def author_instructions_url(self): 

568 return self.__seamless__.get_single("ref.author_instructions") 

569 

570 @author_instructions_url.setter 

571 def author_instructions_url(self, url): 

572 self.__seamless__.set_with_struct("ref.author_instructions", url) 

573 

574 @property 

575 def license_terms_url(self): 

576 return self.__seamless__.get_single("ref.license_terms") 

577 

578 @license_terms_url.setter 

579 def license_terms_url(self, url): 

580 self.__seamless__.set_with_struct("ref.license_terms", url) 

581 

582 @property 

583 def has_waiver(self): 

584 return self.__seamless__.get_single("waiver.has_waiver") 

585 

586 @has_waiver.setter 

587 def has_waiver(self, url): 

588 self.__seamless__.set_with_struct("waiver.has_waiver", url) 

589 

590 @property 

591 def waiver_url(self): 

592 return self.__seamless__.get_single("waiver.url") 

593 

594 @waiver_url.setter 

595 def waiver_url(self, url): 

596 self.__seamless__.set_with_struct("waiver.url", url) 

597 

598 ##################################################### 

599 ## External utility functions 

600 

601 def issns(self): 

602 issns = [] 

603 if self.pissn: 

604 issns.append(self.pissn) 

605 if self.eissn: 

606 issns.append(self.eissn) 

607 return issns 

608 

609 def publisher_country_name(self): 

610 if self.publisher_country is not None: 

611 return datasets.get_country_name(self.publisher_country) 

612 return None 

613 

614 def institution_country_name(self): 

615 if self.institution_country is not None: 

616 return datasets.get_country_name(self.institution_country) 

617 return None 

618 

619 def language_name(self): 

620 # copy the languages and convert them to their english forms 

621 langs = [datasets.name_for_lang(l) for l in self.language] 

622 langs = [to_utf8_unicode(l) for l in langs] 

623 return list(set(langs)) 

624 

625 def term_path(self, term): 

626 from portality.lcc import lcc 

627 return lcc.term_path(term) 

628 

629 def lcc_paths(self): 

630 classification_paths = [] 

631 

632 # calculate the classification paths 

633 from portality.lcc import lcc # inline import since this hits the database 

634 for subs in self.subjects(): 

635 scheme = subs.get("scheme") 

636 term = subs.get("term") 

637 if scheme == "LCC": 

638 p = lcc.pathify(term) 

639 if p is not None: 

640 classification_paths.append(p) 

641 

642 # normalise the classification paths, so we only store the longest ones 

643 classification_paths = lcc.longest(classification_paths) 

644 

645 return classification_paths 

646 

647 def lcc_codes_full_list(self): 

648 full_list = set() 

649 

650 from portality.lcc import lcc # inline import since this hits the database 

651 for subs in self.subjects(): 

652 scheme = subs.get("scheme") 

653 if scheme != "LCC": 

654 continue 

655 code = subs.get("code") 

656 expanded = lcc.expand_codes(code) 

657 full_list.update(expanded) 

658 

659 return ["LCC:" + x for x in full_list if x is not None] 

660 

661 def lcc_paths_and_codes(self): 

662 paths_and_codes = {} 

663 

664 # calculate the classification paths 

665 from portality.lcc import lcc # inline import since this hits the database 

666 for subs in self.subjects(): 

667 scheme = subs.get("scheme") 

668 if scheme != "LCC": 

669 continue 

670 term = subs.get("term") 

671 code = subs.get("code") 

672 p = lcc.pathify(term) 

673 if p is not None: 

674 paths_and_codes[p] = "LCC:" + code 

675 

676 return [(x, paths_and_codes[x]) for x in lcc.longest(list(paths_and_codes.keys()))] 

677 

678 # to help with ToC - we prefer to refer to a journal by E-ISSN, or 

679 # if not, then P-ISSN 

680 def get_preferred_issn(self): 

681 if self.eissn: 

682 return self.eissn 

683 if self.pissn: 

684 return self.pissn 

685 

686 ##################################################### 

687 ## Internal utility functions 

688 

689 def _normalise_issn(self, issn): 

690 if issn is None: 

691 return issn 

692 issn = issn.upper() 

693 if len(issn) > 8: return issn 

694 if len(issn) == 8: 

695 if "-" in issn: return "0" + issn 

696 else: return issn[:4] + "-" + issn[4:] 

697 if len(issn) < 8: 

698 if "-" in issn: return ("0" * (9 - len(issn))) + issn 

699 else: 

700 issn = ("0" * (8 - len(issn))) + issn 

701 return issn[:4] + "-" + issn[4:] 

702 

703 ##################################################### 

704 ## Back Compat methods for v1 of the model 

705 ## ALL DEPRECATED 

706 

707 @property 

708 def publication_time(self): 

709 return self.publication_time_weeks 

710 

711 @publication_time.setter 

712 def publication_time(self, weeks): 

713 self.publication_time_weeks = weeks 

714 

715 @property 

716 def publisher(self): 

717 return self.publisher_name 

718 

719 @publisher.setter 

720 def publisher(self, val): 

721 self.publisher_name = val 

722 

723 @property 

724 def institution(self): 

725 return self.institution_name 

726 

727 @institution.setter 

728 def institution(self, val): 

729 self.institution_name = val 

730 

731 def set_keywords(self, keywords): 

732 self.keywords = keywords 

733 

734 def set_language(self, language): 

735 self.language = language 

736 

737 @property 

738 def persistent_identifier_scheme(self): 

739 return self.pid_scheme 

740 

741 @persistent_identifier_scheme.setter 

742 def persistent_identifier_scheme(self, schemes): 

743 self.pid_scheme = schemes 

744 

745 def add_persistent_identifier_scheme(self, scheme): 

746 self.add_pid_scheme(scheme) 

747 

748 def subjects(self): 

749 return self.subject 

750 

751 def set_subjects(self, subjects): 

752 self.subject = subjects 

753 

754 def remove_subjects(self): 

755 del self.subject 

756 

757 def set_archiving_policy(self, policies, policy_url): 

758 self.set_preservation(policies, policy_url) 

759 

760 def add_archiving_policy(self, policy_name): 

761 self.add_preservation(policy_name) 

762 

763 @property 

764 def flattened_archiving_policies(self): 

765 summary = self.preservation_summary 

766 if summary is None: 

767 return [] 

768 return [": ".join(p) if isinstance(p, list) else p for p in self.preservation_summary] 

769 

770 # vocab of known identifier types 

771 P_ISSN = "pissn" 

772 E_ISSN = "eissn" 

773 DOI = "doi" 

774 

775 IDENTIFIER_MAP = { 

776 P_ISSN : "pissn", 

777 E_ISSN : "eissn", 

778 DOI : "doi" 

779 } 

780 

781 def add_identifier(self, idtype, value): 

782 field = self.IDENTIFIER_MAP.get(idtype) 

783 if field is not None: 

784 setattr(self, field, value) 

785 return 

786 raise RuntimeError("This object does not accept unrecognised identifier types") 

787 

788 def get_identifiers(self, idtype=None): 

789 if idtype is None: 

790 idents = [] 

791 if self.eissn: 

792 idents.append({"type" : self.E_ISSN, "id" : self.eissn}) 

793 if self.pissn: 

794 idents.append({"type" : self.P_ISSN, "id" : self.pissn}) 

795 return idents 

796 field = self.IDENTIFIER_MAP.get(idtype) 

797 if field is None: 

798 raise RuntimeError("No identifier of type {x} known".format(x=idtype)) 

799 

800 ident = getattr(self, field) 

801 if ident is not None: 

802 return [getattr(self, field)] 

803 return [] 

804 

805 def get_one_identifier(self, idtype=None): 

806 if idtype is None: 

807 raise RuntimeError("This object cannot return a generic identifier") 

808 results = self.get_identifiers(idtype=idtype) 

809 if len(results) > 0: 

810 return results[0] 

811 else: 

812 return None 

813 

814 def _set_attr_with_no_check(self, name, value): 

815 self.__setattr__(name, value, allow_coerce_failure=True) 

816 

817 # allowable values for the url types 

818 HOMEPAGE = "homepage" 

819 WAIVER_POLICY = "waiver_policy" 

820 EDITORIAL_BOARD = "editorial_board" 

821 AIMS_SCOPE = "aims_scope" 

822 AUTHOR_INSTRUCTIONS = "author_instructions" 

823 OA_STATEMENT = "oa_statement" 

824 #FULLTEXT = "fulltext" 

825 

826 LINK_MAP = { 

827 HOMEPAGE: "journal_url", 

828 WAIVER_POLICY: "waiver_url", 

829 EDITORIAL_BOARD: "editorial_board_url", 

830 AIMS_SCOPE: "aims_scope_url", 

831 AUTHOR_INSTRUCTIONS: "author_instructions_url", 

832 OA_STATEMENT: "oa_statement_url" 

833 } 

834 

835 def add_url(self, url, urltype=None, content_type=None): 

836 if url is None: 

837 # do not add empty URL-s 

838 return 

839 

840 field = self.LINK_MAP.get(urltype) 

841 if field is not None: 

842 setattr(self, field, url) 

843 return 

844 raise RuntimeError("This object does not accept unrecognised url types") 

845 

846 def get_urls(self, urltype=None, unpack_urlobj=True): 

847 if urltype is None: 

848 raise RuntimeError("This object cannot return lists of urls") 

849 

850 field = self.LINK_MAP.get(urltype) 

851 if field is None: 

852 raise RuntimeError("No url of type {x} known".format(x=urltype)) 

853 

854 url = getattr(self, field) 

855 if unpack_urlobj: 

856 return [url] 

857 else: 

858 return [{"type" : urltype, "url" : url}] 

859 

860 def get_single_url(self, urltype, unpack_urlobj=True): 

861 urls = self.get_urls(urltype=urltype, unpack_urlobj=unpack_urlobj) 

862 if len(urls) > 0: 

863 return urls[0] 

864 return None 

865 

866 @property 

867 def first_pissn(self): 

868 return self.pissn 

869 

870 @property 

871 def first_eissn(self): 

872 return self.eissn 

873 

874 @property 

875 def country(self): 

876 return self.publisher_country 

877 

878 @country.setter 

879 def country(self, val): 

880 self.publisher_country = val 

881 

882 @property 

883 def open_access(self): 

884 return self.boai 

885 

886 def set_open_access(self, open_access): 

887 self.boai = open_access 

888 

889 def country_name(self): 

890 return self.publisher_country_name() 

891 

892 ##################################################### 

893 ## Incompatible functions from v1 

894 

895 def set_license(self, license_type, url=None, version=None, open_access=None, 

896 by=None, sa=None, nc=None, nd=None, 

897 display=None, display_example_url=None): 

898 """ 

899 # FIXME: why is there not a "remove license" function 

900 if not license_title and not license_type: # something wants to delete the license 

901 self._delete("license") 

902 return 

903 

904 lobj = {"title": license_title, "type": license_type} 

905 if url is not None: 

906 lobj["url"] = url 

907 if version is not None: 

908 lobj["version"] = version 

909 if open_access is not None: 

910 lobj["open_access"] = open_access 

911 if by is not None: 

912 lobj["BY"] = by 

913 if sa is not None: 

914 lobj["SA"] = sa 

915 if nc is not None: 

916 lobj["NC"] = nc 

917 if nd is not None: 

918 lobj["ND"] = nd 

919 if embedded is not None: 

920 lobj["embedded"] = embedded 

921 if embedded_example_url is not None: 

922 lobj["embedded_example_url"] = embedded_example_url 

923 

924 self._set_with_struct("license", [lobj]) 

925 """ 

926 raise RuntimeError("set_license is not back compat") 

927 

928 def get_license(self): 

929 """ 

930 ll = self._get_list("license") 

931 if len(ll) > 0: 

932 return ll[0] 

933 return None 

934 """ 

935 raise RuntimeError("get_license is not back compat") 

936 

937 def get_license_type(self): 

938 """ 

939 lobj = self.get_license() 

940 if lobj is not None: 

941 return lobj['type'] 

942 return None 

943 """ 

944 raise RuntimeError("get_license_type is not back compat") 

945 

946 @property 

947 def editorial_review(self): 

948 """ 

949 return self._get_single("editorial_review", default={}) 

950 """ 

951 raise RuntimeError("editorial_review is not back compat") 

952 

953 @property 

954 def archiving_policy(self): 

955 """ 

956 ap = self._get_single("archiving_policy", default={}) 

957 ret = {"policy" : []} 

958 if "url" in ap: 

959 ret["url"] = ap["url"] 

960 if "known" in ap: 

961 ret["policy"] += ap["known"] 

962 if "nat_lib" in ap: 

963 ret["policy"].append(["A national library", ap["nat_lib"]]) 

964 if "other" in ap: 

965 ret["policy"].append(["Other", ap["other"]]) 

966 return ret 

967 """ 

968 raise RuntimeError("archiving_policy is not back compat") 

969 

970 def remove_identifiers(self, idtype=None, id=None): 

971 raise RuntimeError("remove_identifiers is not back compat") 

972 

973 def remove_urls(self, urltype=None, url=None): 

974 raise RuntimeError("remove_urls is not back compat") 

975