Coverage for apps/ptf/model_helpers.py: 75%

549 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2024-02-28 09:09 +0000

1import datetime 

2import itertools 

3import random 

4import re 

5import unicodedata 

6 

7import dateutil.parser 

8from unidecode import unidecode 

9 

10from django.conf import settings 

11from django.http import Http404 

12from django.shortcuts import get_list_or_404 

13from django.urls import reverse 

14from django.utils import timezone 

15from django.utils.translation import gettext_lazy as _ 

16 

17from .models import Article 

18from .models import Author 

19from .models import BibItem 

20from .models import BibItemId 

21from .models import Collection 

22from .models import Container 

23from .models import ExtId 

24from .models import ExtLink 

25from .models import Provider 

26from .models import PtfSite 

27from .models import Publisher 

28from .models import RelatedObject 

29from .models import RelationName 

30from .models import Relationship 

31from .models import Resource 

32from .models import SiteMembership 

33from .models import XmlBase 

34from .site_register import SITE_REGISTER 

35from .utils import volume_display 

36 

37########################################################################## 

38# 

39# Get functions 

40# 

41########################################################################## 

42 

43 

44def get_first_last_years(year): 

45 the_array = year.split("-") 

46 

47 fyear = the_array[0] 

48 lyear = the_array[1] if len(the_array) > 1 else fyear 

49 

50 return fyear, lyear 

51 

52 

53def get_provider_by_name(name): 

54 if name == "numdam": 

55 name = "mathdoc" 

56 

57 provider = Provider.objects.get(name=name) 

58 return provider 

59 

60 

61def get_provider(pid_type): 

62 provider = Provider.objects.get(pid_type=pid_type) 

63 return provider 

64 

65 

66def get_publisher(name): 

67 try: 

68 key = make_key(name) 

69 publisher = Publisher.objects.get(pub_key=key) 

70 except Publisher.DoesNotExist: 

71 publisher = None 

72 return publisher 

73 

74 

75def get_or_create_site(site_id, acro=None): 

76 try: 

77 site = PtfSite.objects.get(id=site_id) 

78 except PtfSite.DoesNotExist: 

79 site = PtfSite.objects.create(id=site_id, name=acro, domain=acro, acro=acro) 

80 return site 

81 

82 

83def get_journals(): 

84 journals = Collection.objects.filter(sites__id=settings.SITE_ID, coltype="journal") 

85 return journals.all() 

86 

87 

88def get_actas(): 

89 actas = Collection.objects.filter(sites__id=settings.SITE_ID, coltype="acta") 

90 return actas.all() 

91 

92 

93def get_lectures(): 

94 lectures = Collection.objects.filter(sites__id=settings.SITE_ID, coltype="lecture-notes") 

95 return lectures.all() 

96 

97 

98def get_proceedings(): 

99 proceedings = Collection.objects.filter(sites__id=settings.SITE_ID, coltype="proceeding") 

100 return proceedings.all() 

101 

102 

103def get_collection_of_books(with_lectures=False): 

104 filters = ["book-series"] 

105 if with_lectures: 

106 filters.append("lecture-notes") 

107 

108 book_series = Collection.objects.filter(sites__id=settings.SITE_ID, coltype__in=filters) 

109 return book_series.all() 

110 

111 

112def get_books(): 

113 return Container.objects.filter( 

114 sites__id=settings.SITE_ID, my_collection__coltype__in=["book-series", "lecture-notes"] 

115 ) 

116 

117 

118def get_theses(): 

119 theses = Container.objects.filter(sites__id=settings.SITE_ID, my_collection__coltype="thesis") 

120 return theses.all() 

121 

122 

123# TODO require the provider in the get_ functions as it serves as a namespace 

124 

125 

126def get_collection(pid, sites=True, prefetch=False): 

127 try: 

128 if sites: 

129 col = Collection.objects.get(pid=pid, sites__id=settings.SITE_ID) 

130 else: 

131 col = Collection.objects.get(pid=pid) 

132 except Collection.DoesNotExist: 

133 col = None 

134 return col 

135 

136 

137def get_volumes_in_collection(collection): 

138 """ 

139 used by issue-list.html and oai gallica 

140 return list of issues by volume if volume_int exist or by date 

141 return list of publishers GROUP BY name with date 

142 @param collection: 

143 @return: 

144 

145 """ 

146 

147 items = ( 

148 collection.content.filter(sites__id=settings.SITE_ID) 

149 .order_by("-vseries_int", "-year", "-volume_int", "number_int") 

150 .all() 

151 ) 

152 # We're building the following list: 

153 # vseries = [ { 'vseries_int': vseries_int, 

154 # 'volumes': list of volumes <=> volumes_in_vseriess 

155 # } 

156 # ] 

157 # 

158 # volumes_in_vseries = [ { 'volume_int': volume_int, 

159 # 'title': ? 

160 # 'fyear': fyear, 

161 # 'lyear': lyear, 

162 # 'issues': list of issues <=> issues_in_volume (list of issue objects) 

163 

164 if collection.collectionmembership_set.count() > 0: 164 ↛ 165line 164 didn't jump to line 165

165 col_membsership_qs = ( 

166 collection.collectionmembership_set.filter(container__sites__id=settings.SITE_ID) 

167 .order_by("-vseries_int", "-volume_int", "number_int") 

168 .all() 

169 ) 

170 joined = itertools.chain(items, col_membsership_qs) 

171 

172 def sorter(dict_): 

173 return ( 

174 dict_.vseries_int, 

175 dict_.year if hasattr(dict_, "year") else dict_.container.year, 

176 dict_.volume_int, 

177 dict_.number_int, 

178 ) 

179 

180 items = sorted(joined, key=sorter, reverse=True) 

181 

182 # items is now a collection of Container and/or CollectionMembership 

183 

184 issue_to_appear_pid = "" 

185 if hasattr(settings, "ISSUE_TO_APPEAR_PID"): 185 ↛ 186line 185 didn't jump to line 186, because the condition on line 185 was never true

186 issue_to_appear_pid = settings.ISSUE_TO_APPEAR_PID 

187 

188 issues_in_vseries = [] 

189 volumes_in_vseries = [] 

190 issues_in_volume = [] 

191 publishers = [] 

192 results_vseries = "-1" 

193 results_volume = "-1" 

194 results_year = "-1" 

195 results_fyear = results_lyear = -1 

196 volume_count = 0 

197 max_volume_count = 0 

198 max_width = 0 

199 width = 0 

200 for item in items: 

201 width += len(item.number) 

202 if hasattr(item, "container"): 202 ↛ 217line 202 didn't jump to line 217, because the condition on line 202 was never false

203 issue = item.container 

204 # The issue-list template use issue properties to display the list of issues 

205 # Replace the values with those of the CollectionMembership for the display 

206 issue.veries = item.vseries 

207 issue.volume = item.volume 

208 issue.number = item.number 

209 issue.vseries_int = item.vseries_int 

210 issue.volume_int = item.volume_int 

211 issue.number_int = item.number_int 

212 

213 year = issue.year 

214 vseries = item.vseries 

215 volume = item.volume 

216 else: 

217 issue = item 

218 year = issue.year 

219 vseries = issue.vseries 

220 volume = issue.volume 

221 

222 if issue.pid != issue_to_appear_pid: 222 ↛ 200line 222 didn't jump to line 200, because the condition on line 222 was never false

223 fyear, lyear = get_first_last_years(year) 

224 fyear = int(fyear) 

225 lyear = int(lyear) 

226 

227 # new volume found, we need to add issues_in_volume in the current volumes_in_veries 

228 if results_volume != volume or (results_volume == "" and results_year != year): 228 ↛ 254line 228 didn't jump to line 254, because the condition on line 228 was never false

229 # The first time, we simply add the issue in issues_in_volume (see below) 

230 # But we do not append in volumes_in_vseries 

231 if results_volume != "-1": 

232 volumes_in_vseries.append( 

233 { 

234 "volume": results_volume, 

235 "fyear": results_fyear, 

236 "lyear": results_lyear, 

237 "issues": issues_in_volume, 

238 } 

239 ) 

240 # Clear issues_in_volume to prepare a new volume 

241 issues_in_volume = [] 

242 

243 # Set the current volume info 

244 results_volume = volume 

245 results_year = year 

246 results_fyear = fyear 

247 results_lyear = lyear 

248 volume_count += 1 

249 if width > max_width: 

250 max_width = width 

251 width = 0 

252 

253 # New vseries found, we need to add volumes_in_vseries to the current vseries 

254 if results_vseries != vseries: 

255 # The first time, we do not append in issues_in_vseries. 

256 # We simply set the vseries info and add the issues in issues_in_volume below 

257 if results_vseries != "-1": 257 ↛ 258line 257 didn't jump to line 258, because the condition on line 257 was never true

258 issues_in_vseries.append( 

259 {"vseries": results_vseries, "volumes": volumes_in_vseries} 

260 ) 

261 volumes_in_vseries = [] 

262 results_vseries = vseries 

263 max_volume_count = max(0, volume_count) 

264 volume_count = 0 

265 

266 issues_in_volume.append(issue) 

267 

268 # we have to create a list of publishers with date - for Gallica OAI 

269 if issue.my_publisher: 

270 if publishers: 

271 item = publishers[-1] 

272 if issue.my_publisher.pub_name != item["name"]: 272 ↛ 273line 272 didn't jump to line 273

273 item = { 

274 "name": issue.my_publisher.pub_name, 

275 "fyear": fyear, 

276 "lyear": lyear, 

277 } 

278 publishers.append(item) 

279 else: 

280 if fyear < item["fyear"]: 280 ↛ 282line 280 didn't jump to line 282, because the condition on line 280 was never false

281 item["fyear"] = fyear 

282 if lyear > item["lyear"]: 282 ↛ 283line 282 didn't jump to line 283, because the condition on line 282 was never true

283 item["lyear"] = lyear 

284 else: 

285 publishers.insert( 

286 0, {"name": issue.my_publisher.pub_name, "fyear": fyear, "lyear": lyear} 

287 ) 

288 

289 # At the end of the loop, we need to append the remaining issues_in_volume 

290 # then volumes_in_vseries 

291 if results_volume != "-1" and issues_in_volume: 

292 volumes_in_vseries.append( 

293 { 

294 "volume": results_volume, 

295 "fyear": results_fyear, 

296 "lyear": results_lyear, 

297 "issues": issues_in_volume, 

298 } 

299 ) 

300 # volume_count += 1 

301 

302 if results_vseries != "-1" and volumes_in_vseries: 

303 issues_in_vseries.append({"vseries": results_vseries, "volumes": volumes_in_vseries}) 

304 max_volume_count = max(0, volume_count) 

305 

306 context = { 

307 "sorted_issues": issues_in_vseries, 

308 "volume_count": max_volume_count, 

309 "publishers": publishers, 

310 "max_width": max_width, 

311 } 

312 

313 return context 

314 

315 

316def get_container(pid, prefetch=False): 

317 try: 

318 if prefetch: 

319 container = ( 

320 Container.objects.filter(sites__id=settings.SITE_ID, pid=pid) 

321 .prefetch_for_toc() 

322 .first() 

323 ) 

324 else: 

325 container = Container.objects.get(sites__id=settings.SITE_ID, pid=pid) 

326 

327 except Container.DoesNotExist: 

328 container = None 

329 return container 

330 

331 

332def get_book_serie(pid): 

333 try: 

334 book_serie = Collection.objects.get( 

335 pid=pid, coltype="book-series", sites__id=settings.SITE_ID 

336 ) 

337 except Collection.DoesNotExist: 

338 book_serie = None 

339 return book_serie 

340 

341 

342def get_issues_count_in_collection(pid): 

343 try: 

344 collection = Collection.objects.get(pid=pid) 

345 issues = Container.objects.filter(my_collection=collection).count() 

346 return issues 

347 except Exception: 

348 pass 

349 

350 

351def get_issues_in_volume(vid, is_cr=False, general_articles=False): 

352 # 08/09/2022: vid is no longer built (see get_vid in models.py) 

353 # It is now the pid of the first issue of the volume 

354 first_issue = get_container(vid) 

355 if first_issue is None: 

356 raise Http404 

357 

358 collection = first_issue.get_collection() 

359 year = first_issue.year 

360 vseries = first_issue.vseries 

361 volume = first_issue.volume 

362 

363 if is_cr: 

364 year_int = int(year) 

365 if year_int > 2020 and collection.pid not in ["CRMATH", "CRBIOL"]: 365 ↛ 368line 365 didn't jump to line 368, because the condition on line 365 was never true

366 # CRAS: Les thématiques à partir de 2021 ont un number en "T1", "T2",... 

367 # On trie par number pour avoir les thématiques isolés des autres 

368 queryset = Container.objects.order_by("number") 

369 elif year_int > 2022 and collection.pid == "CRBIOL": 369 ↛ 370line 369 didn't jump to line 370, because the condition on line 369 was never true

370 queryset = Container.objects.order_by("number") 

371 else: 

372 queryset = Container.objects.order_by("number_int") 

373 if general_articles: 373 ↛ 374line 373 didn't jump to line 374, because the condition on line 373 was never true

374 queryset = queryset.filter(title_html="") 

375 else: 

376 queryset = Container.objects.order_by("number_int") 

377 queryset = queryset.filter( 

378 my_collection__pid=collection.pid, year=year, vseries=vseries, volume=volume 

379 ).prefetch_for_toc() 

380 issues = get_list_or_404(queryset) 

381 

382 if is_cr and ( 382 ↛ 386line 382 didn't jump to line 386, because the condition on line 382 was never true

383 (year_int > 2020 and collection.pid != "CRBIOL") 

384 or (year_int > 2022 and collection.pid == "CRBIOL") 

385 ): 

386 issues_articles = [] 

387 grouped_articles = [] 

388 grouped_issue_articles = {"issue": None, "articles": grouped_articles} 

389 for issue in issues: 

390 if len(issue.title_html) == 0: 

391 grouped_articles.extend(issue.article_set.all().order_by_sequence()) 

392 grouped_issue_articles["issue"] = issue 

393 else: 

394 issues_articles.append( 

395 { 

396 "issue": issue, 

397 "articles": issue.article_set.all().order_by_published_date() 

398 if settings.SORT_ARTICLES_BY_DATE 

399 else issue.article_set.all().order_by_sequence(), 

400 } 

401 ) 

402 if grouped_issue_articles["issue"] is not None: 

403 issues_articles.insert(0, grouped_issue_articles) 

404 else: 

405 issues_articles = [ 

406 { 

407 "issue": issue, 

408 "articles": issue.article_set.all().order_by_published_date() 

409 if settings.SORT_ARTICLES_BY_DATE 

410 else issue.article_set.all().order_by_sequence(), 

411 } 

412 for issue in issues 

413 ] 

414 

415 return issues_articles, collection 

416 

417 

418def get_article(pid: str, prefetch=False) -> Article | None: 

419 try: 

420 if prefetch: 

421 article = ( 

422 Article.objects.filter(sites__id=settings.SITE_ID, pid=pid).prefetch_all().first() 

423 ) 

424 else: 

425 article = Article.objects.get(sites__id=settings.SITE_ID, pid=pid) 

426 

427 except Article.DoesNotExist: 

428 article = None 

429 return article 

430 

431 

432def get_article_by_doi(doi, prefetch=False): 

433 try: 

434 if prefetch: 

435 article = ( 

436 Article.objects.filter(sites__id=settings.SITE_ID, doi=doi).prefetch_all().first() 

437 ) 

438 else: 

439 article = Article.objects.get(sites__id=settings.SITE_ID, doi=doi) 

440 

441 except Article.DoesNotExist: 

442 article = None 

443 return article 

444 

445 

446def get_articles(): 

447 article_qs = Article.objects.filter(sites__id=settings.SITE_ID).exclude( 

448 classname="TranslatedArticle" 

449 ) 

450 return article_qs 

451 

452 

453def get_articles_by_deployed_date(): 

454 sitemembership_qs = SiteMembership.objects.filter( 

455 site__id=settings.SITE_ID, resource__classname="Article" 

456 ).order_by("-deployed", "-seq") 

457 

458 articles = [sm.resource.cast() for sm in sitemembership_qs] 

459 return articles 

460 

461 

462def get_articles_by_published_date(): 

463 article_qs = Article.objects.filter(sites__id=settings.SITE_ID).exclude( 

464 classname="TranslatedArticle" 

465 ) 

466 if hasattr(settings, "ISSUE_TO_APPEAR_PID"): 

467 article_qs = article_qs.exclude(my_container__pid=settings.ISSUE_TO_APPEAR_PID) 

468 article_qs = article_qs.order_by("-date_published", "-seq") 

469 

470 return article_qs 

471 

472 

473def get_xmlbase(base): 

474 try: 

475 xmlbase = XmlBase.objects.get(base=base) 

476 except XmlBase.DoesNotExist: 

477 xmlbase = None 

478 return xmlbase 

479 

480 

481# RelationName are created with a fixture (see app/ptf/apps/ptf/fixtures/initial_data.json 

482# Example { "left" : "follows", "right" : "followed-by" } 

483# A related-article of an article has 1 relation name (ex "follows" or "followed-by") 

484# You need to know if the relation was stored in the left or right attribute of a RelationName, 

485# so that you can create/search the Relationship with the correct object/subject. 

486# Ex: with A "follows" B, A is the subject and B the object because "follows" is a RelationName.left attribute 

487# with A "followed-by" B, A is the object the B the subject because 

488# "followed-by" is a RelationName.right attribute 

489def get_relationname_left(left_name): 

490 try: 

491 relationname = RelationName.objects.get(left=left_name) 

492 except RelationName.DoesNotExist: 

493 relationname = None 

494 

495 return relationname 

496 

497 

498def get_relationname_right(right_name): 

499 try: 

500 relationname = RelationName.objects.get(right=right_name) 

501 except RelationName.DoesNotExist: 

502 relationname = None 

503 

504 return relationname 

505 

506 

507# See comments about RelationName above 

508def get_relationship(subject_pid, object_pid, relationname): 

509 try: 

510 relationship = Relationship.objects.get( 

511 subject_pid=subject_pid, object_pid=object_pid, rel_info=relationname 

512 ) 

513 except Relationship.DoesNotExist: 

514 relationship = None 

515 

516 return relationship 

517 

518 

519def get_extid(resource, id_type): 

520 extid = None 

521 extids = ExtId.objects.filter(resource=resource, id_type=id_type) 

522 if extids.count() > 0: 

523 extid = extids.first() 

524 

525 return extid 

526 

527 

528def get_bibitemid(bibitem, id_type): 

529 bibitemid = None 

530 bibitemids = BibItemId.objects.filter(bibitem=bibitem, id_type=id_type) 

531 if bibitemids.count() > 0: 

532 bibitemid = bibitemids.first() 

533 

534 return bibitemid 

535 

536 

537def get_bibitem_by_seq(article, seq): 

538 try: 

539 bibitem = article.bibitem_set.get(sequence=seq) 

540 except BibItem.DoesNotExist: 

541 bibitem = None 

542 return bibitem 

543 

544 

545def get_extlink(**filters): 

546 try: 

547 extlink = ExtLink.objects.get(**filters) 

548 except ExtLink.DoesNotExist: 

549 extlink = None 

550 return extlink 

551 

552 

553def get_related_object(**filters): 

554 """ 

555 Return RelatedObject with filters pass by params (all are optionals) 

556 resource, base, rel, mimetype, location, metadata, seq 

557 Check models.py for the params of a RelatedObject 

558 """ 

559 try: 

560 related_object = RelatedObject.objects.get(**filters) 

561 related_object.select_related() 

562 except RelatedObject.DoesNotExist: 

563 related_object = None 

564 return related_object 

565 

566 

567def get_authors_by_letter(first_letter): 

568 try: 

569 authors = Author.objects.filter(first_letter=first_letter).order_by("name") 

570 except Author.DoesNotExist: 

571 authors = None 

572 return authors 

573 

574 

575def make_key(string): 

576 n_string = unicodedata.normalize("NFKD", string).encode("ascii", "ignore").decode("ascii") 

577 n_string = re.sub(r"[^\w\s-]", "", n_string).strip().lower() 

578 n_string = re.sub(r"[-\s]+", "-", n_string) 

579 if len(n_string) > 64: 

580 n_string = n_string[:64] 

581 

582 return n_string if n_string else unidecode(string) 

583 

584 

585def get_resource(pid: str, prefetch=False) -> Resource | None: 

586 try: 

587 if prefetch: 

588 resource = ( 

589 Resource.objects.filter(sites__id=settings.SITE_ID, pid=pid).prefetch_all().first() 

590 ) 

591 else: 

592 resource = Resource.objects.get(pid=pid, sites__id=settings.SITE_ID) 

593 except Resource.DoesNotExist: 

594 resource = None 

595 return resource 

596 

597 

598def get_resource_by_doi(doi, prefetch=False): 

599 try: 

600 if prefetch: 600 ↛ 601line 600 didn't jump to line 601

601 resource = ( 

602 Resource.objects.filter(sites__id=settings.SITE_ID, doi=doi).prefetch_all().first() 

603 ) 

604 else: 

605 resource = Resource.objects.get(sites__id=settings.SITE_ID, doi=doi) 

606 

607 except Resource.DoesNotExist: 

608 resource = None 

609 return resource 

610 

611 

612def get_random_containers(): 

613 # TODO get the newest containers only 

614 

615 containers = Container.objects.all() 

616 random_list = random.sample(containers, 6) 

617 

618 return random_list 

619 

620 

621def parse_date_str(date_str): 

622 """ 

623 @param date_str:a string representing a date. Ex: "2017-01-10T18:24:58.202+01:00", "2017-05-03" 

624 @return:a localized datetime object (localized means that the date has a timezone) 

625 """ 

626 the_date = dateutil.parser.parse(date_str) 

627 if not timezone.is_aware(the_date): 

628 the_date = timezone.make_aware(the_date, datetime.UTC) 

629 return the_date 

630 

631 

632def get_issue_to_appear(colid): 

633 """ 

634 Some journals want to display "articles to appear" with articles that have been accepted but are not yet 

635 finalized (pages start at 1). ex: AIF 

636 :param pid: 

637 :return: The container object of articles to appear 

638 """ 

639 pid = "" 

640 

641 if hasattr(settings, "ISSUE_TO_APPEAR_PIDS"): 

642 if colid in settings.ISSUE_TO_APPEAR_PIDS: 

643 pid = settings.ISSUE_TO_APPEAR_PIDS[colid] 

644 

645 container = get_container(pid=pid, prefetch=True) 

646 return container 

647 

648 

649def get_number_from_doi(doi): 

650 value = 0 

651 

652 try: 

653 index = doi.rfind(".") 

654 index += 1 

655 if index > 0: 

656 str_value = doi[index:] 

657 value = int(str_value) 

658 except BaseException: 

659 pass 

660 

661 return value 

662 

663 

664def get_site_mersenne(collection_pid): 

665 key = collection_pid.lower() 

666 

667 # TODO refactor smai-jcm, centre_mersenne to have collection_pid == key 

668 # Do not use a find here, we want an access time in O(1) 

669 if key == "smai-jcm": 669 ↛ 670line 669 didn't jump to line 670, because the condition on line 669 was never true

670 key = "smai" 

671 elif key == "mersenne": 671 ↛ 672line 671 didn't jump to line 672, because the condition on line 671 was never true

672 key = "centre_mersenne" 

673 elif key == "malsm": 673 ↛ 674line 673 didn't jump to line 674, because the condition on line 673 was never true

674 key = "mbk" 

675 

676 try: 

677 site_item = settings.SITE_REGISTER[key] 

678 except KeyError: 

679 return None 

680 site_id = site_item["site_id"] 

681 site_acro = key 

682 

683 return get_or_create_site(site_id, site_acro) 

684 

685 

686def get_container_breadcrumb(collection, container, vseries, volume, number, stop_at_volume=False): 

687 crumbs = [] 

688 

689 if collection: 689 ↛ 703line 689 didn't jump to line 703, because the condition on line 689 was never false

690 collection = collection.get_top_collection() 

691 href = collection.get_absolute_url() 

692 # We show the collection title instead of the basic 'Feuilleter' for the sites with several collections: 

693 # 'ALL' and 'MBK' (proceedings site) 

694 if settings.COLLECTION_PID in ["ALL", "MBK"]: 694 ↛ 695line 694 didn't jump to line 695, because the condition on line 694 was never true

695 title = collection.title_html 

696 elif hasattr(settings, "SITE_NAME") and settings.SITE_NAME[0:2] == "cr": 

697 title = _("Consulter") 

698 else: 

699 title = _("Feuilleter") 

700 

701 crumbs.append({"href": href, "title": title}) 

702 

703 if container and container.ctype == "issue": 

704 # TODO : Here, we should have YEAR_BREACRUMB in all settings file 

705 # Until then we just search if YEAR_BREADCRUMB exists 

706 if hasattr(settings, "YEAR_BREADCRUMB"): 706 ↛ 707line 706 didn't jump to line 707, because the condition on line 706 was never true

707 title = str(container.year) 

708 href = reverse("articles-year", kwargs={"year": container.year}) 

709 else: 

710 href = reverse("volume-items", kwargs={"vid": container.get_vid()}) 

711 title = "{} {} : ".format(_("Série"), vseries) if vseries else "" 

712 if volume: 712 ↛ 713line 712 didn't jump to line 713, because the condition on line 712 was never true

713 title += f"{volume_display()} {volume} ({container.year})" 

714 else: 

715 title += "{} {}".format(_("Année"), container.year) 

716 crumbs.append({"href": href, "title": title}) 

717 

718 if not stop_at_volume: 

719 if number: 719 ↛ 741line 719 didn't jump to line 741, because the condition on line 719 was never false

720 try: 

721 year = int(container.year) 

722 except ValueError: 

723 year = 0 

724 

725 if ( 725 ↛ 734line 725 didn't jump to line 734

726 hasattr(settings, "SITE_NAME") 

727 and settings.SITE_NAME[0:2] == "cr" 

728 and ( 

729 (settings.SITE_NAME != "crbiol" and year > 2020) 

730 or (settings.SITE_NAME == "crbiol" and year > 2022) 

731 ) 

732 and container.title_html == "" 

733 ): 

734 title = _("Articles du volume en cours") 

735 href = reverse("volume-general-items", kwargs={"vid": container.get_vid()}) 

736 else: 

737 href = container.get_absolute_url() 

738 title = "no." + " " + number 

739 crumbs.append({"href": href, "title": title}) 

740 

741 return crumbs 

742 

743 

744def get_breadcrumb(article, container, collection, stop_at_volume=False): 

745 all_crumbs = [] 

746 is_a_mersenne_books = False 

747 previous = next = "" 

748 article_crumb = None 

749 

750 if article: 

751 display_page = True 

752 if hasattr(settings, "PAGE_BREADCRUMB"): 752 ↛ 753line 752 didn't jump to line 753, because the condition on line 752 was never true

753 display_page = settings.PAGE_BREADCRUMB 

754 if display_page: 754 ↛ 758line 754 didn't jump to line 758, because the condition on line 754 was never false

755 href = article.get_absolute_url() 

756 title = article.get_breadcrumb_page_text() 

757 article_crumb = {"href": href, "title": title} 

758 previous = article.previous().get_absolute_url() if article.previous() else None 

759 next = article.next().get_absolute_url() if article.next() else None 

760 elif collection.pid == "CJPS" or settings.CONTAINER_SEQUENCED: 760 ↛ 761line 760 didn't jump to line 761, because the condition on line 760 was never true

761 previous = container.previous().get_absolute_url() if container.previous() else None 

762 next = container.next().get_absolute_url() if container.next() else None 

763 

764 crumbs = get_container_breadcrumb( 

765 collection, 

766 container, 

767 container.vseries, 

768 container.volume, 

769 container.number, 

770 stop_at_volume, 

771 ) 

772 if article_crumb: 

773 crumbs.append(article_crumb) 

774 

775 all_crumbs.append({"crumbs": crumbs, "previous": previous, "next": next}) 

776 if collection.pid == "MBK": 776 ↛ 777line 776 didn't jump to line 777, because the condition on line 776 was never true

777 is_a_mersenne_books = True 

778 else: 

779 is_a_mersenne_books = False 

780 # mersenne_books_crumb = {'href': collection.get_absolute_url(), 'title': collection.title_html} 

781 for collection_membership in container.collectionmembership_set.all(): 781 ↛ 782line 781 didn't jump to line 782, because the loop on line 781 never started

782 collection = collection_membership.collection 

783 vseries = collection_membership.vseries 

784 volume = collection_membership.volume 

785 number = collection_membership.number 

786 crumbs = get_container_breadcrumb( 

787 collection, container, vseries, volume, number, stop_at_volume=True 

788 ) 

789 if article_crumb: 

790 crumbs.append(article_crumb) 

791 

792 # uniquement pour les livres Mersenne ; si un livre appartient à une 2ème collection, on n'affiche que celle-ci 

793 # {{2eme collection}} > Titre Container > Tome1... 

794 if is_a_mersenne_books: 

795 all_crumbs.pop() 

796 # crumbs.insert(0, mersenne_books_crumb) 

797 all_crumbs.append({"crumbs": crumbs, "previous": previous, "next": next}) 

798 

799 show_tex = False 

800 if hasattr(settings, "SHOW_TEX"): 800 ↛ 803line 800 didn't jump to line 803, because the condition on line 800 was never false

801 show_tex = settings.SHOW_TEX 

802 

803 return {"all_crumbs": all_crumbs, "show_tex": show_tex} 

804 

805 

806########################################################################## 

807# 

808# Update functions 

809# 

810########################################################################## 

811def post_resource_updated(resource): 

812 """ 

813 A resource is modified (ex: matching), the last_modified date of its container has to be updated. 

814 :param resource: 

815 :return: 

816 """ 

817 obj = resource.cast() 

818 container = obj.get_container() 

819 if container: 819 ↛ exitline 819 didn't return from function 'post_resource_updated', because the condition on line 819 was never false

820 container.last_modified = timezone.now() 

821 container.save() 

822 

823 

824def update_deployed_date(resource, site, deployed_date_in_prod_to_restore=None, file_=None): 

825 """ 

826 Used by ptf_tools during DeployJatsIssue 

827 

828 Update the SiteMembership deployed_date of container/site based on the production website. 

829 - If there is no deployed_date in ptf_tools (not yet in prod), we create one. 

830 - with deployed_date_in_prod if it's not None (case when we restore data), or 

831 - with now if deployed_date_in_prod is None (first deploy in prod) 

832 - If the last_modified date of the container in ptf_tools is > deployed_date_in_prod 

833 (we have a new version in ptf_tools), we update deployed_date_in_prod with now(), 

834 - else we update deployed_date with deployed_date_in_prod 

835 (Normally, they should be equal) 

836 

837 :param resource: 

838 :param site: 

839 :param deployed_date_in_prod_to_restore: 

840 :param file_ file object to log info 

841 :return: 

842 """ 

843 

844 def get_deployed_date_in_prod(resource_, site_): 

845 deployed_date_in_prod = None 

846 try: 

847 membership = SiteMembership.objects.get(resource=resource_, site=site_) 

848 deployed_date_in_prod = membership.deployed 

849 except SiteMembership.DoesNotExist: 

850 pass 

851 

852 return deployed_date_in_prod 

853 

854 def update_or_create(resource_, site_, deployed): 

855 try: 

856 membership = SiteMembership.objects.get(resource=resource_, site=site_) 

857 membership.deployed = deployed 

858 except SiteMembership.DoesNotExist: 

859 membership = SiteMembership(resource=resource_, site=site_, deployed=deployed) 

860 membership.save() 

861 

862 container = article = None 

863 

864 if resource.classname == "Article": 864 ↛ 865line 864 didn't jump to line 865, because the condition on line 864 was never true

865 article = resource 

866 container = article.my_container 

867 else: 

868 container = resource 

869 

870 existing_deployed_date = get_deployed_date_in_prod(container, site) 

871 

872 # If we restore deployed_date, force the new value to the restored value 

873 if deployed_date_in_prod_to_restore: 

874 new_deployed_date = deployed_date_in_prod_to_restore 

875 else: 

876 # Get the existing deployed_date_in_prod (from SiteMembership) 

877 new_deployed_date = existing_deployed_date 

878 

879 # If there is no value of if the current version (last_modified) is newer, update the date 

880 if new_deployed_date is None or container.last_modified > new_deployed_date: 880 ↛ 885line 880 didn't jump to line 885, because the condition on line 880 was never false

881 new_deployed_date = timezone.now() 

882 

883 # Set the new value to the entire container/articles (+ collection) 

884 

885 if file_: 885 ↛ 886line 885 didn't jump to line 886, because the condition on line 885 was never true

886 file_.write( 

887 "{}. Date to restore: {}. Container.last_modified: {}, Existing date {}. New date {}\n".format( 

888 container.pid, 

889 deployed_date_in_prod_to_restore, 

890 container.last_modified, 

891 existing_deployed_date, 

892 new_deployed_date, 

893 ) 

894 ) 

895 

896 update_or_create(container, site, new_deployed_date) 

897 update_or_create(container.get_collection(), site, new_deployed_date) 

898 

899 if article is not None: 899 ↛ 900line 899 didn't jump to line 900, because the condition on line 899 was never true

900 update_or_create(article, site, new_deployed_date) 

901 else: 

902 for article in container.article_set.all(): 

903 update_or_create(article, site, new_deployed_date) 

904 

905 

906def assign_doi(pid): 

907 """ 

908 In the Mersenne process, articles imported for the first time receive a DOI. 

909 Thus function creates a new DOI, based on the last doi stored in the Collection object. 

910 :param pid: 

911 :return: A new DOI, equal to 10.5802/@pid.(last_doi + 1) 

912 """ 

913 collection = get_collection(pid) 

914 

915 if collection is None: 915 ↛ 916line 915 didn't jump to line 916, because the condition on line 915 was never true

916 return None 

917 

918 last_doi = collection.last_doi + 1 

919 collection.last_doi = last_doi 

920 collection.save() 

921 

922 doi = "10.5802/" + pid.lower() + "." + str(last_doi) 

923 return doi 

924 

925 

926# TODO make a command ? 

927 

928 

929def add_or_update_extid( 

930 resource, id_type, id_value, checked, false_positive, update_last_modified=True 

931): 

932 from ptf.cmds import database_cmds 

933 

934 if id_value: 934 ↛ exitline 934 didn't return from function 'add_or_update_extid', because the condition on line 934 was never false

935 extid = get_extid(resource, id_type) 

936 if extid: 

937 if not extid.checked: 937 ↛ 938line 937 didn't jump to line 938, because the condition on line 937 was never true

938 extid.id_value = id_value 

939 extid.checked = checked 

940 extid.false_positive = false_positive 

941 extid.save() 

942 else: 

943 cmd = database_cmds.addExtIdDatabaseCmd( 

944 { 

945 "id_type": id_type, 

946 "id_value": id_value, 

947 "checked": checked, 

948 "false_positive": false_positive, 

949 } 

950 ) 

951 cmd.set_resource(resource) 

952 cmd.do() 

953 

954 # last_modified is not modified during data restoration (importExtraDataPtfCmd) 

955 if update_last_modified: 955 ↛ 956line 955 didn't jump to line 956, because the condition on line 955 was never true

956 post_resource_updated(resource) 

957 

958 

959def add_or_update_bibitemid( 

960 bibitem, id_type, id_value, checked, false_positive, update_last_modified=True 

961): 

962 from ptf.cmds import database_cmds 

963 from ptf.cmds import xml_cmds 

964 

965 if id_value: 965 ↛ exitline 965 didn't return from function 'add_or_update_bibitemid', because the condition on line 965 was never false

966 bibitemid = get_bibitemid(bibitem, id_type) 

967 if bibitemid: 

968 bibitemid.id_value = id_value 

969 bibitemid.checked = checked 

970 bibitemid.false_positive = false_positive 

971 bibitemid.save() 

972 else: 

973 cmd = database_cmds.addBibItemIdDatabaseCmd( 

974 { 

975 "id_type": id_type, 

976 "id_value": id_value, 

977 "checked": checked, 

978 "false_positive": false_positive, 

979 } 

980 ) 

981 cmd.set_bibitem(bibitem) 

982 cmd.do() 

983 

984 # Update citation_xml|html|tex 

985 cmd = xml_cmds.updateBibitemCitationXmlCmd() 

986 cmd.set_bibitem(bibitem) 

987 cmd.do() 

988 

989 # last_modified is not modified during data restoration (importExtraDataPtfCmd) 

990 if update_last_modified: 

991 post_resource_updated(bibitem.resource) 

992 

993 

994def get_site_id(collection_id): 

995 result = [v for k, v in SITE_REGISTER.items() if v["collection_pid"] == collection_id] 

996 return result[0]["site_id"] if result else "" 

997 

998 

999def get_collection_id(site_id): 

1000 result = [v for k, v in SITE_REGISTER.items() if v["site_id"] == site_id] 

1001 return result[0]["collection_pid"] if result else "" 

1002 

1003 

1004def is_site_en_only(site_id): 

1005 result = [v for k, v in SITE_REGISTER.items() if v["site_id"] == site_id] 

1006 return result[0]["en_only"] if result else False 

1007 

1008 

1009def is_site_fr_only(site_id): 

1010 result = [v for k, v in SITE_REGISTER.items() if v["site_id"] == site_id] 

1011 return result[0]["fr_only"] if result and "fr_only" in result[0] else False