Coverage for src / crawler / cmds / xml_cmds.py: 18%

79 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-07-15 13:33 +0000

1import logging 

2import math 

3 

4from django.core.exceptions import ObjectDoesNotExist 

5from django.db.models import Q 

6from ptf.cmds.xml_cmds import ( 

7 addOrUpdateBookXmlCmd, 

8 addOrUpdateContainerXmlCmd, 

9 addOrUpdateIssueXmlCmd, 

10 importEntireCollectionXmlCmd, 

11) 

12from ptf.models import Collection, CollectionMembership, Container 

13 

14from crawler.models import ContainerSource 

15 

16logger = logging.getLogger(__name__) 

17 

18 

19def add_source_to_container(source_domain: str, container: Container): 

20 from crawler import factory 

21 

22 source_cls = factory.get_crawler_class(source_domain) 

23 if not source_cls: 

24 logger.warning( 

25 f"Couldn't insert source {source_domain} to container : source not implemented" 

26 ) 

27 return False 

28 

29 source = source_cls.get_or_create_source() 

30 try: 

31 container.origin.delete() 

32 except ObjectDoesNotExist: 

33 pass 

34 ContainerSource.objects.get_or_create( 

35 source=source, 

36 container=container, 

37 ) 

38 logger.debug(f"Source {source_domain} successfully added to container {container.pid}") 

39 return True 

40 

41 

42def update_collection_years(pid): 

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

44 parent = collection.parent 

45 

46 if parent is None: 

47 qs = Container.objects.filter(my_collection__pid=pid, origin__disabled=False) 

48 collection_to_update = collection 

49 else: 

50 qs = Container.objects.filter( 

51 Q(my_collection__pid=pid) | Q(my_collection__parent__pid=pid), 

52 origin__disabled=False, 

53 ) 

54 collection_to_update = parent 

55 

56 qs_member = CollectionMembership.objects.filter(collection__pid=collection_to_update.pid) 

57 qs = [*(cm.container for cm in qs_member), *qs] 

58 

59 max_year = -math.inf 

60 min_year = math.inf 

61 for container in qs: 

62 fyear = container.fyear 

63 lyear = container.lyear or 0 

64 max_year = max(lyear, max_year) 

65 min_year = min(fyear, min_year) 

66 if min_year == math.inf: 

67 min_year = 0 

68 if max_year == -math.inf: 

69 max_year = 0 

70 

71 collection_to_update.fyear = int(min_year) 

72 collection_to_update.lyear = int(max_year) 

73 

74 collection_to_update.save(update_fields=["fyear", "lyear"]) 

75 

76 

77class addOrUpdateGDMLIssueXmlCmd(addOrUpdateIssueXmlCmd): 

78 def internal_do(self): 

79 obj = super().internal_do() 

80 if not obj or not self.xissue: 

81 logger.debug("Skipping source insertion : database object or xissue is not set") 

82 return obj 

83 

84 source_str = self.xissue.source 

85 if not source_str: 

86 if not self.add_link_to_source: 

87 logger.debug( 

88 "Skipping source insertion : add_link_to_source is false and xissue.source is None" 

89 ) 

90 return obj 

91 source_str = "NUMDAM" 

92 

93 add_source_to_container(source_str, obj) 

94 self.update_collection_years(self.xissue.journal.pid) 

95 return obj 

96 

97 

98class addOrUpdateGDMLBookXmlCmd(addOrUpdateBookXmlCmd): 

99 def internal_do(self): 

100 obj = super().internal_do() 

101 if not obj or not self.xbook: 

102 logger.debug( 

103 "Skipping source insertion : no database object was returned or xbook is None" 

104 ) 

105 return obj 

106 

107 source_str = self.xbook.source 

108 if not source_str: 

109 if not self.add_link_to_source: 

110 logger.debug( 

111 "Skipping source insertion : add_link_to_source is false and xbook.source is None" 

112 ) 

113 return obj 

114 source_str = "NUMDAM" 

115 

116 add_source_to_container(source_str, obj) 

117 return obj 

118 

119 

120class addOrUpdateGDMLContainerXmlCmd(addOrUpdateContainerXmlCmd): 

121 addOrUpdateIssueXmlCmdOverride = addOrUpdateGDMLIssueXmlCmd 

122 addOrUpdateBookXmlCmdOverride = addOrUpdateGDMLBookXmlCmd 

123 

124 

125importEntireCollectionXmlCmd.addOrUpdateContainerXmlCmdOverride = addOrUpdateGDMLContainerXmlCmd