Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1from settings import REASON_CATEGORIES 

2from flask import current_app 

3from flask_jwt_extended import get_jwt_claims 

4from sqlalchemy import func, text, select, and_ 

5from sqlalchemy.sql.expression import null 

6 

7from src import db, settings 

8from src.utils import pagination_resp, internal_err_resp, message, Paginator, err_resp 

9from src.model import ApplicationModel, UserModel, GenreModel, ContentType, ContentModel, RecommendedContentModel, RecommendedContentForGroupModel, MetaUserContentModel, BadRecommendationContentModel, ApplicationAdditionalModel 

10from src.schemas import ApplicationBase, GenreBase, MetaUserContentBase, ApplicationExtra, ApplicationAdditionalBase 

11 

12 

13class ApplicationService: 

14 @staticmethod 

15 def search_application_data(search_term, page, connected_user_uuid): 

16 """ Search application data by name """ 

17 if not (UserModel.query.filter_by(uuid=connected_user_uuid).first()): 

18 return err_resp("User not found!", 404) 

19 applications, total_pages = Paginator.get_from( 

20 ApplicationModel.query.filter(ApplicationModel.name.ilike(search_term+"%")).union( 

21 ApplicationModel.query.filter(ApplicationModel.name.ilike("%"+search_term+"%"))), 

22 page, 

23 ) 

24 

25 try: 

26 application_data = ApplicationBase.loads(applications) 

27 

28 return pagination_resp( 

29 message="Application data sent", 

30 content=application_data, 

31 page=page, 

32 total_pages=total_pages 

33 ) 

34 

35 except Exception as error: 

36 current_app.logger.error(error) 

37 return internal_err_resp() 

38 

39 @staticmethod 

40 def get_popular_applications(page, connected_user_uuid): 

41 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()): 

42 return err_resp("User not found!", 404) 

43 

44 # NOTE IMDB measure of popularity does not seem to be relevant for this media. 

45 applications, total_pages = Paginator.get_from( 

46 ApplicationModel.query.join(ApplicationModel.content, aliased=True).order_by( 

47 ContentModel.rating_count.desc().nullslast(), 

48 ContentModel.rating.desc().nullslast(), 

49 ), 

50 page, 

51 ) 

52 

53 try: 

54 application_data = ApplicationBase.loads(applications) 

55 

56 return pagination_resp( 

57 message="Most popular application data sent", 

58 content=application_data, 

59 page=page, 

60 total_pages=total_pages 

61 ) 

62 

63 except Exception as error: 

64 current_app.logger.error(error) 

65 return internal_err_resp() 

66 

67 @staticmethod 

68 def get_recommended_applications_for_user(page, connected_user_uuid, reco_engine): 

69 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()): 

70 return err_resp("User not found!", 404) 

71 

72 filters = [RecommendedContentModel.user_id == user.user_id] 

73 if reco_engine is not None: 

74 filters.append(RecommendedContentModel.engine == reco_engine) 

75 

76 applications, total_pages = Paginator.get_from( 

77 db.session.query(RecommendedContentModel, ApplicationModel) 

78 .join(ApplicationModel.content) 

79 .join(RecommendedContentModel, RecommendedContentModel.content_id == ContentModel.content_id) 

80 .filter( 

81 and_(*filters) 

82 ) 

83 .order_by( 

84 RecommendedContentModel.score.desc().nullslast(), 

85 ContentModel.rating_count.desc().nullslast(), 

86 ContentModel.rating.desc().nullslast(), 

87 ), 

88 page, 

89 ) 

90 

91 try: 

92 def c_load(row): 

93 app = ApplicationExtra.load(row[1]) 

94 app["reco_engine"] = row[0].engine 

95 app["reco_score"] = row[0].score 

96 return app 

97 

98 application_data = list(map(c_load, applications)) 

99 

100 return pagination_resp( 

101 message="Most popular application data sent", 

102 content=application_data, 

103 page=page, 

104 total_pages=total_pages 

105 ) 

106 

107 except Exception as error: 

108 current_app.logger.error(error) 

109 return internal_err_resp() 

110 

111 @staticmethod 

112 def get_recommended_applications_for_group(page, connected_user_uuid, reco_engine): 

113 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()): 

114 return err_resp("User not found!", 404) 

115 

116 # Query for recommendation from group 

117 groups_ids = [ 

118 *list(map(lambda x: x.group_id, user.groups)), 

119 *list(map(lambda x: x.group_id, user.owned_groups)) 

120 ] 

121 

122 filters = [RecommendedContentForGroupModel.group_id.in_(groups_ids)] 

123 if reco_engine is not None: 

124 filters.append(RecommendedContentModel.engine == reco_engine) 

125 

126 applications, total_pages = Paginator.get_from( 

127 db.session.query(RecommendedContentForGroupModel, ApplicationModel) 

128 .join(ApplicationModel.content) 

129 .join(RecommendedContentForGroupModel, RecommendedContentForGroupModel.content_id == ContentModel.content_id) 

130 .filter( 

131 and_(*filters) 

132 ) 

133 .order_by( 

134 RecommendedContentModel.score.desc().nullslast(), 

135 ContentModel.rating_count.desc().nullslast(), 

136 ContentModel.rating.desc().nullslast(), 

137 ), 

138 page, 

139 ) 

140 

141 try: 

142 def c_load(row): 

143 app = ApplicationExtra.load(row[1]) 

144 app["reco_engine"] = row[0].engine 

145 app["reco_score"] = row[0].score 

146 return app 

147 

148 application_data = list(map(c_load, applications)) 

149 

150 return pagination_resp( 

151 message="Most popular application data sent", 

152 content=application_data, 

153 page=page, 

154 total_pages=total_pages 

155 ) 

156 

157 except Exception as error: 

158 current_app.logger.error(error) 

159 return internal_err_resp() 

160 

161 @staticmethod 

162 def get_ordered_genres(connected_user_uuid): 

163 if not (UserModel.query.filter_by(uuid=connected_user_uuid).first()): 

164 return err_resp("User not found!", 404) 

165 

166 genres = GenreModel.query.filter_by( 

167 content_type=ContentType.APPLICATION).order_by(GenreModel.count.desc()).all() 

168 

169 # Check permissions 

170 permissions = get_jwt_claims()['permissions'] 

171 if "indicate_interest" not in permissions: 

172 return err_resp("Permission missing", 403) 

173 

174 try: 

175 genres_data = GenreBase.loads(genres) 

176 

177 resp = message(True, "Application genres data sent") 

178 resp["content"] = genres_data 

179 return resp, 200 

180 

181 except Exception as error: 

182 current_app.logger.error(error) 

183 return internal_err_resp() 

184 

185 @staticmethod 

186 def add_bad_recommendation(user_uuid, content_id, data): 

187 """ Add bad user recommendation """ 

188 if not (user := UserModel.query.filter_by(uuid=user_uuid).first()): 

189 return err_resp("User not found!", 404) 

190 

191 if not (app := ApplicationModel.query.filter_by(content_id=content_id).first()): 

192 return err_resp("Application not found!", 404) 

193 

194 try: 

195 for type, value in data.items(): 

196 if type in REASON_CATEGORIES['application']: 

197 for r in value: 

198 

199 new_bad_reco = BadRecommendationContentModel( 

200 user_id=user.user_id, 

201 content_id=app.content_id, 

202 reason_categorie=type, 

203 reason=r 

204 ) 

205 

206 db.session.add(new_bad_reco) 

207 db.session.flush() 

208 db.session.commit() 

209 

210 resp = message(True, "Bad recommendation has been registered.") 

211 return resp, 201 

212 

213 except Exception as error: 

214 current_app.logger.error(error) 

215 return internal_err_resp() 

216 

217 @staticmethod 

218 def add_additional_application(user_uuid, data): 

219 """ Add additional application""" 

220 if not (user := UserModel.query.filter_by(uuid=user_uuid).first()): 

221 return err_resp("User not found!", 404) 

222 

223 # Check permissions 

224 permissions = get_jwt_claims()['permissions'] 

225 if "add_content" not in permissions: 

226 return err_resp("Permission missing", 403) 

227 

228 try: 

229 

230 new_additional_application = ApplicationAdditionalModel( 

231 name=data['name'], 

232 ) 

233 

234 if 'size' in data: 

235 new_additional_application.size = data['size'] 

236 if 'installs' in data: 

237 new_additional_application.installs = data['installs'] 

238 if 'type' in data: 

239 new_additional_application.type = data['type'] 

240 if 'price' in data: 

241 new_additional_application.price = data['price'] 

242 if 'content_rating' in data: 

243 new_additional_application.content_rating = data['content_rating'] 

244 if 'last_updated' in data: 

245 new_additional_application.last_updated = data['last_updated'] 

246 if 'current_version' in data: 

247 new_additional_application.current_version = data['current_version'] 

248 if 'android_version' in data: 

249 new_additional_application.android_version = data['android_version'] 

250 if 'cover' in data: 

251 new_additional_application.cover = data['cover'] 

252 

253 for genre_id in data["genres"]: 

254 if (ge := GenreModel.query.filter_by(genre_id=genre_id).first()): 

255 new_additional_application.genres.append(ge) 

256 else: 

257 return err_resp("Genre %s not found!" % genre_id, 404) 

258 

259 db.session.add(new_additional_application) 

260 db.session.commit() 

261 

262 resp = message(True, "Application have been added to validation.") 

263 return resp, 201 

264 

265 except Exception as error: 

266 current_app.logger.error(error) 

267 return internal_err_resp() 

268 

269 @staticmethod 

270 def get_additional_application(connected_user_uuid, page): 

271 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()): 

272 return err_resp("User not found!", 404) 

273 

274 # Check permissions 

275 permissions = get_jwt_claims()['permissions'] 

276 if "add_content" not in permissions: 

277 return err_resp("Permission missing", 403) 

278 

279 applications, total_pages = Paginator.get_from( 

280 ApplicationAdditionalModel.query, 

281 page, 

282 ) 

283 

284 try: 

285 application_data = ApplicationAdditionalBase.loads(applications) 

286 

287 return pagination_resp( 

288 message="Additional application data sent", 

289 content=application_data, 

290 page=page, 

291 total_pages=total_pages 

292 ) 

293 

294 except Exception as error: 

295 current_app.logger.error(error) 

296 return internal_err_resp() 

297 

298 @staticmethod 

299 def validate_additional_application(connected_user_uuid, app_id): 

300 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()): 

301 return err_resp("User not found!", 404) 

302 

303 # Check permissions 

304 permissions = get_jwt_claims()['permissions'] 

305 if "validate_added_content" not in permissions: 

306 return err_resp("Permission missing", 403) 

307 

308 if not (app := ApplicationAdditionalModel.query.filter_by(app_id=app_id).first()): 

309 return err_resp("Additional application not found!", 404) 

310 

311 try: 

312 content = ContentModel(rating=None, genres=app.genres) 

313 db.session.add(content) 

314 db.session.flush() 

315 

316 new_application = ApplicationModel( 

317 name=app.name, 

318 size=app.size, 

319 installs=app.installs, 

320 type=app.type, 

321 price=app.price, 

322 content_rating=app.content_rating, 

323 last_updated=app.last_updated, 

324 current_version=app.current_version, 

325 android_version=app.android_version, 

326 cover=app.cover, 

327 content=content 

328 ) 

329 db.session.add(new_application) 

330 db.session.delete(app) 

331 

332 db.session.commit() 

333 

334 resp = message( 

335 True, "Additional application data successfully validated") 

336 return resp, 201 

337 

338 except Exception as error: 

339 current_app.logger.error(error) 

340 return internal_err_resp() 

341 

342 @staticmethod 

343 def decline_additional_application(connected_user_uuid, app_id): 

344 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()): 

345 return err_resp("User not found!", 404) 

346 

347 # Check permissions 

348 permissions = get_jwt_claims()['permissions'] 

349 if "delete_content" not in permissions: 

350 return err_resp("Permission missing", 403) 

351 

352 if not (app := ApplicationAdditionalModel.query.filter_by(app_id=app_id).first()): 

353 return err_resp("Additional application not found!", 404) 

354 

355 try: 

356 db.session.delete(app) 

357 db.session.commit() 

358 

359 resp = message(True, "Additional application successfully deleted") 

360 return resp, 201 

361 

362 except Exception as error: 

363 current_app.logger.error(error) 

364 return internal_err_resp()