Coverage for apps/kwai-api/src/kwai_api/v1/news/presenters.py: 92%

38 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2024-01-01 00:00 +0000

1"""Module that defines presenters for the portal/news endpoint.""" 

2 

3from typing import Self 

4 

5from kwai_bc_identity.users.user import UserEntity 

6from kwai_bc_portal.domain.application import ApplicationEntity 

7from kwai_bc_portal.domain.news_item import NewsItemEntity 

8from kwai_core.domain.exceptions import NotAllowedException 

9from kwai_core.domain.presenter import AsyncPresenter, IterableResult, Presenter 

10from kwai_core.json_api import JsonApiPresenter, Meta, Relationship, ResourceMeta 

11 

12from kwai_api.converter import MarkdownConverter 

13from kwai_api.schemas.resources import ApplicationResourceIdentifier 

14from kwai_api.v1.news.schemas import ( 

15 NewsApplicationAttributes, 

16 NewsApplicationDocument, 

17 NewsApplicationResource, 

18 NewsItemAttributes, 

19 NewsItemDocument, 

20 NewsItemRelationships, 

21 NewsItemResource, 

22 NewsItemsDocument, 

23 NewsItemText, 

24) 

25 

26 

27class JsonApiNewsApplicationPresenter( 

28 JsonApiPresenter[NewsApplicationDocument], Presenter[ApplicationEntity] 

29): 

30 """A presenter that transforms a news application into a JSON:API document.""" 

31 

32 def present(self, news_application: ApplicationEntity) -> Self: 

33 self._document = NewsApplicationDocument( 

34 data=NewsApplicationResource( 

35 id=str(news_application.id), 

36 attributes=NewsApplicationAttributes( 

37 name=news_application.name, title=news_application.title 

38 ), 

39 ) 

40 ) 

41 return self 

42 

43 

44class JsonApiNewsItemPresenter( 

45 JsonApiPresenter[NewsItemDocument], Presenter[NewsItemEntity] 

46): 

47 """A presenter that transform a news item entity into a JSON:API document.""" 

48 

49 def __init__(self, user: UserEntity | None): 

50 super().__init__() 

51 self._user = user 

52 

53 def present(self, news_item: NewsItemEntity) -> Self: 

54 # Only a know user is allowed to see disabled news. 

55 if not self._user and not news_item.enabled: 

56 raise NotAllowedException( 

57 f"Not allowed to view the news item {news_item.id}" 

58 ) 

59 

60 application_document = ( 

61 JsonApiNewsApplicationPresenter() 

62 .present(news_item.application) 

63 .get_document() 

64 ) 

65 self._document = NewsItemDocument( 

66 data=NewsItemResource( 

67 id=str(news_item.id), 

68 meta=ResourceMeta( 

69 created_at=str(news_item.traceable_time.created_at), 

70 updated_at=str(news_item.traceable_time.updated_at), 

71 ), 

72 attributes=NewsItemAttributes( 

73 priority=news_item.promotion.priority, 

74 publish_date=str(news_item.period.start_date), 

75 end_date=str(news_item.period.end_date), 

76 enabled=news_item.enabled, 

77 remark=news_item.remark or "", 

78 promotion_end_date=str(news_item.promotion.end_date), 

79 texts=[ 

80 NewsItemText( 

81 locale=text.locale.value, 

82 format=text.format.value, 

83 title=text.title, 

84 summary=MarkdownConverter().convert(text.summary), 

85 content=MarkdownConverter().convert(text.content) 

86 if text.content 

87 else None, 

88 original_summary=text.summary, 

89 original_content=text.content, 

90 ) 

91 for text in news_item.texts 

92 ], 

93 ), 

94 relationships=NewsItemRelationships( 

95 application=Relationship[ApplicationResourceIdentifier]( 

96 data=ApplicationResourceIdentifier( 

97 id=str(news_item.application.id) 

98 ) 

99 ) 

100 ), 

101 ), 

102 included={application_document.data}, 

103 ) 

104 return self 

105 

106 

107class JsonApiNewsItemsPresenter( 

108 JsonApiPresenter[NewsItemsDocument], AsyncPresenter[IterableResult[NewsItemEntity]] 

109): 

110 """A presenter that transfer an iterable list of news items into a JSON:API document.""" 

111 

112 def __init__(self, user: UserEntity | None): 

113 super().__init__() 

114 self._user = user 

115 

116 async def present(self, result: IterableResult[NewsItemEntity]) -> Self: 

117 self._document = NewsItemsDocument( 

118 meta=Meta(count=result.count, offset=result.offset, limit=result.limit), 

119 data=[], 

120 ) 

121 async for news_item in result.iterator: 

122 try: 

123 news_item_document = ( 

124 JsonApiNewsItemPresenter(self._user) 

125 .present(news_item) 

126 .get_document() 

127 ) 

128 self._document.data.append(news_item_document.data) 

129 self._document.included |= news_item_document.included 

130 except NotAllowedException: 

131 pass 

132 

133 return self