Coverage for apps/kwai-api/src/kwai_api/v1/news/endpoints.py: 81%

79 statements  

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

1"""Module that implements the endpoints for /api/v1/news.""" 

2 

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

4from kwai_bc_identity.users.user import UserEntity 

5from kwai_bc_portal.applications.application_db_repository import ( 

6 ApplicationDbRepository, 

7) 

8from kwai_bc_portal.create_news_item import CreateNewsItem, CreateNewsItemCommand 

9from kwai_bc_portal.delete_news_item import DeleteNewsItem, DeleteNewsItemCommand 

10from kwai_bc_portal.get_news_item import GetNewsItem, GetNewsItemCommand 

11from kwai_bc_portal.get_news_items import GetNewsItems, GetNewsItemsCommand 

12from kwai_bc_portal.news.news_item_db_repository import NewsItemDbRepository 

13from kwai_bc_portal.news.news_item_repository import NewsItemNotFoundException 

14from kwai_bc_portal.update_news_item import UpdateNewsItem, UpdateNewsItemCommand 

15from kwai_core.domain.exceptions import NotAllowedException 

16from kwai_core.domain.use_case import TextCommand 

17from kwai_core.domain.value_objects.owner import Owner 

18from kwai_core.json_api import PaginationModel 

19from pydantic import BaseModel, Field 

20 

21from kwai_api.dependencies import create_database, get_current_user, get_optional_user 

22from kwai_api.v1.news.presenters import ( 

23 JsonApiNewsItemPresenter, 

24 JsonApiNewsItemsPresenter, 

25) 

26from kwai_api.v1.news.schemas import NewsItemDocument, NewsItemsDocument 

27 

28 

29router = APIRouter() 

30 

31 

32class NewsFilterModel(BaseModel): 

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

34 

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

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

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

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

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

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

41 

42 

43@router.get("/news_items") 

44async def get_news_items( 

45 pagination: PaginationModel = Depends(PaginationModel), 

46 news_filter: NewsFilterModel = Depends(NewsFilterModel), 

47 db=Depends(create_database), 

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

49) -> NewsItemsDocument: 

50 """Get news items.""" 

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

52 if user is None and not news_filter.enabled: 

53 raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED) 

54 

55 command = GetNewsItemsCommand( 

56 offset=pagination.offset or 0, 

57 limit=pagination.limit or 10, 

58 enabled=news_filter.enabled, 

59 publish_year=news_filter.publish_year, 

60 publish_month=news_filter.publish_month, 

61 application=news_filter.application, 

62 promoted=news_filter.promoted, 

63 author_uuid=news_filter.author, 

64 ) 

65 presenter = JsonApiNewsItemsPresenter(user) 

66 await GetNewsItems(NewsItemDbRepository(db), presenter).execute(command) 

67 return presenter.get_document() 

68 

69 

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

71async def get_news_item( 

72 id: int, 

73 db=Depends(create_database), 

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

75) -> NewsItemDocument: 

76 """Get a news item.""" 

77 command = GetNewsItemCommand(id=id) 

78 presenter = JsonApiNewsItemPresenter(user) 

79 try: 

80 await GetNewsItem(NewsItemDbRepository(db), presenter).execute(command) 

81 except NewsItemNotFoundException as ex: 

82 raise HTTPException( 

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

84 ) from ex 

85 except NotAllowedException as ex: 

86 raise HTTPException( 

87 status_code=status.HTTP_403_FORBIDDEN, detail=str(ex) 

88 ) from ex 

89 

90 return presenter.get_document() 

91 

92 

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

94async def create_news_item( 

95 resource: NewsItemDocument, 

96 db=Depends(create_database), 

97 user: UserEntity = Depends(get_current_user), 

98) -> NewsItemDocument: 

99 """Create a new news item.""" 

100 if resource.data.relationships is None: 

101 raise HTTPException( 

102 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, 

103 detail="Relationships data is missing.", 

104 ) 

105 if resource.data.relationships.application.data is None: 

106 raise HTTPException( 

107 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, 

108 detail="Relationship application data should not be None.", 

109 ) 

110 if resource.data.relationships.application.data.id is None: 

111 raise HTTPException( 

112 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, 

113 detail="Id of the application relationship should be set.", 

114 ) 

115 

116 command = CreateNewsItemCommand( 

117 enabled=resource.data.attributes.enabled, 

118 texts=[ 

119 TextCommand( 

120 locale=text.locale, 

121 format=text.format, 

122 title=text.title, 

123 summary=text.original_summary, 

124 content=text.original_content or "", 

125 ) 

126 for text in resource.data.attributes.texts 

127 ], 

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

129 publish_datetime=resource.data.attributes.publish_date, 

130 end_datetime=resource.data.attributes.end_date, 

131 promotion=resource.data.attributes.priority, 

132 promotion_end_datetime=resource.data.attributes.promotion_end_date, 

133 remark=resource.data.attributes.remark, 

134 ) 

135 presenter = JsonApiNewsItemPresenter(user) 

136 await CreateNewsItem( 

137 NewsItemDbRepository(db), 

138 ApplicationDbRepository(db), 

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

140 presenter, 

141 ).execute(command) 

142 

143 return presenter.get_document() 

144 

145 

146@router.patch( 

147 "/news_items/{id}", 

148 status_code=status.HTTP_200_OK, 

149 responses={ 

150 status.HTTP_404_NOT_FOUND: {"description": "News item was not found."}, 

151 status.HTTP_422_UNPROCESSABLE_ENTITY: {"description": "Invalid data passed."}, 

152 }, 

153) 

154async def update_news_item( 

155 id: int, 

156 resource: NewsItemDocument, 

157 db=Depends(create_database), 

158 user: UserEntity = Depends(get_current_user), 

159) -> NewsItemDocument: 

160 """Update a new news item.""" 

161 if resource.data.relationships is None: 

162 raise HTTPException( 

163 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, 

164 detail="Relationships data is missing.", 

165 ) 

166 if resource.data.relationships.application.data is None: 

167 raise HTTPException( 

168 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, 

169 detail="Relationship application data should not be None.", 

170 ) 

171 if resource.data.relationships.application.data.id is None: 

172 raise HTTPException( 

173 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, 

174 detail="Id of the application relationship should be set.", 

175 ) 

176 

177 command = UpdateNewsItemCommand( 

178 id=id, 

179 enabled=resource.data.attributes.enabled, 

180 texts=[ 

181 TextCommand( 

182 locale=text.locale, 

183 format=text.format, 

184 title=text.title, 

185 summary=text.original_summary, 

186 content=text.original_content or "", 

187 ) 

188 for text in resource.data.attributes.texts 

189 ], 

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

191 publish_datetime=resource.data.attributes.publish_date, 

192 end_datetime=resource.data.attributes.end_date, 

193 promotion=resource.data.attributes.priority, 

194 promotion_end_datetime=resource.data.attributes.promotion_end_date, 

195 remark=resource.data.attributes.remark, 

196 ) 

197 presenter = JsonApiNewsItemPresenter(user) 

198 try: 

199 await UpdateNewsItem( 

200 NewsItemDbRepository(db), 

201 ApplicationDbRepository(db), 

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

203 presenter, 

204 ).execute(command) 

205 except NewsItemNotFoundException as ex: 

206 raise HTTPException( 

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

208 ) from ex 

209 

210 return presenter.get_document() 

211 

212 

213@router.delete( 

214 "/news_items/{id}", 

215 status_code=status.HTTP_200_OK, 

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

217) 

218async def delete_news_item( 

219 id: int, 

220 db=Depends(create_database), 

221 user: UserEntity = Depends(get_current_user), 

222): 

223 """Delete a new news item.""" 

224 command = DeleteNewsItemCommand(id=id) 

225 

226 try: 

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

228 except NewsItemNotFoundException as ex: 

229 raise HTTPException( 

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

231 ) from ex