Coverage for src/kwai/api/v1/news/endpoints/news.py: 85%

65 statements  

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

1"""Module that implements the endpoints for news.""" 

2 

3from fastapi import APIRouter, Depends, HTTPException, Query, status 

4from pydantic import BaseModel, Field 

5 

6from kwai.api.dependencies import create_database, get_current_user, get_optional_user 

7from kwai.api.schemas.news_item import NewsItemDocument 

8from kwai.core.domain.use_case import TextCommand 

9from kwai.core.domain.value_objects.owner import Owner 

10from kwai.core.json_api import Meta, PaginationModel 

11from kwai.modules.identity.users.user import UserEntity 

12from kwai.modules.portal.applications.application_db_repository import ( 

13 ApplicationDbRepository, 

14) 

15from kwai.modules.portal.create_news_item import CreateNewsItem, CreateNewsItemCommand 

16from kwai.modules.portal.delete_news_item import DeleteNewsItem, DeleteNewsItemCommand 

17from kwai.modules.portal.get_news_item import GetNewsItem, GetNewsItemCommand 

18from kwai.modules.portal.get_news_items import GetNewsItems, GetNewsItemsCommand 

19from kwai.modules.portal.news.news_item_db_repository import NewsItemDbRepository 

20from kwai.modules.portal.news.news_item_repository import NewsItemNotFoundException 

21from kwai.modules.portal.update_news_item import UpdateNewsItem, UpdateNewsItemCommand 

22 

23 

24router = APIRouter() 

25 

26 

27class NewsFilterModel(BaseModel): 

28 """Define the JSON:API filter for news.""" 

29 

30 enabled: bool = Field(Query(default=True, alias="filter[enabled]")) 

31 publish_year: int = Field(Query(default=0, alias="filter[publish_year]")) 

32 publish_month: int = Field(Query(default=0, alias="filter[publish_month]")) 

33 application: str | None = Field(Query(default=None, alias="filter[application]")) 

34 promoted: bool = Field(Query(default=False, alias="filter[promoted]")) 

35 author: str | None = Field(Query(default=None, alias="filter[author]")) 

36 

37 

38@router.get("/news_items") 

39async def get_news_items( 

40 pagination: PaginationModel = Depends(PaginationModel), 

41 news_filter: NewsFilterModel = Depends(NewsFilterModel), 

42 db=Depends(create_database), 

43 user: UserEntity | None = Depends(get_optional_user), 

44) -> NewsItemDocument: 

45 """Get news items.""" 

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

47 if user is None and not news_filter.enabled: 

48 raise HTTPException(status_code=status.HTTP_403_FORBIDDEN) 

49 

50 command = GetNewsItemsCommand( 

51 offset=pagination.offset or 0, 

52 limit=pagination.limit or 10, 

53 enabled=news_filter.enabled, 

54 publish_year=news_filter.publish_year, 

55 publish_month=news_filter.publish_month, 

56 application=news_filter.application, 

57 promoted=news_filter.promoted, 

58 author_uuid=news_filter.author, 

59 ) 

60 count, news_item_iterator = await GetNewsItems(NewsItemDbRepository(db)).execute( 

61 command 

62 ) 

63 

64 result = NewsItemDocument( 

65 meta=Meta(count=count, offset=command.offset, limit=command.limit), data=[] 

66 ) 

67 

68 async for news_item in news_item_iterator: 

69 news_document = NewsItemDocument.create(news_item) 

70 result.merge(news_document) 

71 

72 return result 

73 

74 

75@router.get("/news_items/{id}") 

76async def get_news_item( 

77 id: int, 

78 db=Depends(create_database), 

79 user: UserEntity | None = Depends(get_optional_user), 

80) -> NewsItemDocument: 

81 """Get a news item.""" 

82 command = GetNewsItemCommand(id=id) 

83 

84 try: 

85 news_item = await GetNewsItem(NewsItemDbRepository(db)).execute(command) 

86 except NewsItemNotFoundException as ex: 

87 raise HTTPException( 

88 status_code=status.HTTP_404_NOT_FOUND, detail=str(ex) 

89 ) from ex 

90 

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

92 if not user and not news_item.is_enabled: 

93 raise HTTPException(status_code=status.HTTP_403_FORBIDDEN) 

94 

95 return NewsItemDocument.create(news_item) 

96 

97 

98@router.post("/news_items", status_code=status.HTTP_201_CREATED) 

99async def create_news_item( 

100 resource: NewsItemDocument, 

101 db=Depends(create_database), 

102 user: UserEntity = Depends(get_current_user), 

103) -> NewsItemDocument: 

104 """Create a new news item.""" 

105 command = CreateNewsItemCommand( 

106 enabled=resource.data.attributes.enabled, 

107 texts=[ 

108 TextCommand( 

109 locale=text.locale, 

110 format=text.format, 

111 title=text.title, 

112 summary=text.original_summary, 

113 content=text.original_content, 

114 ) 

115 for text in resource.data.attributes.texts 

116 ], 

117 application=int(resource.data.relationships.application.data.id), 

118 publish_datetime=resource.data.attributes.publish_date, 

119 end_datetime=resource.data.attributes.end_date, 

120 promotion=resource.data.attributes.priority, 

121 promotion_end_datetime=resource.data.attributes.promotion_end_date, 

122 remark=resource.data.attributes.remark, 

123 ) 

124 news_item = await CreateNewsItem( 

125 NewsItemDbRepository(db), 

126 ApplicationDbRepository(db), 

127 Owner(id=user.id, uuid=user.uuid, name=user.name), 

128 ).execute(command) 

129 

130 return NewsItemDocument.create(news_item) 

131 

132 

133@router.patch( 

134 "/news_items/{id}", 

135 status_code=status.HTTP_200_OK, 

136 responses={status.HTTP_404_NOT_FOUND: {"description": "News item was not found."}}, 

137) 

138async def update_news_item( 

139 id: int, 

140 resource: NewsItemDocument, 

141 db=Depends(create_database), 

142 user: UserEntity = Depends(get_current_user), 

143) -> NewsItemDocument: 

144 """Update a new news item.""" 

145 command = UpdateNewsItemCommand( 

146 id=id, 

147 enabled=resource.data.attributes.enabled, 

148 texts=[ 

149 TextCommand( 

150 locale=text.locale, 

151 format=text.format, 

152 title=text.title, 

153 summary=text.original_summary, 

154 content=text.original_content, 

155 ) 

156 for text in resource.data.attributes.texts 

157 ], 

158 application=int(resource.data.relationships.application.data.id), 

159 publish_datetime=resource.data.attributes.publish_date, 

160 end_datetime=resource.data.attributes.end_date, 

161 promotion=resource.data.attributes.priority, 

162 promotion_end_datetime=resource.data.attributes.promotion_end_date, 

163 remark=resource.data.attributes.remark, 

164 ) 

165 try: 

166 news_item = await UpdateNewsItem( 

167 NewsItemDbRepository(db), 

168 ApplicationDbRepository(db), 

169 Owner(id=user.id, uuid=user.uuid, name=user.name), 

170 ).execute(command) 

171 except NewsItemNotFoundException as ex: 

172 raise HTTPException( 

173 status_code=status.HTTP_404_NOT_FOUND, detail=str(ex) 

174 ) from ex 

175 

176 return NewsItemDocument.create(news_item) 

177 

178 

179@router.delete( 

180 "/news_items/{id}", 

181 status_code=status.HTTP_200_OK, 

182 responses={status.HTTP_404_NOT_FOUND: {"description": "News Item was not found."}}, 

183) 

184async def delete_news_item( 

185 id: int, 

186 db=Depends(create_database), 

187 user: UserEntity = Depends(get_current_user), 

188): 

189 """Delete a new news item.""" 

190 command = DeleteNewsItemCommand(id=id) 

191 

192 try: 

193 await DeleteNewsItem(NewsItemDbRepository(db)).execute(command) 

194 except NewsItemNotFoundException as ex: 

195 raise HTTPException( 

196 status_code=status.HTTP_404_NOT_FOUND, detail=str(ex) 

197 ) from ex