Coverage for src/service/book_service.py : 62%
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
7from src import db, settings
8from src.utils import pagination_resp, internal_err_resp, message, Paginator, err_resp
9from src.model import BookModel, UserModel, ContentModel, RecommendedContentModel, RecommendedContentForGroupModel, MetaUserContentModel, BadRecommendationContentModel, BookAdditionalModel
10from src.schemas import BookBase, BookExtra, MetaUserContentBase, BookAdditionalBase
13class BookService:
14 @staticmethod
15 def search_book_data(search_term, page, connected_user_uuid):
16 """ Search book data by title """
17 if not (UserModel.query.filter_by(uuid=connected_user_uuid).first()):
18 return err_resp("User not found!", 404)
19 books, total_pages = Paginator.get_from(
20 BookModel.query.filter(BookModel.title.ilike(search_term+"%")).union(
21 BookModel.query.filter(BookModel.title.ilike("%"+search_term+"%"))),
22 page,
23 )
25 try:
26 book_data = BookBase.loads(books)
28 return pagination_resp(
29 message="Book data sent",
30 content=book_data,
31 page=page,
32 total_pages=total_pages
33 )
35 except Exception as error:
36 current_app.logger.error(error)
37 return internal_err_resp()
39 @staticmethod
40 def get_popular_books(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)
44 books, total_pages = Paginator.get_from(
45 BookModel.query.join(BookModel.content, aliased=True).order_by(
46 ContentModel.popularity_score.desc().nullslast(),
47 ),
48 page,
49 )
51 try:
52 book_data = BookBase.loads(books)
54 return pagination_resp(
55 message="Most popular book data sent",
56 content=book_data,
57 page=page,
58 total_pages=total_pages
59 )
61 except Exception as error:
62 current_app.logger.error(error)
63 return internal_err_resp()
65 @staticmethod
66 def get_recommended_books_for_user(page, connected_user_uuid, reco_engine):
67 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()):
68 return err_resp("User not found!", 404)
70 filters = [RecommendedContentModel.user_id == user.user_id]
71 if reco_engine is not None:
72 filters.append(RecommendedContentModel.engine == reco_engine)
74 books, total_pages = Paginator.get_from(
75 db.session.query(RecommendedContentModel, BookModel)
76 .join(BookModel.content)
77 .join(RecommendedContentModel, RecommendedContentModel.content_id == ContentModel.content_id)
78 .filter(
79 and_(*filters)
80 )
81 .order_by(
82 RecommendedContentModel.score.desc().nullslast(),
83 ContentModel.popularity_score.desc().nullslast(),
84 ),
85 page,
86 )
88 try:
89 def c_load(row):
90 book = BookExtra.load(row[1])
91 book["reco_engine"] = row[0].engine
92 book["reco_score"] = row[0].score
93 return book
95 book_data = list(map(c_load, books))
97 return pagination_resp(
98 message="Most popular book data sent",
99 content=book_data,
100 page=page,
101 total_pages=total_pages
102 )
104 except Exception as error:
105 current_app.logger.error(error)
106 return internal_err_resp()
108 @staticmethod
109 def get_recommended_books_for_group(page, connected_user_uuid, reco_engine):
110 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()):
111 return err_resp("User not found!", 404)
113 # Query for recommendation from group
114 groups_ids = [
115 *list(map(lambda x: x.group_id, user.groups)),
116 *list(map(lambda x: x.group_id, user.owned_groups))
117 ]
119 filters = [RecommendedContentForGroupModel.group_id.in_(groups_ids)]
120 if reco_engine is not None:
121 filters.append(RecommendedContentModel.engine == reco_engine)
123 books, total_pages = Paginator.get_from(
124 db.session.query(RecommendedContentForGroupModel, BookModel)
125 .join(BookModel.content)
126 .join(RecommendedContentForGroupModel, RecommendedContentForGroupModel.content_id == ContentModel.content_id)
127 .filter(
128 and_(*filters)
129 )
130 .order_by(
131 RecommendedContentModel.score.desc().nullslast(),
132 ContentModel.popularity_score.desc().nullslast(),
133 ),
134 page,
135 )
137 try:
138 def c_load(row):
139 book = BookExtra.load(row[1])
140 book["reco_engine"] = row[0].engine
141 book["reco_score"] = row[0].score
142 return app
144 book_data = list(map(c_load, books))
146 return pagination_resp(
147 message="Most popular book data sent",
148 content=book_data,
149 page=page,
150 total_pages=total_pages
151 )
153 except Exception as error:
154 current_app.logger.error(error)
155 return internal_err_resp()
157 @staticmethod
158 def add_bad_recommendation(user_uuid, content_id, data):
159 """ Add bad user recommendation """
160 if not (user := UserModel.query.filter_by(uuid=user_uuid).first()):
161 return err_resp("User not found!", 404)
163 if not (book := BookModel.query.filter_by(content_id=content_id).first()):
164 return err_resp("Book not found!", 404)
166 try:
167 for type, value in data.items():
168 if type in REASON_CATEGORIES['book']:
169 for r in value:
171 new_bad_reco = BadRecommendationContentModel(
172 user_id=user.user_id,
173 content_id=book.content_id,
174 reason_categorie=type,
175 reason=r
176 )
178 db.session.add(new_bad_reco)
179 db.session.flush()
180 db.session.commit()
182 resp = message(True, "Bad recommendation has been registered.")
183 return resp, 201
185 except Exception as error:
186 current_app.logger.error(error)
187 return internal_err_resp()
189 @staticmethod
190 def add_additional_book(user_uuid, data):
191 """ Add additional book"""
192 if not (user := UserModel.query.filter_by(uuid=user_uuid).first()):
193 return err_resp("User not found!", 404)
195 # Check permissions
196 permissions = get_jwt_claims()['permissions']
197 if "add_content" not in permissions:
198 return err_resp("Permission missing", 403)
200 try:
202 new_additional_book = BookAdditionalModel(
203 title=data['title'],
204 isbn=data['isbn'],
205 )
207 if 'author' in data:
208 new_additional_book.author = data['author']
209 if 'year_of_publication' in data:
210 new_additional_book.year_of_publication = data['year_of_publication']
211 if 'publisher' in data:
212 new_additional_book.publisher = data['publisher']
213 if 'image_url_s' in data:
214 new_additional_book.image_url_s = data['image_url_s']
215 if 'image_url_m' in data:
216 new_additional_book.image_url_m = data['image_url_m']
217 if 'image_url_l' in data:
218 new_additional_book.image_url_l = data['image_url_l']
220 db.session.add(new_additional_book)
221 db.session.commit()
223 resp = message(True, "Book have been added to validation.")
224 return resp, 201
226 except Exception as error:
227 current_app.logger.error(error)
228 return internal_err_resp()
231 @staticmethod
232 def get_additional_book(connected_user_uuid, page):
233 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()):
234 return err_resp("User not found!", 404)
236 # Check permissions
237 permissions = get_jwt_claims()['permissions']
238 if "add_content" not in permissions:
239 return err_resp("Permission missing", 403)
241 books, total_pages = Paginator.get_from(
242 BookAdditionalModel.query,
243 page,
244 )
246 try:
247 book_data = BookAdditionalBase.loads(books)
249 return pagination_resp(
250 message="Additional Book data sent",
251 content=book_data,
252 page=page,
253 total_pages=total_pages
254 )
256 except Exception as error:
257 current_app.logger.error(error)
258 return internal_err_resp()
260 @staticmethod
261 def validate_additional_book(connected_user_uuid, book_id):
262 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()):
263 return err_resp("User not found!", 404)
265 # Check permissions
266 permissions = get_jwt_claims()['permissions']
267 if "validate_added_content" not in permissions:
268 return err_resp("Permission missing", 403)
270 if not (book := BookAdditionalModel.query.filter_by(book_id=book_id).first()):
271 return err_resp("Additional book not found!", 404)
273 try:
274 content = ContentModel(rating=None)
275 db.session.add(content)
276 db.session.flush()
278 new_book = BookModel(
279 isbn=book.isbn,
280 title=book.title,
281 author=book.author,
282 year_of_publication=book.year_of_publication,
283 publisher=book.publisher,
284 image_url_s=book.image_url_s,
285 image_url_m=book.image_url_m,
286 image_url_l=book.image_url_l,
287 content=content
288 )
289 db.session.add(new_book)
290 db.session.delete(book)
292 db.session.commit()
294 resp = message(
295 True, "Additional book data successfully validated")
296 return resp, 201
298 except Exception as error:
299 current_app.logger.error(error)
300 return internal_err_resp()
302 @staticmethod
303 def decline_additional_book(connected_user_uuid, book_id):
304 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()):
305 return err_resp("User not found!", 404)
307 # Check permissions
308 permissions = get_jwt_claims()['permissions']
309 if "delete_content" not in permissions:
310 return err_resp("Permission missing", 403)
312 if not (book := BookAdditionalModel.query.filter_by(book_id=book_id).first()):
313 return err_resp("Additional book not found!", 404)
315 try:
316 db.session.delete(book)
317 db.session.commit()
319 resp = message(True, "Additional book successfully deleted")
320 return resp, 201
322 except Exception as error:
323 current_app.logger.error(error)
324 return internal_err_resp()