Coverage for apps/ptf/cmds/ptf_cmds/base_ptf_cmds.py: 70%

865 statements  

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

1import copy 

2import datetime 

3import json 

4import os 

5import subprocess 

6import sys 

7 

8import lxml.etree as etree 

9from PIL import Image 

10 

11from django.conf import settings 

12from django.core.exceptions import ObjectDoesNotExist 

13from django.template.loader import render_to_string 

14 

15from ptf import exceptions 

16from ptf import model_helpers 

17from ptf import utils 

18from ptf.cmds.database_cmds import add_contributors 

19from ptf.cmds.database_cmds import addArticleDatabaseCmd 

20from ptf.cmds.database_cmds import addBibItemDatabaseCmd 

21from ptf.cmds.database_cmds import addBibItemIdDatabaseCmd 

22from ptf.cmds.database_cmds import addCollectionDatabaseCmd 

23from ptf.cmds.database_cmds import addContainerDatabaseCmd 

24from ptf.cmds.database_cmds import addDataStreamDatabaseCmd 

25from ptf.cmds.database_cmds import addExtIdDatabaseCmd 

26from ptf.cmds.database_cmds import addExtLinkDatabaseCmd 

27from ptf.cmds.database_cmds import addFrontMatterDatabaseCmd 

28from ptf.cmds.database_cmds import addProviderDatabaseCmd 

29from ptf.cmds.database_cmds import addPublisherDatabaseCmd 

30from ptf.cmds.database_cmds import addRelatedObjectDatabaseCmd 

31from ptf.cmds.database_cmds import addRelationshipDatabaseCmd 

32from ptf.cmds.database_cmds import addResourceCountDatabaseCmd 

33from ptf.cmds.database_cmds import addSiteDatabaseCmd 

34from ptf.cmds.database_cmds import addSupplementaryMaterialDatabaseCmd 

35from ptf.cmds.database_cmds import addXmlBaseDatabaseCmd 

36from ptf.cmds.database_cmds import baseCmd 

37from ptf.cmds.database_cmds import publishArticleDatabaseCmd 

38from ptf.cmds.database_cmds import publishContainerDatabaseCmd 

39from ptf.cmds.database_cmds import updateCollectionDatabaseCmd 

40from ptf.cmds.database_cmds import updateExtLinkDatabaseCmd 

41from ptf.cmds.database_cmds import updateResourceIdDatabaseCmd 

42from ptf.cmds.solr_cmds import addArticleSolrCmd 

43from ptf.cmds.solr_cmds import addBookPartSolrCmd 

44from ptf.cmds.solr_cmds import addContainerSolrCmd 

45from ptf.cmds.solr_cmds import solrFactory 

46from ptf.cmds.solr_cmds import updateResourceSolrCmd 

47from ptf.cmds.xml import xml_utils 

48from ptf.display import resolver 

49from ptf.model_data import PublisherData 

50from ptf.models import ExtLink 

51from ptf.models import Person 

52from ptf.models import Relationship 

53from ptf.models import backup_obj_not_in_metadata 

54from ptf.models import restore_obj_not_in_metadata 

55 

56 

57def myconverter(o): 

58 if isinstance(o, datetime.datetime): 58 ↛ exitline 58 didn't return from function 'myconverter', because the condition on line 58 was never false

59 return o.__str__() 

60 

61 

62def do_solr_commit(): 

63 solrFactory.do_solr_commit() 

64 

65 

66def do_solr_rollback(): 

67 solrFactory.do_solr_rollback() 

68 

69 

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

71# 

72# addPtfCmd: base class of PtfCmds 

73# 

74# PtfCmds may have a cmd and a sub-cmd 

75# The cmd is executed, and the id of the returned object is passed 

76# to the sub-cmd before its execution. 

77# 

78# This allows to store an object in Django, get the django object id, 

79# then store the corresponding document in Solr 

80# 

81###################################################################### 

82 

83 

84class addPtfCmd(baseCmd): 

85 def __init__(self, params=None): 

86 if params is not None and "solr_commit" in params: 

87 params["commit"] = params["solr_commit"] 

88 

89 super().__init__(params) 

90 self.required_delete_params.append("object_to_be_deleted") 

91 

92 self.cmd = None 

93 self.sub_cmd = None 

94 

95 def internal_do(self): 

96 obj = super().internal_do() 

97 

98 if self.cmd: 98 ↛ 101line 98 didn't jump to line 101, because the condition on line 98 was never false

99 obj = self.cmd.do() 

100 

101 if self.sub_cmd: 

102 self.sub_cmd.db_obj = obj 

103 self.sub_cmd.id = obj.id 

104 self.sub_cmd.pid = obj.pid 

105 

106 # if hasattr(obj, "title_tex"): 

107 # self.sub_cmd.title = obj.title_tex 

108 

109 self.sub_cmd.do() 

110 # au cas d'un futur undo sur la cmd 

111 self.set_object_to_be_deleted(obj) 

112 return obj 

113 

114 def set_object_to_be_deleted(self, obj): 

115 if obj is not None: 115 ↛ exitline 115 didn't return from function 'set_object_to_be_deleted', because the condition on line 115 was never false

116 self.object_to_be_deleted = obj 

117 self.cmd.object_to_be_deleted = obj 

118 

119 def internal_undo(self): 

120 id = super().internal_undo() 

121 

122 if self.cmd: 122 ↛ 125line 122 didn't jump to line 125, because the condition on line 122 was never false

123 id = self.cmd.undo() 

124 

125 if self.sub_cmd: 

126 self.sub_cmd.id = id 

127 self.sub_cmd.undo() 

128 

129 return id 

130 

131 

132##################################################################### 

133# 

134# addSitePtfCmd: adds/remove a PtfSite 

135# params: 'site_name', 'site_domain' 

136# 

137# Exception raised: 

138# - ValueError if the init params are empty 

139# - exceptions.ResourceExists during do if the site already exists 

140# - exceptions.ResourceDoesNotExist during undo if the site does not exist 

141# - RuntimeError during undo if resources are still published 

142# 

143###################################################################### 

144class addSitePtfCmd(addPtfCmd): 

145 def __init__(self, params=None): 

146 super().__init__(params) 

147 

148 self.cmd = addSiteDatabaseCmd(params) 

149 

150 

151##################################################################### 

152# 

153# addProviderPtfCmd: adds/remove a Provider 

154# params: 'name', 'pid_type', 'sid_type' 

155# 

156# Exception raised: 

157# - ValueError if the init params are empty 

158# - exceptions.ResourceExists during do if the provider already exists 

159# - exceptions.ResourceDoesNotExist during undo if the provider does not exist 

160# 

161###################################################################### 

162class addProviderPtfCmd(addPtfCmd): 

163 def __init__(self, params=None): 

164 super().__init__(params) 

165 

166 self.cmd = addProviderDatabaseCmd(params) 

167 

168 

169##################################################################### 

170# 

171# addXmlBasePtfCmd: adds/remove an XmlBase 

172# XmlBase is the root URL of an ExtLink (ex: http://archive.numdam.org/article) 

173# params: 'base' 

174# 

175# Exception raised: 

176# - ValueError if the init params are empty 

177# - exceptions.ResourceExists during do if the XmlBase already exists 

178# - exceptions.ResourceDoesNotExist during undo if the XmlBase does not exist 

179# - RuntimeError during undo if related extlinks or objects still exist 

180# 

181###################################################################### 

182class addXmlBasePtfCmd(addPtfCmd): 

183 def __init__(self, params=None): 

184 super().__init__(params) 

185 

186 self.cmd = addXmlBaseDatabaseCmd(params) 

187 

188 

189##################################################################### 

190# 

191# addExtLinkPtfCmd: adds/remove an ExtLink 

192# params: 'rel': 'website' or 'small_icon' 

193# 'mimetype', 'location', 'metadata', 'seq' 

194# 

195# Needs a Resource object (required) and a XmlBase object (option) 

196# 

197# Exception raised: 

198# - ValueError if the init params are empty 

199# - exceptions.ResourceExists during do if the ExtLink already exists 

200# - exceptions.ResourceDoesNotExist during undo if the ExtLink does not exist 

201# - RuntimeError during undo if resources are still published 

202# 

203###################################################################### 

204class addExtLinkPtfCmd(addPtfCmd): 

205 def __init__(self, params=None): 

206 super().__init__(params) 

207 

208 self.cmd = addExtLinkDatabaseCmd(params) 

209 

210 def set_resource(self, resource): 

211 self.cmd.set_resource(resource) 

212 

213 def set_base(self, base): 

214 self.cmd.set_base(base) 

215 

216 def pre_do(self): 

217 super().pre_do() 

218 

219 if self.to_folder and self.location.find("file:") == 0: 219 ↛ 224line 219 didn't jump to line 224, because the condition on line 219 was never true

220 # import avec un full path de fichier (ex: Elsevier CRAS) 

221 # 1. On copie le fichier 

222 # 2. On met à jour le champs location pour utiliser l'arborescence PTF 

223 # On fait ça dans le pre_do pour stocker un objet avec le champ location final 

224 from_path = self.location[5:] 

225 

226 convert_image = False 

227 extension = os.path.splitext(self.location)[1] 

228 if extension == ".tif" or extension == ".tiff": 

229 convert_image = True 

230 extension = ".jpg" 

231 

232 resource = self.cmd.resource 

233 relative_path = resource.pid + extension 

234 new_location = os.path.join(resource.get_relative_folder(), relative_path) 

235 to_path = os.path.join(self.to_folder, new_location) 

236 

237 dest_folder = os.path.dirname(to_path) 

238 os.makedirs(dest_folder, exist_ok=True) 

239 

240 if convert_image: 

241 im = Image.open(from_path) 

242 im.thumbnail(im.size) 

243 im.save(to_path, "JPEG", quality=100) 

244 else: 

245 resolver.copy_file(from_path, to_path) 

246 

247 self.location = new_location 

248 self.cmd.location = new_location 

249 

250 

251##################################################################### 

252# 

253# addExtIdPtfCmd: adds/remove an ExtId 

254# params: 'id_type', 'id_value' 

255# 

256# Needs a Resource object 

257# 

258# Exception raised: 

259# - ValueError if the init params are empty 

260# - exceptions.ResourceExists during do if the ExtId already exists 

261# - exceptions.ResourceDoesNotExist during undo if the ExtId does not exist 

262# - RuntimeError during undo if resources are still published 

263# 

264###################################################################### 

265class addExtIdPtfCmd(addPtfCmd): 

266 def __init__(self, params=None): 

267 super().__init__(params) 

268 

269 self.cmd = addExtIdDatabaseCmd(params) 

270 

271 def set_resource(self, resource): 

272 self.cmd.set_resource(resource) 

273 

274 

275##################################################################### 

276# 

277# addRelatedObjectPtfCmd: adds/remove a RelatedObject 

278# params: 'rel': 

279# 'mimetype', 'location', 'metadata', 'seq' 

280# 

281# Needs a Resource object and a XmlBase object 

282# 

283# Exception raised: 

284# - ValueError if the init params are empty 

285# - exceptions.ResourceExists during do if the RelatedObject already exists 

286# - exceptions.ResourceDoesNotExist during undo if the RelatedObject does not exist 

287# - RuntimeError during undo if resources are still published 

288# 

289###################################################################### 

290class addRelatedObjectPtfCmd(addPtfCmd): 

291 def __init__(self, params=None): 

292 super().__init__(params) 

293 self.do_linearize = True 

294 

295 # need Resource to construct complete path 

296 self.required_delete_params.append("resource") 

297 

298 self.cmd = addRelatedObjectDatabaseCmd(params) 

299 

300 def set_resource(self, resource): 

301 self.resource = resource 

302 self.cmd.set_resource(resource) 

303 

304 def set_base(self, base): 

305 self.cmd.set_base(base) 

306 

307 def pre_do(self): 

308 super().pre_do() 

309 

310 full_path_pos = self.location.find("file:") 

311 if ( 

312 self.from_folder and self.to_folder and self.from_folder == settings.CEDRAM_TEX_FOLDER 

313 ) or (self.to_folder and full_path_pos != -1): 

314 # A. Import d'un XML Cedrics. Les champs location sont relatifs au from_folder. 

315 # (contrairement à un import Cedrics transformé en JATS où les champs sont plus ou moins 

316 # relatifs au to_folder) 

317 # B. Autre possibilité: import avec un full path de fichier (ex: Elsevier CRAS) 

318 # RelatedObject est utilisé pour les images des articles (HTML) 

319 # Pour les images de couvertures des numéros, ce sont des ExtLink 

320 # (voir addExtLinkPtfCmd) 

321 # 1. On copie le fichier 

322 # 2. On met à jour le champs location pour utiliser l'arborescence PTF 

323 # On fait ça dans le pre_do pour stocker un objet avec le champ location final 

324 location = self.location 

325 if full_path_pos > -1: 325 ↛ 326line 325 didn't jump to line 326, because the condition on line 325 was never true

326 from_path = location[full_path_pos + 5 :].replace( 

327 "/ums_dev/numdam_dev", "/numdam_dev" 

328 ) 

329 else: 

330 from_path = os.path.join(self.from_folder, location) 

331 

332 convert_image = False 

333 extension = os.path.splitext(from_path)[1] 

334 resource = self.cmd.resource 

335 

336 if full_path_pos > -1 and extension in xml_utils.get_elsevier_image_extensions(): 336 ↛ 337line 336 didn't jump to line 337, because the condition on line 336 was never true

337 convert_image = True 

338 extension = ".jpg" 

339 

340 if full_path_pos > 0: 340 ↛ 341line 340 didn't jump to line 341, because the condition on line 340 was never true

341 relative_path = location[0:full_path_pos] 

342 else: 

343 i = location.find("/Attach/") 

344 if i > 0: 344 ↛ 345line 344 didn't jump to line 345, because the condition on line 344 was never true

345 relative_path = "a" + location[i + 2 :] 

346 elif extension == ".tex": 

347 relative_path = os.path.join("src/tex", resource.pid + extension) 

348 elif extension == ".jpg": 348 ↛ 349line 348 didn't jump to line 349, because the condition on line 348 was never true

349 basename = os.path.splitext(os.path.basename(from_path))[0] 

350 relative_path = os.path.join("src/tex/figures", basename + extension) 

351 elif hasattr(self, "supplementary_material") and self.supplementary_material: 351 ↛ 354line 351 didn't jump to line 354, because the condition on line 351 was never true

352 # Supplements from Elsevier. They are declared with "file://" 

353 # They need to be copied in attach/basename 

354 relative_path = "attach/" + os.path.basename(from_path) 

355 else: 

356 relative_path = resource.pid + extension 

357 

358 new_location = os.path.join(resource.get_relative_folder(), relative_path) 

359 to_path = os.path.join(self.to_folder, new_location) 

360 

361 dest_folder = os.path.dirname(to_path) 

362 os.makedirs(dest_folder, exist_ok=True) 

363 

364 do_copy = True 

365 # linearize_pdf directly create the to_path (ptf-tools only) 

366 # there is no need to copy the file in that case 

367 if extension.lower() == ".pdf" and self.do_linearize: 

368 do_copy = utils.linearize_pdf(from_path, to_path) 

369 if do_copy: 

370 if convert_image: 370 ↛ 371line 370 didn't jump to line 371, because the condition on line 370 was never true

371 im = Image.open(from_path) 

372 size = 1000, 1000 

373 im.thumbnail(size, Image.Resampling.LANCZOS) 

374 im.save(to_path, "JPEG", quality=90) 

375 else: 

376 resolver.copy_file(from_path, to_path) 

377 

378 self.location = new_location 

379 self.cmd.location = new_location 

380 

381 def post_do(self, obj): 

382 super().post_do(obj) 

383 # on est dans le cas où on veut récupérer depuis mathdoc_archive (sinon les fichiers sont copiés dans le pre_do) 

384 if self.from_folder == settings.MATHDOC_ARCHIVE_FOLDER and self.to_folder: 

385 # on passe ds binary files pour profiter de la logique copy_binary_files qui copie aussi les ExtLink (icon, small-icon) 

386 # sinon ces fichiers ne sont pas copiés -> soit icon dans DataStream ou peut-être créer une classe addBinaryFiles dont dépendraient ts les objects avec fichiers 

387 # les couvertures ne sont pas dans les xml cedram donc pas de question à se poser dans ce cas 

388 resolver.copy_binary_files(obj.resource, self.from_folder, self.to_folder) 

389 

390 def pre_undo(self): 

391 super().pre_undo() 

392 if self.to_folder: 392 ↛ 393line 392 didn't jump to line 393, because the condition on line 392 was never true

393 path = os.path.join(self.to_folder, self.object_to_be_deleted.location) 

394 resolver.delete_file(path=path) 

395 

396 

397##################################################################### 

398# 

399# addSupplementaryMaterialPtfCmd: adds/remove a Supplementary Material 

400# params: 'rel': 

401# 'mimetype', 'location', 'metadata', 'seq', 'caption' 

402# 

403# Needs a Resource object and a XmlBase object 

404# 

405# Exception raised: 

406# - ValueError if the init params are empty 

407# - exceptions.ResourceExists during do if the RelatedObject already exists 

408# - exceptions.ResourceDoesNotExist during undo if the RelatedObject does not exist 

409# - RuntimeError during undo if resources are still published 

410# 

411###################################################################### 

412class addSupplementaryMaterialPtfCmd(addRelatedObjectPtfCmd): 

413 def __init__(self, params=None): 

414 super().__init__(params) 

415 self.cmd = addSupplementaryMaterialDatabaseCmd(params) 

416 self.do_linearize = False 

417 

418 

419##################################################################### 

420# 

421# addDataStreamPtfCmd: adds/remove a RelatedObject 

422# params: 'rel': 

423# 'mimetype', 'location', 'metadata', 'seq' 

424# 

425# Needs a Resource object and a XmlBase object 

426# 

427# Exception raised: 

428# - ValueError if the init params are empty 

429# - exceptions.ResourceExists during do if the DataStream already exists 

430# - exceptions.ResourceDoesNotExist during undo if the DataStream does not exist 

431# - RuntimeError during undo if resources are still published 

432# 

433###################################################################### 

434class addDataStreamPtfCmd(addRelatedObjectPtfCmd): 

435 def __init__(self, params=None): 

436 super().__init__(params) 

437 self.cmd = addDataStreamDatabaseCmd(params) 

438 

439 

440# ##################################################################### 

441# # 

442# # addOrUpdateDataStreamPtfCmd: adds or Update a Datastream 

443# # params: 'rel': 

444# # 'mimetype', 'location', 'metadata', 'seq' 

445# # 

446# # if new location specify params: 'new_location' 

447# # Needs a Resource object and a XmlBase object 

448# # 

449# # Exception raised: 

450# # - ValueError if the init params are empty 

451# # - RuntimeError during undo if resources are still published 

452# # 

453# ###################################################################### 

454# class addOrUpdateDataStreamPtfCmd(baseCmd): 

455# def set_resource(self, resource): 

456# self.resource = resource 

457# 

458# def internal_do(self): 

459# super(addOrUpdateDataStreamPtfCmd, self).internal_do() 

460# # copy new article pdf cedram_dev to mersenne_test_data 

461# datastream_qs = DataStream.objects.filter(resource=self.resource, 

462# base=self.base, 

463# rel=self.rel, 

464# location=self.location) 

465# 

466# cmd = addDataStreamPtfCmd({'rel':self.rel, 

467# 'mimetype':self.mimetype, 

468# 'location':self.location, 

469# 'text':self.text, 

470# 'seq':self.seq 

471# }) 

472# cmd.set_base(self.base) 

473# cmd.set_resource(self.resource) 

474# 

475 

476# if datastream_qs.count() > 0: 

477# cmd.set_object_to_be_deleted(datastream_qs.get()) 

478# cmd.undo() 

479# cmd.set_params({'location': self.new_location}) 

480# cmd.do() 

481 

482 

483##################################################################### 

484# 

485# addResourceCountPtfCmd: adds/remove a ResourceCount 

486# 

487# A ResourceCount is a generic count element. 

488# Exemple: page count, table count, image count... 

489# 

490# params: 'name', 'value', 'seq' 

491# 

492# Needs a Resource object 

493# 

494# Exception raised: 

495# - ValueError if the init params are empty 

496# - exceptions.ResourceExists during do if the ResourceCount already exists 

497# - exceptions.ResourceDoesNotExist during undo if the ResourceCount does not exist 

498# - RuntimeError during undo if resources are still published 

499# 

500###################################################################### 

501class addResourceCountPtfCmd(addPtfCmd): 

502 def __init__(self, params=None): 

503 super().__init__(params) 

504 

505 self.cmd = addResourceCountDatabaseCmd(params) 

506 

507 def set_resource(self, resource): 

508 self.cmd.set_resource(resource) 

509 

510 

511##################################################################### 

512# 

513# addBibItemPtfCmd: adds/remove a BibItem 

514# 

515# No verification is done to check if a BibItem already exists 

516# Rationale: BibItems are only added in a loop within an article. 

517# The check is actually the existence of the article. 

518# 

519# Exception raised: 

520# - ValueError if the init params are empty 

521# - exceptions.ResourceDoesNotExist during undo if the BibItem does not exist 

522# - RuntimeError during undo if resources are still published 

523# 

524###################################################################### 

525class addBibItemPtfCmd(addPtfCmd): 

526 def __init__(self, params=None): 

527 super().__init__(params) 

528 

529 self.cmd = addBibItemDatabaseCmd(params) 

530 

531 def set_resource(self, resource): 

532 self.cmd.set_resource(resource) 

533 

534 

535##################################################################### 

536# 

537# addBibItemIdPtfCmd: adds/remove a BibItemId 

538# 

539# No verification is done to check if a BibItemId already exists 

540# Rationale: BibItems are only added inside an article/book 

541# The check is actually the existence of the resource. 

542# 

543# Exception raised: 

544# - ValueError if the init params are empty 

545# - exceptions.ResourceDoesNotExist during undo if the BibItemId does not exist 

546# - RuntimeError during undo if resources are still published 

547# 

548###################################################################### 

549class addBibItemIdPtfCmd(addPtfCmd): 

550 def __init__(self, params=None): 

551 super().__init__(params) 

552 

553 self.cmd = addBibItemIdDatabaseCmd(params) 

554 

555 def set_bibitem(self, bibitem): 

556 self.cmd.set_bibitem(bibitem) 

557 

558 

559##################################################################### 

560# 

561# addFrontMatterPtfCmd: adds/remove a FrontMatter 

562# 

563# No verification is done to check if a FrontMatter already exists 

564# Rationale: FrontMatters are only added inside a book 

565# The check is actually the existence of the book. 

566# 

567# Exception raised: 

568# - ValueError if the init params are empty 

569# - exceptions.ResourceDoesNotExist during undo if the FrontMatter does not exist 

570# - RuntimeError during undo if resources are still published 

571# 

572###################################################################### 

573class addFrontMatterPtfCmd(addPtfCmd): 

574 def __init__(self, params=None): 

575 super().__init__(params) 

576 

577 self.cmd = addFrontMatterDatabaseCmd(params) 

578 

579 def set_resource(self, resource): 

580 self.cmd.set_resource(resource) 

581 

582 

583##################################################################### 

584# 

585# addRelationshipPtfCmd: adds/remove a Relationship 

586# 

587# Relationship relates 2 resources (ex: articles) with a relation. ex "follows", "followed-by" 

588# 

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

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

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

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

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

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

595# with A "followed-by" B, A is the object the B the subject because "followed-by" is a RelationName.right attribute 

596# A Relationship relates 2 resources with a RelationName 

597# 

598# Exception raised: 

599# - ValueError if the init params are empty 

600# - exceptions.ResourceExists during do if the Relationship already exists 

601# - exceptions.ResourceDoesNotExist during undo if the Relationship does not exist 

602# - RuntimeError during undo if resources are still published 

603# 

604###################################################################### 

605class addRelationshipPtfCmd(addPtfCmd): 

606 def __init__(self, params=None): 

607 super().__init__(params) 

608 

609 self.cmd = addRelationshipDatabaseCmd(params) 

610 

611 def set_subject_resource(self, resource): 

612 self.cmd.set_subject_resource(resource) 

613 

614 def set_object_resource(self, resource): 

615 self.cmd.set_object_resource(resource) 

616 

617 def set_relationname(self, relationname): 

618 self.cmd.set_relationname(relationname) 

619 

620 

621##################################################################### 

622# 

623# addPublisherPtfCmd: adds/remove a publisher 

624# params: 'name', 'location' 

625# 

626# Exception raised: 

627# - ValueError if the init params are empty 

628# - exceptions.ResourceExists during do if the Publisher already exists 

629# - exceptions.ResourceDoesNotExist during undo if the Publisher does not exist 

630# 

631###################################################################### 

632class addPublisherPtfCmd(addPtfCmd): 

633 def __init__(self, params=None): 

634 super().__init__(params) 

635 

636 self.cmd = addPublisherDatabaseCmd(params) 

637 # self.sub_cmd = addPublisherSolrCmd(params) 

638 

639 

640##################################################################### 

641# 

642# addResourcePtfCmd: adds/remove folder for a Resource 

643# 

644# 

645# is responsible of creation/deletion of resource folders 

646###################################################################### 

647class addResourcePtfCmd(addPtfCmd): 

648 def post_do(self, obj): 

649 super().post_do(obj) 

650 # if self.from_folder and self.to_folder: 

651 # # binary_files (PDF, images, TeX, Attach) are copied in the addRelatedObjectPtfCmd::pre_do 

652 # # We only need to copy the html images 

653 # resolver.copy_html_images(obj, from_folder=self.from_folder, to_folder=self.to_folder) 

654 

655 def pre_undo(self): 

656 super().pre_undo() 

657 if self.object_to_be_deleted and self.to_folder: 

658 resolver.delete_object_folder( 

659 object_folder=self.object_to_be_deleted.get_relative_folder(), 

660 to_folder=self.to_folder, 

661 ) 

662 

663 

664##################################################################### 

665# 

666# addCollectionPtfCmd: adds/remove a journal 

667# a Collection needs a Provider object 

668# 

669# params: 'coltype', 'title_xml', 'wall', 

670# 'pid', 'sid', 

671# 'title_tex', 'title_html', 

672# 'other_ids' Ex. [ ('cedram-id','AFST'), ('issn', '0240-2963') ] 

673# 

674# Exception raised: 

675# - ValueError if the init params are empty 

676# - exceptions.ResourceExists during do if the Collection already exists 

677# - exceptions.ResourceDoesNotExist during undo if the Collection does not exist 

678# 

679###################################################################### 

680class addCollectionPtfCmd(addResourcePtfCmd): 

681 def __init__(self, params=None): 

682 super().__init__(params) 

683 

684 self.cmd = addCollectionDatabaseCmd(params) 

685 

686 # self.sub_cmd = addCollectionSolrCmd(params) 

687 

688 def set_provider(self, provider): 

689 self.cmd.set_provider(provider) 

690 

691 def set_parent(self, parent): 

692 self.cmd.set_parent(parent) 

693 

694 

695##################################################################### 

696# 

697# addContainerPtfCmd: adds/remove an issue 

698# a Container needs a Collection (journal, book-series) that needs a Provider object 

699# 

700# params: 'year', 'vseries', 'volume', 'number' 

701# 'doi','seq', 

702# 

703# (params common to Container/Article) 

704# 'title_xml', 'title_tex', 'title_html', 'lang', 

705# 'other_ids' Ex: [ ('cedram-id','AFST'), ('issn', '0240-2963') ] 

706# 'abstracts' Ex: [ { 'tag': tag, 'lang': lang, 'value': value } ] 

707# 'contributors' Ex: [ { 'first_name': 'John', "corresponding": True...}, ... ] 

708# 'kwd_groups' Ex1: [ { 'content_type': content_type, 'lang': lang, 'value': value } ] 

709# Ex2: # [ { 'content_type': content_type, 'lang': lang, 

710# 'kwds': [ value1, value2,... ] } ] 

711# 

712# Exception raised: 

713# - ValueError if the init params are empty 

714# - exceptions.ResourceExists during do if the issue already exists 

715# - exceptions.ResourceDoesNotExist during undo if the Container does not exist 

716# 

717###################################################################### 

718class addContainerPtfCmd(addResourcePtfCmd): 

719 def __init__(self, params=None): 

720 super().__init__(params) 

721 self.required_params.extend(["xobj"]) 

722 

723 self.cmd = addContainerDatabaseCmd(params) 

724 if hasattr(self, "xobj") and ( 

725 self.xobj.ctype.startswith("book") or self.xobj.ctype == "lecture-notes" 

726 ): 

727 self.sub_cmd = addContainerSolrCmd(params) 

728 

729 self.article_ids = [] 

730 

731 def add_collection(self, collection): 

732 self.cmd.add_collection(collection) 

733 if self.sub_cmd: 

734 self.sub_cmd.add_collection(collection) 

735 

736 def set_publisher(self, publisher): 

737 pass 

738 

739 # self.sub_cmd.publisher_id = publisher.id 

740 

741 def set_provider(self, provider): 

742 self.cmd.set_provider(provider) 

743 

744 def pre_undo(self): 

745 # To delete a container directly (cmd=addContainerPtfCmd({'pid':pid,'ctype':ctype}); cmd.undo() and 

746 # associated set) 

747 # you simply need to pass its pid AND ctype. 

748 # addContainerPtfCmd is then responsible to remove the issue and its articles from the system 

749 # Django automatically remove all objects related to the container (cascade) 

750 # But we need to manually remove the articles of the container from SolR 

751 # Store the article ids in pre_undo and delete the Solr articles in 

752 # internal_undo 

753 # 

754 # addResourcePtfCmd is responsible to remove articles binary files from the system 

755 

756 super().pre_undo() 

757 if self.object_to_be_deleted: 757 ↛ exitline 757 didn't return from function 'pre_undo', because the condition on line 757 was never false

758 for article in self.object_to_be_deleted.article_set.all(): 

759 self.article_ids.append(article.id) 

760 

761 # Exception to the Django cascade mecanism: Relationship. 

762 # A Relationship links 2 articles. 

763 # If an article is removed, Django automatically deletes the Relationship. 

764 # It's not good, we want the relationship to remain, but the article field set to None 

765 

766 qs = Relationship.objects.filter(resource=article) 

767 for r in qs: 

768 if r.related is None: 

769 r.delete() 

770 else: 

771 r.resource = None 

772 r.save() 

773 qs = Relationship.objects.filter(related=article) 

774 for r in qs: 

775 if r.resource is None: 

776 r.delete() 

777 else: 

778 r.related = None 

779 r.save() 

780 

781 def internal_undo(self): 

782 for id in self.article_ids: 

783 cmd = addArticleSolrCmd({"id": id, "solr_commit": False}) 

784 cmd.undo() 

785 

786 id = super().internal_undo() 

787 return id 

788 

789 def post_undo(self): 

790 super().post_undo() 

791 

792 Person.objects.clean() 

793 

794 

795##################################################################### 

796# 

797# addArticlePtfCmd: adds/remove an article 

798# an Article needs a Container that needs a Collection (Journal) that needs a Provider object 

799# 

800# params: fpage, lpage, doi, seq, atype (article type), page_range, elocation, article_number, talk_number 

801# 

802# pseq (parent seq) 

803# related_article ? 

804# 

805# (params common to Container/Article) 

806# 'title_xml', 'title_tex', 'title_html', 'lang', 

807# 'other_ids' Ex: [ ('cedram-id','AFST'), ('issn', '0240-2963') ] 

808# 'abstracts' Ex: [ { 'tag': tag, 'lang': lang, 'value': value } ] 

809# 'contributors' Ex: [ { 'first_name': 'John', "corresponding": True...}, ... ] 

810# 'kwd_groups' Ex1: [ { 'content_type': content_type, 'lang': lang, 'value': value } ] 

811# Ex2: # [ { 'content_type': content_type, 'lang': lang, 

812# 'kwds': [ value1, value2,... ] } ] 

813 

814 

815# 

816# Exception raised: 

817# - ValueError if the init params are empty 

818# - exceptions.ResourceExists during do if the article already exists 

819# - exceptions.ResourceDoesNotExist during undo if the Article does not exist 

820# 

821###################################################################### 

822class addArticlePtfCmd(addResourcePtfCmd): 

823 def __init__(self, params=None): 

824 super().__init__(params) 

825 self.cmd = addArticleDatabaseCmd(params) 

826 

827 # is_cr = False 

828 # if (hasattr(settings, 'SITE_NAME') and len(settings.SITE_NAME) == 6 and settings.SITE_NAME[ 

829 # 0:2] == "cr"): 

830 # is_cr = True 

831 # 

832 # to_appear = False 

833 # if (params is not None and 'xobj' in params and 

834 # hasattr(settings, 'ISSUE_TO_APPEAR_PID') and 

835 # params['xobj'].pid.find(settings.ISSUE_TO_APPEAR_PID) == 0): 

836 # to_appear = True 

837 # 

838 # # The articles to appear are not stored in the search engine. 

839 # if is_cr or not to_appear: 

840 self.sub_cmd = addArticleSolrCmd(params) 

841 

842 def set_container(self, container): 

843 self.cmd.set_container(container) 

844 if self.sub_cmd: 844 ↛ exitline 844 didn't return from function 'set_container', because the condition on line 844 was never false

845 self.sub_cmd.set_container(container) 

846 

847 def set_provider(self, provider): 

848 self.cmd.set_provider(provider) 

849 

850 def set_eprint(self, eprint): 

851 self.sub_cmd.set_eprint(eprint) 

852 

853 def set_source(self, source): 

854 self.sub_cmd.set_source(source) 

855 

856 def set_thesis(self, thesis): 

857 self.sub_cmd.set_thesis(thesis) 

858 

859 def add_collection(self, collection): 

860 self.cmd.set_collection(collection) 

861 

862 if self.sub_cmd: 862 ↛ exitline 862 didn't return from function 'add_collection', because the condition on line 862 was never false

863 self.sub_cmd.add_collection(collection) 

864 

865 def post_do(self, article): 

866 super().post_do(article) 

867 for xtrans_article, trans_article in zip( 867 ↛ 870line 867 didn't jump to line 870, because the loop on line 867 never started

868 self.xobj.translations, self.cmd.translated_articles 

869 ): 

870 solr_xtrans_article = copy.deepcopy(xtrans_article) 

871 solr_xtrans_article.trans_title_tex = self.xobj.title_tex 

872 solr_xtrans_article.trans_title_html = self.xobj.title_html 

873 if article.trans_lang == xtrans_article.lang: 

874 if article.trans_title_tex: 

875 solr_xtrans_article.title_tex = article.trans_title_tex 

876 solr_xtrans_article.title_html = article.trans_title_html 

877 for abstract in self.xobj.abstracts: 

878 if abstract["tag"] == "abstract" and abstract["lang"] == xtrans_article.lang: 

879 solr_xtrans_article.abstracts = [abstract] 

880 

881 sub_cmd = addArticleSolrCmd({"xobj": solr_xtrans_article}) 

882 sub_cmd.set_container(article.my_container) 

883 sub_cmd.add_collection(article.get_collection()) 

884 sub_cmd.db_obj = trans_article 

885 sub_cmd.id = trans_article.id 

886 sub_cmd.pid = trans_article.pid 

887 sub_cmd.do() 

888 # xtrans_article.doi = doi_sav 

889 

890 def pre_undo(self): 

891 super().pre_undo() 

892 

893 qs = Relationship.objects.filter(resource=self.object_to_be_deleted) 

894 for r in qs: 

895 if r.related is None: 

896 r.delete() 

897 else: 

898 r.resource = None 

899 r.save() 

900 qs = Relationship.objects.filter(related=self.object_to_be_deleted) 

901 for r in qs: 

902 if r.resource is None: 

903 r.delete() 

904 else: 

905 r.related = None 

906 r.save() 

907 

908 def internal_undo(self): 

909 if self.object_to_be_deleted: 909 ↛ 917line 909 didn't jump to line 917, because the condition on line 909 was never false

910 cmd = addArticleSolrCmd({"id": self.object_to_be_deleted.id, "solr_commit": False}) 

911 cmd.undo() 

912 

913 for trans_article in self.object_to_be_deleted.translations.all(): 913 ↛ 914line 913 didn't jump to line 914, because the loop on line 913 never started

914 cmd = addArticleSolrCmd({"id": trans_article.id, "solr_commit": False}) 

915 cmd.undo() 

916 

917 id = super().internal_undo() 

918 return id 

919 

920 

921##################################################################### 

922# 

923# addBookPartPtfCmd: adds/remove a book part 

924# 

925# TODO an Article is used to store a book part in the database. Why not use a JournalArticle in SolR ? 

926# 

927# params: 'year', 'fpage', 'lpage' 

928# 'colid' Ex: [ 1,2 ] 

929# 

930# (params common to Book) 

931# 'title_xml', 'title_tex', 'title_html', 'lang', 

932# 'other_ids' Ex: [ ('cedram-id','AFST'), ('issn', '0240-2963') ] 

933# 'ext_ids' Ex: [ ('zbl-item-id','0216.23901'), ('mr-item-id', '289322') ] 

934# 'abstracts' Ex: [ { 'tag': tag, 'lang': lang, 'value': value } ] 

935# 'contributors' Ex: [ { 'first_name': 'John', "corresponding": True...}, ... ] 

936# 'kwd_groups' Ex1: [ { 'content_type': content_type, 'lang': lang, 'value': value } ] 

937# Ex2: # [ { 'content_type': content_type, 'lang': lang, 

938# 'kwds': [ value1, value2,... ] } ] 

939# 'bibitem' Ex: ["1) Name - Title", "2) Name2 - Title2" ] 

940# 

941# Exception raised: 

942# - ValueError if the init params are empty 

943# - exceptions.ResourceExists during do if the book part already exists 

944# - exceptions.ResourceDoesNotExist during undo if the BookPart does not exist 

945# 

946###################################################################### 

947class addBookPartPtfCmd(addResourcePtfCmd): 

948 def __init__(self, params=None): 

949 super().__init__(params) 

950 

951 self.cmd = addArticleDatabaseCmd(params) 

952 self.sub_cmd = addBookPartSolrCmd(params) 

953 

954 def set_container(self, container): 

955 self.cmd.set_container(container) 

956 self.sub_cmd.set_container(container) 

957 # 'colid' is used to find the collection of a book part 

958 # TODO store the book_id as well ? 

959 

960 def add_collection(self, collection): 

961 # manage collection MBK : only index the other collection 

962 if collection.pid != "MBK": 962 ↛ exitline 962 didn't return from function 'add_collection', because the condition on line 962 was never false

963 self.sub_cmd.add_collection(collection) 

964 

965 

966########################################################################## 

967########################################################################## 

968# 

969# Update Commands 

970# 

971########################################################################## 

972########################################################################## 

973 

974 

975##################################################################### 

976# 

977# updateCollectionPtfCmd: updates a journal 

978# a Collection needs a Provider object 

979# 

980# params: 'coltype', 'title_xml', 'wall', 

981# 'pid', 'sid', 

982# 'title_tex', 'title_html', 

983# 'other_ids' Ex. [ ('cedram-id','AFST'), ('issn', '0240-2963') ] 

984# 

985# Exception raised: 

986# - ValueError if the init params are empty 

987# - exceptions.ResourceDoesNotExist during do if the Collection does not exist 

988# 

989###################################################################### 

990class updateCollectionPtfCmd(addPtfCmd): 

991 def __init__(self, params=None): 

992 super().__init__(params) 

993 

994 self.cmd = updateCollectionDatabaseCmd(params) 

995 # self.sub_cmd = addCollectionSolrCmd(params) 

996 

997 def set_provider(self, provider): 

998 self.cmd.set_provider(provider) 

999 

1000 def set_publisher(self, publisher): 

1001 self.sub_cmd.set_publisher(publisher) 

1002 

1003 

1004##################################################################### 

1005# 

1006# updateResourceIdPtfCmd: upates an existing ResourceId 

1007# params: 'id_type': 'doi', 'issn', 'e-issn' 

1008# 'id_value' 

1009# 

1010# Needs a Resource object (required) 

1011# 

1012# Exception raised: 

1013# - ValueError if the init params are empty 

1014# - exceptions.ResourceDoesNotExist during do if the ResourceId does not exist 

1015# 

1016###################################################################### 

1017class updateResourceIdPtfCmd(addPtfCmd): 

1018 def __init__(self, params={}): 

1019 super().__init__(params) 

1020 

1021 self.cmd = updateResourceIdDatabaseCmd(params) 

1022 

1023 def set_resource(self, resource): 

1024 self.cmd.set_resource(resource) 

1025 

1026 

1027##################################################################### 

1028# 

1029# updateExtLinkPtfCmd: upates an existing ExtLink 

1030# params: 'rel': 'website' or 'small_icon' 

1031# 'mimetype', 'location', 'metadata', 'seq' 

1032# 

1033# Needs a Resource object (required) 

1034# TODO: update the related XmlBase object 

1035# 

1036# Exception raised: 

1037# - ValueError if the init params are empty 

1038# - exceptions.ResourceDoesNotExist during do if the ExtLink does not exist 

1039# 

1040###################################################################### 

1041class updateExtLinkPtfCmd(addPtfCmd): 

1042 def __init__(self, params=None): 

1043 super().__init__(params) 

1044 

1045 self.cmd = updateExtLinkDatabaseCmd(params) 

1046 

1047 def set_resource(self, resource): 

1048 self.cmd.set_resource(resource) 

1049 

1050 

1051class importExtraDataPtfCmd(baseCmd): 

1052 """ 

1053 Restore additional info, such as checked/false_positive attributes on extid/bibitemid 

1054 

1055 results: articles are updated 

1056 """ 

1057 

1058 def __init__(self, params=None): 

1059 self.pid = None 

1060 self.import_folder = None 

1061 

1062 super().__init__(params) 

1063 

1064 self.required_params.extend(["pid", "import_folder"]) 

1065 

1066 def copy_file(self, filename, resource, from_pid): 

1067 # on recupere potentiellement l'image positionnée via ptf-tools pour la resource 

1068 # il faut renommer l'image car la logique est d'avoir une image avec pour nom pid.EXT 

1069 # En cas de déplacement d'online first, from_pid peut être différent de resource.pid 

1070 basename = os.path.basename(filename) 

1071 extension = os.path.splitext(filename)[1] 

1072 if (f"{from_pid}{extension}") == basename: 

1073 new_basename = f"{resource.pid}{extension}" 

1074 from_path = os.path.join(self.import_folder, filename) 

1075 new_filename = os.path.join(resource.get_relative_folder(), new_basename) 

1076 to_path = os.path.join(settings.MERSENNE_TEST_DATA_FOLDER, new_filename) 

1077 resolver.copy_file(from_path, to_path) 

1078 filename = new_filename 

1079 return filename 

1080 

1081 def import_article_extra_info(self, article, article_data): 

1082 if article_data is None: 1082 ↛ 1083line 1082 didn't jump to line 1083, because the condition on line 1082 was never true

1083 return 

1084 

1085 for extid_data in article_data["extids"]: 

1086 model_helpers.add_or_update_extid( 

1087 article, 

1088 extid_data["type"], 

1089 extid_data["value"], 

1090 extid_data["checked"], 

1091 extid_data["false_positive"], 

1092 False, 

1093 ) 

1094 

1095 for ref_data in article_data["references"]: 

1096 bibitem = model_helpers.get_bibitem_by_seq(article, ref_data["seq"]) 

1097 if bibitem: 1097 ↛ 1095line 1097 didn't jump to line 1095, because the condition on line 1097 was never false

1098 for bibid_data in ref_data["bibids"]: 

1099 model_helpers.add_or_update_bibitemid( 

1100 bibitem, 

1101 bibid_data["type"], 

1102 bibid_data["value"], 

1103 bibid_data["checked"], 

1104 bibid_data["false_positive"], 

1105 False, 

1106 ) 

1107 

1108 if "date_published" in article_data: 1108 ↛ 1109line 1108 didn't jump to line 1109, because the condition on line 1108 was never true

1109 date = model_helpers.parse_date_str(article_data["date_published"]) 

1110 article.date_published = date 

1111 article.save() 

1112 

1113 if "date_pre_published" in article_data: 1113 ↛ 1114line 1113 didn't jump to line 1114, because the condition on line 1113 was never true

1114 date = model_helpers.parse_date_str(article_data["date_pre_published"]) 

1115 article.date_pre_published = date 

1116 article.save() 

1117 

1118 if "date_online_first" in article_data: 

1119 date = model_helpers.parse_date_str(article_data["date_online_first"]) 

1120 article.date_online_first = date 

1121 article.save() 

1122 

1123 if "deployed_date" in article_data: 1123 ↛ 1124line 1123 didn't jump to line 1124, because the condition on line 1123 was never true

1124 date = model_helpers.parse_date_str(article_data["deployed_date"]) 

1125 ptfSite = model_helpers.get_site_mersenne(article.get_top_collection().pid) 

1126 article.deploy(ptfSite, date) 

1127 

1128 if "icon" in article_data: 

1129 file = self.copy_file(article_data["icon"], article, article_data["pid"]) 

1130 cmd = addorUpdateExtLinkPtfCmd({"rel": "icon", "location": file}) 

1131 cmd.set_resource(article) 

1132 cmd.do() 

1133 

1134 if "show_body" in article_data: 

1135 article.show_body = article_data["show_body"] 

1136 article.save() 

1137 

1138 if "do_not_publish" in article_data: 

1139 article.do_not_publish = article_data["do_not_publish"] 

1140 article.save() 

1141 

1142 if ( 1142 ↛ 1147line 1142 didn't jump to line 1147

1143 settings.SITE_NAME == "ptf_tools" 

1144 and "doi_status" in article_data 

1145 and article_data["doi_status"] != 0 

1146 ): 

1147 if ( 

1148 article.pid == article_data["pid"] 

1149 ): # on restreint aux articles qui ne changent pas de pid 

1150 from mersenne_tools.models import DOIBatch 

1151 from ptf_tools.doi import get_doibatch 

1152 

1153 doib = get_doibatch(article) 

1154 if not doib: 

1155 doibatch = DOIBatch( 

1156 resource=article, 

1157 status=article_data["doi_status"], 

1158 id=article_data["doibatch_id"], 

1159 xml=article_data["doibatch_xml"], 

1160 log="-- import --", 

1161 ) 

1162 doibatch.save() 

1163 

1164 restore_obj_not_in_metadata(article) 

1165 

1166 def import_container_extra_info(self, container, data): 

1167 ptfSite = model_helpers.get_site_mersenne(container.my_collection.pid) 

1168 

1169 if "deployed_date" in data: 

1170 date = model_helpers.parse_date_str(data["deployed_date"]) 

1171 container.deploy(ptfSite, date) 

1172 

1173 if "icon" in data: 1173 ↛ 1174line 1173 didn't jump to line 1174, because the condition on line 1173 was never true

1174 file = self.copy_file(data["icon"], container, container.pid) 

1175 cmd = addorUpdateExtLinkPtfCmd({"rel": "icon", "location": file}) 

1176 cmd.set_resource(container) 

1177 cmd.do() 

1178 

1179 for article_data in data["articles"]: 

1180 article = None 

1181 if article_data["doi"]: 1181 ↛ 1183line 1181 didn't jump to line 1183, because the condition on line 1181 was never false

1182 article = model_helpers.get_article_by_doi(article_data["doi"]) 

1183 if not article: 

1184 article = model_helpers.get_article(article_data["pid"]) 

1185 if article: 

1186 self.import_article_extra_info(article, article_data) 

1187 

1188 def internal_do(self): 

1189 super().internal_do() 

1190 article_pid = None 

1191 

1192 resource = model_helpers.get_resource(self.pid) 

1193 if not resource: 1193 ↛ 1194line 1193 didn't jump to line 1194, because the condition on line 1193 was never true

1194 raise exceptions.ResourceDoesNotExist(f"Resource {self.pid} does not exist") 

1195 

1196 obj = resource.cast() 

1197 

1198 classname = obj.classname.lower() 

1199 if classname == "article": 1199 ↛ 1200line 1199 didn't jump to line 1200, because the condition on line 1199 was never true

1200 article_pid = self.pid 

1201 

1202 container = obj.get_container() 

1203 container_pid = container.pid 

1204 collection = container.my_collection 

1205 

1206 file = resolver.get_archive_filename( 

1207 self.import_folder, collection.pid, container_pid, "json", article_pid=article_pid 

1208 ) 

1209 

1210 if os.path.exists(file): 

1211 with open(file, encoding="utf-8") as f: 

1212 data = json.load(f) 

1213 

1214 fct_name = f"import_{classname}_extra_info" 

1215 ftor = getattr(self, fct_name, None) 

1216 if callable(ftor): 1216 ↛ exitline 1216 didn't return from function 'internal_do', because the condition on line 1216 was never false

1217 ftor(obj, data) 

1218 

1219 

1220##################################################################### 

1221# 

1222# addDjvuPtfCmd: add a Djvu to an existing issue 

1223# Used when an issue is sent to Numdam by ptf-tools 

1224# 

1225# Needs a Resource object (required) 

1226# 

1227# Exception raised: 

1228# - ValueError if the init params are empty 

1229# 

1230###################################################################### 

1231class addDjvuPtfCmd(baseCmd): 

1232 def __init__(self, params={}): 

1233 self.resource = None 

1234 

1235 super().__init__(params) 

1236 

1237 self.required_params.extend(["resource"]) 

1238 

1239 def set_resource(self, resource): 

1240 self.resource = resource 

1241 

1242 def convert_pdf_to_djvu(self): 

1243 obj = self.resource.cast() 

1244 qs = obj.datastream_set.filter(mimetype="image/x.djvu") 

1245 if qs.count() == 0: 

1246 qs = obj.datastream_set.filter(mimetype="application/pdf") 

1247 if qs.count() != 0: 

1248 datastream = qs.first() 

1249 location = datastream.location.replace(".pdf", ".djvu") 

1250 

1251 folder = settings.MERSENNE_PROD_DATA_FOLDER 

1252 if ( 

1253 hasattr(settings, "NUMDAM_COLLECTIONS") 

1254 and obj.my_container.my_collection.pid in settings.NUMDAM_COLLECTIONS 

1255 ): 

1256 folder = settings.MERSENNE_TEST_DATA_FOLDER 

1257 

1258 # Create the djvu in MERSENNE_PROD_DATA_FOLDER (used to archive) 

1259 djvu_filename = os.path.join(folder, location) 

1260 

1261 if not os.path.isfile(djvu_filename): 

1262 pdf_filename = os.path.join(folder, datastream.location) 

1263 if not os.path.isfile(pdf_filename): 

1264 pdf_filename = os.path.join( 

1265 settings.MERSENNE_TEST_DATA_FOLDER, datastream.location 

1266 ) 

1267 

1268 cmd_str = "pdf2djvu --quiet --dpi 600 --output {} {}".format( 

1269 djvu_filename, pdf_filename 

1270 ) 

1271 

1272 subprocess.check_output(cmd_str, shell=True) 

1273 

1274 # Copy the new djvu in MERSENNE_TEST_DATA_FOLDER (used to deploy) 

1275 djvu_filename_in_test = os.path.join( 

1276 settings.MERSENNE_TEST_DATA_FOLDER, location 

1277 ) 

1278 if djvu_filename_in_test != djvu_filename: 

1279 resolver.copy_file(djvu_filename, djvu_filename_in_test) 

1280 

1281 cmd = addDataStreamDatabaseCmd( 

1282 { 

1283 "rel": "full-text", 

1284 "mimetype": "image/x.djvu", 

1285 "location": location, 

1286 "text": "Full (DJVU)", 

1287 "seq": qs.count() + 1, 

1288 } 

1289 ) 

1290 cmd.set_resource(obj) 

1291 cmd.do() 

1292 

1293 if ( 

1294 not hasattr(obj, "ctype") 

1295 or (hasattr(obj, "ctype") and obj.ctype.startswith("book")) 

1296 or (hasattr(obj, "ctype") and obj.ctype == "lecture-notes") 

1297 ): 

1298 self.update_solr(obj, location) 

1299 

1300 def update_solr(self, resource, djvu_location): 

1301 params = {"djvu": djvu_location} 

1302 cmd = updateResourceSolrCmd(params) 

1303 cmd.set_resource(resource) 

1304 cmd.do() 

1305 

1306 # Convert the PDF in Djvu 

1307 def internal_do(self): 

1308 super().internal_do() 

1309 

1310 self.convert_pdf_to_djvu() 

1311 

1312 

1313##################################################################### 

1314# 

1315# addorUpdateContribsPtfCmd: update the list of contributions of a Resource 

1316# Remove the existing contributions and replace with the new ones 

1317# 

1318# Needs a Resource object (required) 

1319# 

1320# Exception raised: 

1321# - ValueError if the init params are empty 

1322# 

1323###################################################################### 

1324class addorUpdateContribsPtfCmd(baseCmd): 

1325 def __init__(self, params={}): 

1326 self.resource = None 

1327 self.contributors = [] 

1328 

1329 super().__init__(params) 

1330 

1331 self.required_params.extend(["resource"]) 

1332 

1333 def set_resource(self, resource): 

1334 self.resource = resource 

1335 

1336 def internal_do(self): 

1337 super().internal_do() 

1338 

1339 self.resource.contributions.all().delete() 

1340 add_contributors(self.contributors, self.resource) 

1341 

1342 cmd = updateResourceSolrCmd({"contributors": self.contributors}) 

1343 cmd.set_resource(self.resource) 

1344 cmd.do() 

1345 

1346 

1347##################################################################### 

1348# 

1349# addorUpdateKwdsPtfCmd: update the keywords of a Resource 

1350# Remove the existing keywords and replace with the new ones 

1351# 

1352# Needs a Resource object (required) 

1353# 

1354# TODO: pass a list of kwd_groups instead of separate kwd_<lang> values 

1355# 

1356# Exception raised: 

1357# - ValueError if the init params are empty 

1358# 

1359###################################################################### 

1360# class addorUpdateKwdsPtfCmd(baseCmd): 

1361# def __init__(self, params={}): 

1362# self.resource = None 

1363# self.kwds_fr = None 

1364# self.kwds_en = None 

1365# self.kwd_uns_fr = None 

1366# self.kwd_uns_en = None 

1367# 

1368# super(addorUpdateKwdsPtfCmd, self).__init__(params) 

1369# 

1370# self.required_params.extend(['resource']) 

1371# 

1372# def set_resource(self, resource): 

1373# self.resource = resource 

1374# 

1375# def addOrUpdateKwds(self, kwd_uns, kwds, lang): 

1376# kwds_groups_qs = self.resource.kwdgroup_set.filter(content_type='', lang=lang) 

1377# if kwds_groups_qs.exists(): 

1378# # There is already a kwd_group. 

1379# group = kwds_groups_qs.first() 

1380# # First, delete all its kwds 

1381# group.kwd_set.all().delete() 

1382# group.delete() 

1383# 

1384# new_kwd_group = None 

1385# 

1386# if kwd_uns or kwds: 

1387# new_kwd_group = {'content_type': '', 'lang': lang, 'kwds': kwds} 

1388# if kwd_uns: 

1389# new_kwd_group['value_tex'] = kwd_uns 

1390# new_kwd_group['value_html'] = kwd_uns 

1391# new_kwd_group[ 

1392# 'value_xml'] = '<unstructured-kwd-group xml:space="preserve">' + kwd_uns + '</unstructured-kwd-group>' 

1393# else: 

1394# # Build value_tex and value_html for display and SolR 

1395# # But do not create value_xml: it is done by the XML export templates (OAI, PubMed) 

1396# value = '' 

1397# for kwd in kwds: 

1398# if value: 

1399# value += ', ' 

1400# value += kwd 

1401# new_kwd_group['value_tex'] = value 

1402# new_kwd_group['value_html'] = value 

1403# 

1404# addKwdGroup(new_kwd_group, self.resource) 

1405# 

1406# return new_kwd_group 

1407# 

1408# def internal_do(self): 

1409# super(addorUpdateKwdsPtfCmd, self).internal_do() 

1410# 

1411# kwd_groups = [] 

1412# kwd_group = self.addOrUpdateKwds(self.kwd_uns_fr, self.kwds_fr, 'fr') 

1413# if kwd_group: 

1414# kwd_groups.append(kwd_group) 

1415# 

1416# kwd_group = self.addOrUpdateKwds(self.kwd_uns_en, self.kwds_en, 'en') 

1417# if kwd_group: 

1418# kwd_groups.append(kwd_group) 

1419# 

1420# cmd = updateResourceSolrCmd({'kwd_groups': kwd_groups}) 

1421# cmd.set_resource(self.resource) 

1422# cmd.do() 

1423 

1424 

1425##################################################################### 

1426# 

1427# addorUpdateExtLinkPtfCmd: update the list of contribs of a Resource 

1428# Remove the existing contribs and replace with the new ones 

1429# 

1430# Needs a Resource object (required) 

1431# 

1432# Exception raised: 

1433# - ValueError if the init params are empty 

1434# 

1435# TODO : les images de couv - les icon - sont stockées ici mais du coup ne profite pas DIRECTEMENT de la logique de copie de fichiers des RelatedObjects 

1436###################################################################### 

1437class addorUpdateExtLinkPtfCmd(baseCmd): 

1438 def __init__(self, params={}): 

1439 self.resource = None 

1440 self.location = None 

1441 self.rel = None 

1442 self.mimetype = "" 

1443 

1444 super().__init__(params) 

1445 

1446 self.required_params.extend(["resource", "rel"]) 

1447 

1448 def set_resource(self, resource): 

1449 self.resource = resource 

1450 

1451 def internal_do(self): 

1452 super().internal_do() 

1453 

1454 extlink_qs = ExtLink.objects.filter(resource=self.resource, rel=self.rel) 

1455 

1456 if extlink_qs.exists(): 1456 ↛ 1457line 1456 didn't jump to line 1457, because the condition on line 1456 was never true

1457 extlink = extlink_qs.first() 

1458 if self.location: 

1459 extlink.location = self.location 

1460 extlink.save() 

1461 else: 

1462 extlink.delete() 

1463 elif self.location: 1463 ↛ exitline 1463 didn't return from function 'internal_do', because the condition on line 1463 was never false

1464 params = { 

1465 "rel": self.rel, 

1466 "mimetype": self.mimetype, 

1467 "location": self.location, 

1468 "seq": 1, 

1469 "metadata": "", 

1470 } 

1471 

1472 cmd = addExtLinkPtfCmd(params) 

1473 cmd.set_resource(self.resource) 

1474 cmd.do() 

1475 

1476 

1477##################################################################### 

1478# 

1479# updateArticlePtfCmd: update an existing Article 

1480# Olivier: 12/06/2020. This function needs major refactoring. 

1481# If page_count is not provided, it gets deleted. 

1482# There should be a way to pass only attributes to edit 

1483# 

1484# Needs an Article object (required) 

1485# 

1486# Exception raised: 

1487# - ValueError if the init params are empty 

1488# 

1489###################################################################### 

1490class updateArticlePtfCmd(baseCmd): 

1491 def __init__(self, params={}): 

1492 self.article = None 

1493 self.title_xml = None 

1494 self.title_html = None 

1495 self.title_tex = None 

1496 self.authors = None 

1497 self.page_count = None 

1498 self.use_page_count = True 

1499 self.icon_location = None 

1500 self.body = None 

1501 self.body_tex = None 

1502 self.body_html = None 

1503 self.body_xml = None 

1504 # self.use_kwds = None 

1505 # self.kwds_fr = None 

1506 # self.kwds_en = None 

1507 # self.kwd_uns_fr = None 

1508 # self.kwd_uns_en = None 

1509 

1510 super().__init__(params) 

1511 

1512 self.required_params.extend(["article"]) 

1513 

1514 def set_article(self, article): 

1515 self.article = article 

1516 

1517 def internal_do(self): 

1518 super().internal_do() 

1519 

1520 container = self.article.my_container 

1521 collection = container.my_collection 

1522 

1523 if self.title_tex and self.title_html and self.title_xml: 1523 ↛ 1524line 1523 didn't jump to line 1524, because the condition on line 1523 was never true

1524 self.article.title_tex = self.title_tex 

1525 self.article.title_html = self.title_html 

1526 self.article.title_xml = self.title_xml 

1527 self.article.save() 

1528 

1529 if self.body_xml or self.body_html or self.body_tex: 1529 ↛ 1536line 1529 didn't jump to line 1536, because the condition on line 1529 was never false

1530 self.article.body_tex = self.body_tex 

1531 self.article.body_html = self.body_html 

1532 self.article.body_xml = self.body_xml 

1533 self.article.save() 

1534 

1535 # Authors 

1536 if self.authors: 1536 ↛ 1537line 1536 didn't jump to line 1537, because the condition on line 1536 was never true

1537 params = {"contributors": self.authors} 

1538 cmd = addorUpdateContribsPtfCmd(params) 

1539 cmd.set_resource(self.article) 

1540 cmd.do() 

1541 

1542 # Page count 

1543 if self.use_page_count: 1543 ↛ 1544line 1543 didn't jump to line 1544, because the condition on line 1543 was never true

1544 qs = self.article.resourcecount_set.filter(name="page-count") 

1545 if qs.exists(): 

1546 qs.first().delete() 

1547 if self.page_count: 

1548 seq = self.article.resourcecount_set.count() + 1 

1549 params = {"name": "page-count", "value": self.page_count, "seq": seq} 

1550 cmd = addResourceCountPtfCmd(params) 

1551 cmd.set_resource(self.article) 

1552 cmd.do() 

1553 

1554 # Add a DataStream for the PDF 

1555 qs = self.article.datastream_set.filter(mimetype="application/pdf") 

1556 if not qs.exists(): 1556 ↛ 1557line 1556 didn't jump to line 1557, because the condition on line 1556 was never true

1557 folder = resolver.get_relative_folder(collection.pid, container.pid, self.article.pid) 

1558 location = os.path.join(folder, self.article.pid + ".pdf") 

1559 params = { 

1560 "rel": "full-text", 

1561 "mimetype": "application/pdf", 

1562 "location": location, 

1563 "seq": self.article.datastream_set.count() + 1, 

1564 "text": "Full (PDF)", 

1565 } 

1566 cmd = addDataStreamPtfCmd(params) 

1567 cmd.set_resource(self.article) 

1568 cmd.do() 

1569 

1570 # image ajoutée via ptf-tools pour un article 

1571 if self.icon_location: 1571 ↛ 1572line 1571 didn't jump to line 1572, because the condition on line 1571 was never true

1572 params = {"rel": "icon", "location": self.icon_location} 

1573 cmd = addorUpdateExtLinkPtfCmd(params) 

1574 cmd.set_resource(self.article) 

1575 cmd.do() 

1576 

1577 # Kwds 

1578 # if self.use_kwds: 

1579 # params = {'kwds_en': self.kwds_en, 'kwds_fr': self.kwds_fr, 

1580 # 'kwd_uns_en': self.kwd_uns_en, 'kwd_uns_fr': self.kwd_uns_fr} 

1581 # cmd = addorUpdateKwdsPtfCmd(params) 

1582 # cmd.set_resource(self.article) 

1583 # cmd.do() 

1584 

1585 if self.body or self.title_tex: 1585 ↛ 1586line 1585 didn't jump to line 1586, because the condition on line 1585 was never true

1586 params = {} 

1587 if self.body: 

1588 params["body"] = self.body 

1589 if self.title_tex and self.title_html: 

1590 params["title_tex"] = self.title_tex 

1591 params["title_html"] = self.title_html 

1592 

1593 cmd = updateResourceSolrCmd(params) 

1594 cmd.set_resource(self.article) 

1595 cmd.do() 

1596 

1597 

1598##################################################################### 

1599# 

1600# updateContainerPtfCmd: update an existing Container 

1601# 

1602# Needs a Container object (required) 

1603# 

1604# Exception raised: 

1605# - ValueError if the init params are empty 

1606# 

1607###################################################################### 

1608class updateContainerPtfCmd(baseCmd): 

1609 def __init__(self, params={}): 

1610 self.resource = None 

1611 self.icon_location = None 

1612 

1613 super().__init__(params) 

1614 

1615 self.required_params.extend(["resource"]) 

1616 

1617 def set_resource(self, resource): 

1618 self.resource = resource 

1619 

1620 def internal_do(self): 

1621 super().internal_do() 

1622 

1623 params = {"rel": "icon", "location": self.icon_location} 

1624 cmd = addorUpdateExtLinkPtfCmd(params) 

1625 cmd.set_resource(self.resource) 

1626 cmd.do() 

1627 

1628 

1629########################################################################## 

1630########################################################################## 

1631# 

1632# Export Commands 

1633# 

1634########################################################################## 

1635########################################################################## 

1636 

1637 

1638class exportExtraDataPtfCmd(baseCmd): 

1639 """ 

1640 Exports additional info, such as checked/false_positive attributes on extid/bibitemid 

1641 

1642 force_pid is only used when the volume to be published becomes published 

1643 Ex: AIF_0_0 becomes AIF_2018. We want to backup data in AIF_2018.json 

1644 so that additional are restored when AIF_2018.xml is read 

1645 

1646 export_all export all extids. 

1647 If you want to archive, export_all should be False (checked extids are in the XML) 

1648 If you want to store in a temp file (updateXML), then export_all should be True 

1649 to preserve new extids found by the matching an not present in the XML 

1650 

1651 if with_binary_files = True, copy in tempFolder, binary files set by ptf-tools ( extlink(rel='icon') ) 

1652 

1653 results: a json file on disk 

1654 """ 

1655 

1656 def __init__(self, params=None): 

1657 self.pid = None 

1658 self.export_folder = None 

1659 self.force_pid = None 

1660 self.export_all = True 

1661 self.with_binary_files = True 

1662 # Deleting an article deletes its GraphicalAbstract (if any). We need to preserve the GraphicalAbstract 

1663 self.do_backup_obj_not_in_metadata = False 

1664 

1665 super().__init__(params) 

1666 

1667 self.required_params.extend(["pid", "export_folder"]) 

1668 

1669 def get_article_extra_info(self, article, export_all=False): 

1670 data = None 

1671 

1672 extids_data = [] 

1673 for extid in article.extid_set.all(): 

1674 extid_data = {} 

1675 if export_all or not extid.checked or extid.false_positive: 1675 ↛ 1680line 1675 didn't jump to line 1680, because the condition on line 1675 was never false

1676 extid_data["type"] = extid.id_type 

1677 extid_data["value"] = extid.id_value 

1678 extid_data["checked"] = extid.checked 

1679 extid_data["false_positive"] = extid.false_positive 

1680 if extid_data: 1680 ↛ 1673line 1680 didn't jump to line 1673, because the condition on line 1680 was never false

1681 extids_data.append(extid_data) 

1682 

1683 references_data = [] 

1684 for bib in article.bibitem_set.all(): 

1685 bibids_data = [] 

1686 for bibid in bib.bibitemid_set.all(): 

1687 bibid_data = {} 

1688 if export_all or not bibid.checked or bibid.false_positive: 

1689 bibid_data["type"] = bibid.id_type 

1690 bibid_data["value"] = bibid.id_value 

1691 bibid_data["checked"] = bibid.checked 

1692 bibid_data["false_positive"] = bibid.false_positive 

1693 

1694 if bibid_data: 

1695 bibids_data.append(bibid_data) 

1696 

1697 if bibids_data: 

1698 references_data.append({"seq": bib.sequence, "bibids": bibids_data}) 

1699 

1700 icon = None 

1701 

1702 for extlink in article.extlink_set.filter(rel="icon"): 

1703 if self.with_binary_files is True: 

1704 icon = extlink.location 

1705 

1706 # copy des imgs associées via ptf-tools 

1707 from_path = os.path.join(settings.RESOURCES_ROOT, extlink.location) 

1708 to_path = os.path.join(self.export_folder, extlink.location) 

1709 resolver.create_folder(os.path.dirname(to_path)) 

1710 resolver.copy_file(from_path, to_path) 

1711 

1712 if ( 

1713 extids_data 

1714 or references_data 

1715 or article.date_published 

1716 or article.date_online_first 

1717 or icon 

1718 ): 

1719 data = { 

1720 "pid": article.pid, 

1721 "doi": article.doi, 

1722 "extids": extids_data, 

1723 "references": references_data, 

1724 } 

1725 

1726 if export_all and icon: 

1727 data["icon"] = icon 

1728 

1729 if export_all and article.date_published: 1729 ↛ 1730line 1729 didn't jump to line 1730, because the condition on line 1729 was never true

1730 data["date_published"] = article.date_published 

1731 

1732 if export_all and article.date_pre_published: 1732 ↛ 1733line 1732 didn't jump to line 1733, because the condition on line 1732 was never true

1733 data["date_pre_published"] = article.date_pre_published 

1734 

1735 if export_all and article.date_online_first: 

1736 data["date_online_first"] = article.date_online_first 

1737 

1738 if export_all: 

1739 data["show_body"] = article.show_body 

1740 data["do_not_publish"] = article.do_not_publish 

1741 

1742 if ( 1742 ↛ 1747line 1742 didn't jump to line 1747

1743 export_all 

1744 and settings.SITE_NAME == "ptf_tools" 

1745 and not ((len(sys.argv) > 1 and sys.argv[1] == "test") or "pytest" in sys.modules) 

1746 ): 

1747 try: 

1748 data["doi_status"] = article.doibatch.status 

1749 data["doibatch_id"] = article.doibatch.id 

1750 data["doibatch_xml"] = article.doibatch.xml 

1751 except ObjectDoesNotExist: 

1752 data["doi_status"] = 0 

1753 

1754 if self.do_backup_obj_not_in_metadata: 

1755 backup_obj_not_in_metadata(article) 

1756 

1757 return data 

1758 

1759 def get_container_extra_info(self, container, export_all=False): 

1760 result = {"pid": container.pid} 

1761 

1762 collection = container.my_collection 

1763 ptfSite = model_helpers.get_site_mersenne(collection.pid) 

1764 

1765 if ptfSite and not self.force_pid: 

1766 # si self.force_pid on est dans le cas où on passe un article de 0_0_0 vers issue final et dans ce cas là on ne conserve pas la deployed_date du 0_0_0 

1767 deployed_date = container.deployed_date(ptfSite) 

1768 if deployed_date: 

1769 result["deployed_date"] = deployed_date 

1770 

1771 icon = None 

1772 for extlink in container.extlink_set.filter(rel="icon"): 1772 ↛ 1773line 1772 didn't jump to line 1773, because the loop on line 1772 never started

1773 icon = extlink.location 

1774 if self.with_binary_files is True: 

1775 # copy des imgs associées via ptf-tools 

1776 from_path = os.path.join(settings.MERSENNE_TEST_DATA_FOLDER, extlink.location) 

1777 to_path = os.path.join(self.export_folder, extlink.location) 

1778 resolver.create_folder(os.path.dirname(to_path)) 

1779 resolver.copy_file(from_path, to_path) 

1780 

1781 if export_all and icon: 1781 ↛ 1782line 1781 didn't jump to line 1782, because the condition on line 1781 was never true

1782 result["icon"] = icon 

1783 

1784 articles_data = [] 

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

1786 data = self.get_article_extra_info(article, export_all) 

1787 if data: 

1788 articles_data.append(data) 

1789 

1790 result["articles"] = articles_data 

1791 

1792 return result 

1793 

1794 def internal_do(self): 

1795 super().internal_do() 

1796 article_pid = None 

1797 

1798 resource = model_helpers.get_resource(self.pid) 

1799 if not resource: 1799 ↛ 1800line 1799 didn't jump to line 1800, because the condition on line 1799 was never true

1800 raise exceptions.ResourceDoesNotExist(f"Resource {self.pid} does not exist") 

1801 

1802 obj = resource.cast() 

1803 

1804 classname = obj.classname.lower() 

1805 if classname == "article": 1805 ↛ 1806line 1805 didn't jump to line 1806, because the condition on line 1805 was never true

1806 article_pid = self.pid 

1807 

1808 container = obj.get_container() 

1809 container_pid = self.force_pid if self.force_pid else container.pid 

1810 collection = container.get_top_collection() 

1811 

1812 fct_name = f"get_{classname}_extra_info" 

1813 ftor = getattr(self, fct_name, None) 

1814 data = ftor(obj, self.export_all) 

1815 

1816 file = resolver.get_archive_filename( 

1817 self.export_folder, 

1818 collection.pid, 

1819 container_pid, 

1820 "json", 

1821 do_create_folder=True, 

1822 article_pid=article_pid, 

1823 ) 

1824 

1825 with open(file, "w", encoding="utf-8") as f: 

1826 json.dump(data, f, default=myconverter) 

1827 

1828 

1829class exportPtfCmd(baseCmd): 

1830 """ 

1831 Generate the Article/Container/Collection XML 

1832 

1833 Write on disk if export_folder is given as parameter 

1834 Copy binary files if with_binary_files = True 

1835 results: unicode string 

1836 """ 

1837 

1838 def __init__(self, params=None): 

1839 self.pid = None 

1840 self.with_body = True 

1841 self.with_djvu = True # No djvu in Mersenne web sites 

1842 self.article_standalone = False # PCJ editor sets to True 

1843 

1844 # Export le json des données internes (false_ids...). 

1845 # Il faut alors un self.export_folder 

1846 self.with_internal_data = False 

1847 

1848 # Copie des fichiers binaires (PDF...) and l'export_folder 

1849 self.with_binary_files = False 

1850 

1851 self.export_folder = None 

1852 

1853 # Permet de contrôler le répertoire source des fichiers binaires 

1854 self.binary_files_folder = settings.RESOURCES_ROOT 

1855 

1856 # Ajouter des métadonnées internes (deployed_date) ou non dans le XML 

1857 self.for_archive = False 

1858 

1859 # Permet au final d'exclure les articles marqués comme étant à ne pas publier 

1860 self.export_to_website = False 

1861 

1862 # Le XML dans l'onglet export n'a pas toutes les métadonnées 

1863 self.full_xml = True 

1864 

1865 super().__init__(params) 

1866 

1867 self.required_params.extend(["pid"]) 

1868 

1869 def internal_do(self): 

1870 super().internal_do() 

1871 

1872 resource = model_helpers.get_resource(self.pid) 

1873 if not resource: 1873 ↛ 1874line 1873 didn't jump to line 1874, because the condition on line 1873 was never true

1874 raise exceptions.ResourceDoesNotExist(f"Resource {self.pid} does not exist") 

1875 

1876 obj = resource.cast() 

1877 

1878 # export Book ? need a visitor ? see oai_helpers 

1879 if obj.classname == "Article": 

1880 template_name = "oai/common-article_eudml-article2.xml" 

1881 item_name = "article" 

1882 elif obj.classname == "Container": 

1883 if obj.ctype == "issue": 1883 ↛ 1887line 1883 didn't jump to line 1887, because the condition on line 1883 was never false

1884 template_name = "oai/common-issue_eudml-article2.xml" 

1885 item_name = "container" 

1886 else: 

1887 template_name = "oai/book_bits.xml" 

1888 item_name = "book" 

1889 elif obj.classname == "Collection": 1889 ↛ 1893line 1889 didn't jump to line 1893, because the condition on line 1889 was never false

1890 template_name = "collection.xml" 

1891 item_name = "collection" 

1892 else: 

1893 raise ValueError("Only articles, containers or collections can be exported") 

1894 

1895 if self.export_folder and self.with_internal_data and obj.classname == "Container": 

1896 params = { 

1897 "pid": self.pid, 

1898 "export_folder": self.export_folder, 

1899 "with_binary_files": self.with_binary_files, 

1900 } 

1901 exportExtraDataPtfCmd(params).do() 

1902 

1903 p = model_helpers.get_provider("mathdoc-id") 

1904 for_export = not self.for_archive 

1905 safetext_xml_body = render_to_string( 

1906 template_name, 

1907 { 

1908 item_name: obj, 

1909 "no_headers": True, 

1910 "provider": p.name, 

1911 "with_body": self.with_body, 

1912 "with_djvu": self.with_djvu, 

1913 "for_disk": True, 

1914 "for_export": for_export, 

1915 "full_xml": self.full_xml, 

1916 "export_to_website": self.export_to_website, 

1917 "article_standalone": self.article_standalone, 

1918 }, 

1919 ) 

1920 xml_body = str(safetext_xml_body) 

1921 if not self.full_xml: 1921 ↛ 1922line 1921 didn't jump to line 1922, because the condition on line 1921 was never true

1922 parser = etree.XMLParser( 

1923 huge_tree=True, 

1924 recover=True, 

1925 remove_blank_text=False, 

1926 remove_comments=True, 

1927 resolve_entities=True, 

1928 ) 

1929 tree = etree.fromstring(xml_body.encode("utf-8"), parser=parser) 

1930 xml_body = etree.tostring(tree, pretty_print=True).decode("utf-8") 

1931 

1932 if self.export_folder: 

1933 if obj.classname == "Collection": 

1934 # Export of a collection XML: we don't attempt to write in the top collection 

1935 file = resolver.get_archive_filename( 

1936 self.export_folder, obj.pid, None, "xml", True 

1937 ) 

1938 with open(file, "w", encoding="utf-8") as f: 

1939 f.write(xml_body) 

1940 

1941 if self.with_binary_files: 1941 ↛ 1974line 1941 didn't jump to line 1974, because the condition on line 1941 was never false

1942 resolver.copy_binary_files(obj, self.binary_files_folder, self.export_folder) 

1943 

1944 elif obj.classname == "Container": 1944 ↛ 1965line 1944 didn't jump to line 1965, because the condition on line 1944 was never false

1945 issue = obj 

1946 collection = obj.get_top_collection() 

1947 

1948 file = resolver.get_archive_filename( 

1949 self.export_folder, collection.pid, issue.pid, "xml", True 

1950 ) 

1951 

1952 with open(file, "w", encoding="utf-8") as f: 

1953 f.write(xml_body) 

1954 

1955 if self.with_binary_files: 

1956 resolver.copy_binary_files(issue, self.binary_files_folder, self.export_folder) 

1957 

1958 qs = issue.article_set.all() 

1959 if self.for_archive: 1959 ↛ 1961line 1959 didn't jump to line 1961, because the condition on line 1959 was never false

1960 qs = qs.exclude(do_not_publish=True) 

1961 for article in qs: 

1962 resolver.copy_binary_files( 

1963 article, self.binary_files_folder, self.export_folder 

1964 ) 

1965 elif obj.classname == "Article": 

1966 collection = obj.get_top_collection() 

1967 file = resolver.get_archive_filename( 

1968 self.export_folder, collection.pid, None, "xml", True 

1969 ) 

1970 

1971 with open(file, "w", encoding="utf-8") as f: 

1972 f.write(xml_body) 

1973 

1974 return xml_body 

1975 

1976 

1977class publishResourcePtfCmd(addPtfCmd): 

1978 """ 

1979 Publish a container <=> Create a pub-date for all articles/book-parts of the container 

1980 Publish an article <=> Create a pub-date 

1981 """ 

1982 

1983 def __init__(self, params=None): 

1984 self.params = params 

1985 super().__init__(params) 

1986 

1987 def set_resource(self, resource): 

1988 obj = resource.cast() 

1989 if obj.classname.find("Article") > -1: 1989 ↛ 1990line 1989 didn't jump to line 1990, because the condition on line 1989 was never true

1990 self.cmd = publishArticleDatabaseCmd(self.params) 

1991 self.cmd.set_article(obj) 

1992 else: 

1993 self.cmd = publishContainerDatabaseCmd(self.params) 

1994 self.cmd.set_container(obj) 

1995 

1996 

1997def get_or_create_publisher(name): 

1998 publisher = model_helpers.get_publisher(name) 

1999 if publisher is None: 

2000 publisher = PublisherData() 

2001 publisher.name = name 

2002 publisher = addPublisherPtfCmd({"xobj": publisher}).do() 

2003 return publisher