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

476 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2024-05-30 16:32 +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.utils import timezone 

14 

15from .models import Article 

16from .models import Author 

17from .models import BibItem 

18from .models import BibItemId 

19from .models import Collection 

20from .models import Container 

21from .models import ExtId 

22from .models import ExtLink 

23from .models import Provider 

24from .models import PtfSite 

25from .models import Publisher 

26from .models import RelatedObject 

27from .models import RelationName 

28from .models import Relationship 

29from .models import Resource 

30from .models import SiteMembership 

31from .models import XmlBase 

32from .site_register import SITE_REGISTER 

33 

34########################################################################## 

35# 

36# Get functions 

37# 

38########################################################################## 

39 

40 

41def get_first_last_years(year): 

42 the_array = year.split("-") 

43 

44 fyear = the_array[0] 

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

46 

47 return fyear, lyear 

48 

49 

50def get_provider_by_name(name): 

51 if name == "numdam": 

52 name = "mathdoc" 

53 

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

55 return provider 

56 

57 

58def get_provider(pid_type): 

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

60 return provider 

61 

62 

63def get_publisher(name): 

64 try: 

65 key = make_key(name) 

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

67 except Publisher.DoesNotExist: 

68 publisher = None 

69 return publisher 

70 

71 

72def get_or_create_site(site_id, acro=None): 

73 try: 

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

75 except PtfSite.DoesNotExist: 

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

77 return site 

78 

79 

80def get_journals(): 

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

82 return journals.all() 

83 

84 

85def get_actas(): 

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

87 return actas.all() 

88 

89 

90def get_lectures(): 

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

92 return lectures.all() 

93 

94 

95def get_proceedings(): 

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

97 return proceedings.all() 

98 

99 

100def get_collection_of_books(with_lectures=False): 

101 filters = ["book-series"] 

102 if with_lectures: 

103 filters.append("lecture-notes") 

104 

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

106 return book_series.all() 

107 

108 

109def get_books(): 

110 return Container.objects.filter( 

111 sites__id=settings.SITE_ID, 

112 my_collection__coltype__in=["book-series", "lecture-notes", "book-edited-book"], 

113 ) 

114 

115 

116def get_theses(): 

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

118 return theses.all() 

119 

120 

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

122 

123 

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

125 try: 

126 if sites: 

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

128 else: 

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

130 except Collection.DoesNotExist: 

131 col = None 

132 return col 

133 

134 

135def get_volumes_in_collection(collection): 

136 """ 

137 used by issue-list.html and oai gallica 

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

139 return list of publishers GROUP BY name with date 

140 @param collection: 

141 @return: 

142 

143 """ 

144 

145 items = ( 

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

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

148 .all() 

149 ) 

150 # We're building the following list: 

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

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

153 # } 

154 # ] 

155 # 

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

157 # 'title': ? 

158 # 'fyear': fyear, 

159 # 'lyear': lyear, 

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

161 

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

163 col_membsership_qs = ( 

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

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

166 .all() 

167 ) 

168 joined = itertools.chain(items, col_membsership_qs) 

169 

170 def sorter(dict_): 

171 return ( 

172 dict_.vseries_int, 

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

174 dict_.volume_int, 

175 dict_.number_int, 

176 ) 

177 

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

179 

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

181 

182 issue_to_appear_pid = "" 

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

184 issue_to_appear_pid = settings.ISSUE_TO_APPEAR_PID 

185 

186 issues_in_vseries = [] 

187 volumes_in_vseries = [] 

188 issues_in_volume = [] 

189 publishers = [] 

190 results_vseries = "-1" 

191 results_volume = "-1" 

192 results_year = "-1" 

193 results_fyear = results_lyear = -1 

194 volume_count = 0 

195 max_volume_count = 0 

196 max_width = 0 

197 width = 0 

198 for item in items: 

199 width += len(item.number) 

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

201 issue = item.container 

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

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

204 issue.veries = item.vseries 

205 issue.volume = item.volume 

206 issue.number = item.number 

207 issue.vseries_int = item.vseries_int 

208 issue.volume_int = item.volume_int 

209 issue.number_int = item.number_int 

210 

211 year = issue.year 

212 vseries = item.vseries 

213 volume = item.volume 

214 else: 

215 issue = item 

216 year = issue.year 

217 vseries = issue.vseries 

218 volume = issue.volume 

219 

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

221 fyear, lyear = get_first_last_years(year) 

222 fyear = int(fyear) 

223 lyear = int(lyear) 

224 

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

226 if ( 226 ↛ 256line 226 didn't jump to line 256

227 results_volume != volume 

228 or (results_volume == "" and results_year != year) 

229 # or (results_volume == volume and results_year != year) 

230 ): 

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

232 # But we do not append in volumes_in_vseries 

233 if results_volume != "-1": 

234 volumes_in_vseries.append( 

235 { 

236 "volume": results_volume, 

237 "fyear": results_fyear, 

238 "lyear": results_lyear, 

239 "issues": issues_in_volume, 

240 } 

241 ) 

242 # Clear issues_in_volume to prepare a new volume 

243 issues_in_volume = [] 

244 

245 # Set the current volume info 

246 results_volume = volume 

247 results_year = year 

248 results_fyear = fyear 

249 results_lyear = lyear 

250 volume_count += 1 

251 if width > max_width: 

252 max_width = width 

253 width = 0 

254 

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

256 if results_vseries != vseries: 

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

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

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

260 issues_in_vseries.append( 

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

262 ) 

263 volumes_in_vseries = [] 

264 results_vseries = vseries 

265 max_volume_count = max(0, volume_count) 

266 volume_count = 0 

267 

268 issues_in_volume.append(issue) 

269 

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

271 if issue.my_publisher: 

272 if publishers: 

273 item = publishers[-1] 

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

275 item = { 

276 "name": issue.my_publisher.pub_name, 

277 "fyear": fyear, 

278 "lyear": lyear, 

279 } 

280 publishers.append(item) 

281 else: 

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

283 item["fyear"] = fyear 

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

285 item["lyear"] = lyear 

286 else: 

287 publishers.insert( 

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

289 ) 

290 

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

292 # then volumes_in_vseries 

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

294 volumes_in_vseries.append( 

295 { 

296 "volume": results_volume, 

297 "fyear": results_fyear, 

298 "lyear": results_lyear, 

299 "issues": issues_in_volume, 

300 } 

301 ) 

302 # volume_count += 1 

303 

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

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

306 max_volume_count = max(0, volume_count) 

307 

308 context = { 

309 "sorted_issues": issues_in_vseries, 

310 "volume_count": max_volume_count, 

311 "publishers": publishers, 

312 "max_width": max_width, 

313 } 

314 

315 return context 

316 

317 

318def get_container(pid, prefetch=False, sites=True): 

319 try: 

320 if prefetch: 

321 container = ( 

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

323 .prefetch_for_toc() 

324 .first() 

325 ) 

326 else: 

327 if sites: 327 ↛ 330line 327 didn't jump to line 330, because the condition on line 327 was never false

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

329 else: 

330 container = Container.objects.get(pid=pid) 

331 

332 except Container.DoesNotExist: 

333 container = None 

334 return container 

335 

336 

337def get_book_serie(pid): 

338 try: 

339 book_serie = Collection.objects.get( 

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

341 ) 

342 except Collection.DoesNotExist: 

343 book_serie = None 

344 return book_serie 

345 

346 

347def get_issues_count_in_collection(pid): 

348 try: 

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

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

351 return issues 

352 except Exception: 

353 pass 

354 

355 

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

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

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

359 first_issue = get_container(vid) 

360 if first_issue is None: 

361 raise Http404 

362 

363 collection = first_issue.get_collection() 

364 year = first_issue.year 

365 vseries = first_issue.vseries 

366 volume = first_issue.volume 

367 

368 if is_cr: 

369 year_int = int(year) 

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

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

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

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

374 elif year_int > 2022 and collection.pid == "CRBIOL": 

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

376 else: 

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

378 if general_articles: 

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

380 else: 

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

382 queryset = queryset.filter( 

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

384 ).prefetch_for_toc() 

385 issues = get_list_or_404(queryset) 

386 

387 if is_cr and ( 

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

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

390 ): 

391 issues_articles = [] 

392 grouped_articles = [] 

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

394 for issue in issues: 

395 if len(issue.title_html) == 0: 395 ↛ 399line 395 didn't jump to line 399, because the condition on line 395 was never false

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

397 grouped_issue_articles["issue"] = issue 

398 else: 

399 issues_articles.append( 

400 { 

401 "issue": issue, 

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

403 if settings.SORT_ARTICLES_BY_DATE 

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

405 } 

406 ) 

407 if grouped_issue_articles["issue"] is not None: 407 ↛ 420line 407 didn't jump to line 420, because the condition on line 407 was never false

408 issues_articles.insert(0, grouped_issue_articles) 

409 else: 

410 issues_articles = [ 

411 { 

412 "issue": issue, 

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

414 if settings.SORT_ARTICLES_BY_DATE 

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

416 } 

417 for issue in issues 

418 ] 

419 

420 return issues_articles, collection 

421 

422 

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

424 try: 

425 if prefetch: 

426 article = ( 

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

428 ) 

429 else: 

430 if sites: 430 ↛ 433line 430 didn't jump to line 433, because the condition on line 430 was never false

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

432 else: 

433 article = Article.objects.get(pid=pid) 

434 

435 except Article.DoesNotExist: 

436 article = None 

437 return article 

438 

439 

440def get_article_by_doi(doi, prefetch=False): 

441 try: 

442 if prefetch: 

443 article = ( 

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

445 ) 

446 else: 

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

448 

449 except Article.DoesNotExist: 

450 article = None 

451 return article 

452 

453 

454def get_articles(): 

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

456 classname="TranslatedArticle" 

457 ) 

458 return article_qs 

459 

460 

461def get_articles_by_deployed_date(): 

462 sitemembership_qs = SiteMembership.objects.filter( 

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

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

465 

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

467 return articles 

468 

469 

470def get_articles_by_published_date(): 

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

472 classname="TranslatedArticle" 

473 ) 

474 if hasattr(settings, "ISSUE_TO_APPEAR_PID"): 

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

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

477 

478 return article_qs 

479 

480 

481def get_xmlbase(base): 

482 try: 

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

484 except XmlBase.DoesNotExist: 

485 xmlbase = None 

486 return xmlbase 

487 

488 

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

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

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

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

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

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

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

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

497def get_relationname_left(left_name): 

498 try: 

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

500 except RelationName.DoesNotExist: 

501 relationname = None 

502 

503 return relationname 

504 

505 

506def get_relationname_right(right_name): 

507 try: 

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

509 except RelationName.DoesNotExist: 

510 relationname = None 

511 

512 return relationname 

513 

514 

515# See comments about RelationName above 

516def get_relationship(subject_pid, object_pid, relationname): 

517 try: 

518 relationship = Relationship.objects.get( 

519 subject_pid=subject_pid, object_pid=object_pid, rel_info=relationname 

520 ) 

521 except Relationship.DoesNotExist: 

522 relationship = None 

523 

524 return relationship 

525 

526 

527def get_extid(resource, id_type): 

528 extid = None 

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

530 if extids.count() > 0: 

531 extid = extids.first() 

532 

533 return extid 

534 

535 

536def get_bibitemid(bibitem, id_type): 

537 bibitemid = None 

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

539 if bibitemids.count() > 0: 

540 bibitemid = bibitemids.first() 

541 

542 return bibitemid 

543 

544 

545def get_bibitem_by_seq(article, seq): 

546 try: 

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

548 except BibItem.DoesNotExist: 

549 bibitem = None 

550 return bibitem 

551 

552 

553def get_extlink(**filters): 

554 try: 

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

556 except ExtLink.DoesNotExist: 

557 extlink = None 

558 return extlink 

559 

560 

561def get_related_object(**filters): 

562 """ 

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

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

565 Check models.py for the params of a RelatedObject 

566 """ 

567 try: 

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

569 related_object.select_related() 

570 except RelatedObject.DoesNotExist: 

571 related_object = None 

572 return related_object 

573 

574 

575def get_authors_by_letter(first_letter): 

576 try: 

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

578 except Author.DoesNotExist: 

579 authors = None 

580 return authors 

581 

582 

583def make_key(string): 

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

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

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

587 if len(n_string) > 64: 

588 n_string = n_string[:64] 

589 

590 return n_string if n_string else unidecode(string) 

591 

592 

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

594 try: 

595 if prefetch: 

596 resource = ( 

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

598 ) 

599 else: 

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

601 except Resource.DoesNotExist: 

602 resource = None 

603 return resource 

604 

605 

606def get_resource_by_doi(doi, prefetch=False): 

607 try: 

608 if prefetch: 608 ↛ 609line 608 didn't jump to line 609

609 resource = ( 

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

611 ) 

612 else: 

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

614 

615 except Resource.DoesNotExist: 

616 resource = None 

617 return resource 

618 

619 

620def get_random_containers(): 

621 # TODO get the newest containers only 

622 

623 containers = Container.objects.all() 

624 random_list = random.sample(containers, 6) 

625 

626 return random_list 

627 

628 

629def parse_date_str(date_str): 

630 """ 

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

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

633 """ 

634 the_date = dateutil.parser.parse(date_str) 

635 if not timezone.is_aware(the_date): 

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

637 return the_date 

638 

639 

640def get_issue_to_appear(colid): 

641 """ 

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

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

644 :param pid: 

645 :return: The container object of articles to appear 

646 """ 

647 pid = "" 

648 

649 if hasattr(settings, "ISSUE_TO_APPEAR_PIDS"): 

650 if colid in settings.ISSUE_TO_APPEAR_PIDS: 

651 pid = settings.ISSUE_TO_APPEAR_PIDS[colid] 

652 

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

654 return container 

655 

656 

657def get_number_from_doi(doi): 

658 value = 0 

659 

660 try: 

661 index = doi.rfind(".") 

662 index += 1 

663 if index > 0: 

664 str_value = doi[index:] 

665 value = int(str_value) 

666 except BaseException: 

667 pass 

668 

669 return value 

670 

671 

672def get_site_mersenne(collection_pid): 

673 key = collection_pid.lower() 

674 

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

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

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

678 key = "smai" 

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

680 key = "centre_mersenne" 

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

682 key = "mbk" 

683 

684 try: 

685 site_item = settings.SITE_REGISTER[key] 

686 except KeyError: 

687 return None 

688 site_id = site_item["site_id"] 

689 site_acro = key 

690 

691 return get_or_create_site(site_id, site_acro) 

692 

693 

694########################################################################## 

695# 

696# Update functions 

697# 

698########################################################################## 

699def post_resource_updated(resource): 

700 """ 

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

702 :param resource: 

703 :return: 

704 """ 

705 obj = resource.cast() 

706 container = obj.get_container() 

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

708 container.last_modified = timezone.now() 

709 container.save() 

710 

711 

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

713 """ 

714 Used by ptf_tools during DeployJatsIssue 

715 

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

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

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

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

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

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

722 - else we update deployed_date with deployed_date_in_prod 

723 (Normally, they should be equal) 

724 

725 :param resource: 

726 :param site: 

727 :param deployed_date_in_prod_to_restore: 

728 :param file_ file object to log info 

729 :return: 

730 """ 

731 

732 def get_deployed_date_in_prod(resource_, site_): 

733 deployed_date_in_prod = None 

734 try: 

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

736 deployed_date_in_prod = membership.deployed 

737 except SiteMembership.DoesNotExist: 

738 pass 

739 

740 return deployed_date_in_prod 

741 

742 def update_or_create(resource_, site_, deployed): 

743 try: 

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

745 membership.deployed = deployed 

746 except SiteMembership.DoesNotExist: 

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

748 membership.save() 

749 

750 container = article = None 

751 

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

753 article = resource 

754 container = article.my_container 

755 else: 

756 container = resource 

757 

758 existing_deployed_date = get_deployed_date_in_prod(container, site) 

759 

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

761 if deployed_date_in_prod_to_restore: 

762 new_deployed_date = deployed_date_in_prod_to_restore 

763 else: 

764 # Get the existing deployed_date_in_prod (from SiteMembership) 

765 new_deployed_date = existing_deployed_date 

766 

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

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

769 new_deployed_date = timezone.now() 

770 

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

772 

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

774 file_.write( 

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

776 container.pid, 

777 deployed_date_in_prod_to_restore, 

778 container.last_modified, 

779 existing_deployed_date, 

780 new_deployed_date, 

781 ) 

782 ) 

783 

784 update_or_create(container, site, new_deployed_date) 

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

786 

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

788 update_or_create(article, site, new_deployed_date) 

789 else: 

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

791 update_or_create(article, site, new_deployed_date) 

792 

793 

794def assign_doi(pid): 

795 """ 

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

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

798 :param pid: 

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

800 """ 

801 collection = get_collection(pid) 

802 

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

804 return None 

805 

806 last_doi = collection.last_doi + 1 

807 collection.last_doi = last_doi 

808 collection.save() 

809 

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

811 return doi 

812 

813 

814# TODO make a command ? 

815 

816 

817def add_or_update_extid( 

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

819): 

820 from ptf.cmds import database_cmds 

821 

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

823 extid = get_extid(resource, id_type) 

824 if extid: 

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

826 extid.id_value = id_value 

827 extid.checked = checked 

828 extid.false_positive = false_positive 

829 extid.save() 

830 else: 

831 cmd = database_cmds.addExtIdDatabaseCmd( 

832 { 

833 "id_type": id_type, 

834 "id_value": id_value, 

835 "checked": checked, 

836 "false_positive": false_positive, 

837 } 

838 ) 

839 cmd.set_resource(resource) 

840 cmd.do() 

841 

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

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

844 post_resource_updated(resource) 

845 

846 

847def add_or_update_bibitemid( 

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

849): 

850 from ptf.cmds import database_cmds 

851 from ptf.cmds import xml_cmds 

852 

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

854 bibitemid = get_bibitemid(bibitem, id_type) 

855 if bibitemid: 

856 bibitemid.id_value = id_value 

857 bibitemid.checked = checked 

858 bibitemid.false_positive = false_positive 

859 bibitemid.save() 

860 else: 

861 cmd = database_cmds.addBibItemIdDatabaseCmd( 

862 { 

863 "id_type": id_type, 

864 "id_value": id_value, 

865 "checked": checked, 

866 "false_positive": false_positive, 

867 } 

868 ) 

869 cmd.set_bibitem(bibitem) 

870 cmd.do() 

871 

872 # Update citation_xml|html|tex 

873 cmd = xml_cmds.updateBibitemCitationXmlCmd() 

874 cmd.set_bibitem(bibitem) 

875 cmd.do() 

876 

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

878 if update_last_modified: 

879 post_resource_updated(bibitem.resource) 

880 

881 

882def get_site_id(collection_id): 

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

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

885 

886 

887def get_collection_id(site_id): 

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

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

890 

891 

892def is_site_en_only(site_id): 

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

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

895 

896 

897def is_site_fr_only(site_id): 

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

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