Coverage for src/service/track_service.py : 60%
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, and_, select
5from sqlalchemy.sql.expression import null
6from datetime import datetime
8from src import db, settings
9from src.utils import pagination_resp, internal_err_resp, message, Paginator, err_resp
10from src.model import TrackModel, GenreModel, ContentType, UserModel, ContentModel, RecommendedContentModel, RecommendedContentForGroupModel, MetaUserContentModel, BadRecommendationContentModel, TrackAdditionalModel
11from src.schemas import TrackBase, TrackObject, GenreBase, TrackExtra, MetaUserContentBase, TrackAdditionalBase
14class TrackService:
15 @staticmethod
16 def search_track_data(search_term, page, connected_user_uuid):
17 """ Search track data by title """
18 if not (UserModel.query.filter_by(uuid=connected_user_uuid).first()):
19 return err_resp("User not found!", 404)
20 tracks, total_pages = Paginator.get_from(
21 TrackModel.query.filter(TrackModel.title.ilike(search_term+"%")).union(
22 TrackModel.query.filter(TrackModel.title.ilike("%"+search_term+"%"))),
23 page,
24 )
26 try:
27 track_data = TrackObject.loads(tracks)
29 return pagination_resp(
30 message="Track data sent",
31 content=track_data,
32 page=page,
33 total_pages=total_pages
34 )
36 except Exception as error:
37 current_app.logger.error(error)
38 return internal_err_resp()
40 @staticmethod
41 def get_popular_tracks(page, connected_user_uuid):
42 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()):
43 return err_resp("User not found!", 404)
45 # NOTE IMDB measure of popularity does not seem to be relevant for this media.
46 tracks, total_pages = Paginator.get_from(
47 TrackModel.query.join(TrackModel.content, aliased=True).order_by(
48 ContentModel.rating_count.desc().nullslast(),
49 ContentModel.rating.desc().nullslast(),
50 ),
51 page,
52 )
54 try:
55 track_data = TrackObject.loads(tracks)
57 return pagination_resp(
58 message="Most popular track data sent",
59 content=track_data,
60 page=page,
61 total_pages=total_pages
62 )
64 except Exception as error:
65 current_app.logger.error(error)
66 return internal_err_resp()
68 @staticmethod
69 def get_recommended_tracks_for_user(page, connected_user_uuid, reco_engine):
70 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()):
71 return err_resp("User not found!", 404)
73 filters = [RecommendedContentModel.user_id == user.user_id]
74 if reco_engine is not None:
75 filters.append(RecommendedContentModel.engine == reco_engine)
77 tracks, total_pages = Paginator.get_from(
78 db.session.query(RecommendedContentModel, TrackModel)
79 .join(TrackModel.content)
80 .join(RecommendedContentModel, RecommendedContentModel.content_id == ContentModel.content_id)
81 .filter(
82 and_(*filters)
83 )
84 .order_by(
85 RecommendedContentModel.score.desc().nullslast(),
86 ContentModel.rating_count.desc().nullslast(),
87 ContentModel.rating.desc().nullslast(),
88 ),
89 page,
90 )
92 try:
93 def c_load(row):
94 track = TrackExtra.load(row[1])
95 track["reco_engine"] = row[0].engine
96 track["reco_score"] = row[0].score
97 return track
99 track_data = list(map(c_load, tracks))
101 return pagination_resp(
102 message="Most popular track data sent",
103 content=track_data,
104 page=page,
105 total_pages=total_pages
106 )
108 except Exception as error:
109 current_app.logger.error(error)
110 return internal_err_resp()
112 @staticmethod
113 def get_recommended_tracks_for_group(page, connected_user_uuid, reco_engine):
114 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()):
115 return err_resp("User not found!", 404)
117 # Query for recommendation from group
118 groups_ids = [
119 *list(map(lambda x: x.group_id, user.groups)),
120 *list(map(lambda x: x.group_id, user.owned_groups))
121 ]
123 filters = [RecommendedContentForGroupModel.group_id.in_(groups_ids)]
124 if reco_engine is not None:
125 filters.append(RecommendedContentModel.engine == reco_engine)
127 tracks, total_pages = Paginator.get_from(
128 db.session.query(RecommendedContentForGroupModel, TrackModel)
129 .join(TrackModel.content)
130 .join(RecommendedContentForGroupModel, RecommendedContentForGroupModel.content_id == ContentModel.content_id)
131 .filter(
132 and_(*filters)
133 )
134 .order_by(
135 RecommendedContentModel.score.desc().nullslast(),
136 ContentModel.rating_count.desc().nullslast(),
137 ContentModel.rating.desc().nullslast(),
138 ),
139 page,
140 )
142 try:
143 def c_load(row):
144 app = TrackExtra.load(row[1])
145 app["reco_engine"] = row[0].engine
146 app["reco_score"] = row[0].score
147 return app
149 track_data = list(map(c_load, tracks))
151 return pagination_resp(
152 message="Most popular track data sent",
153 content=track_data,
154 page=page,
155 total_pages=total_pages
156 )
158 except Exception as error:
159 current_app.logger.error(error)
160 return internal_err_resp()
162 @staticmethod
163 def get_ordered_genre(connected_user_uuid):
164 if not (UserModel.query.filter_by(uuid=connected_user_uuid).first()):
165 return err_resp("User not found!", 404)
166 genres = GenreModel.query.filter_by(
167 content_type=ContentType.TRACK).order_by(GenreModel.count.desc()).all()
169 try:
170 genres_data = GenreBase.loads(genres)
172 resp = message(True, "track genres data sent")
173 resp["content"] = genres_data
174 return resp, 200
176 except Exception as error:
177 current_app.logger.error(error)
178 return internal_err_resp()
180 @staticmethod
181 def get_history(user_uuid, page):
182 """ Get the history of listened track """
183 if not (user := UserModel.query.filter_by(uuid=user_uuid).first()):
184 return err_resp("User not found!", 404)
186 datas, total_pages = Paginator.get_from(
187 db.session.query(MetaUserContentModel, TrackModel)
188 .join(TrackModel.content)
189 .join(MetaUserContentModel, MetaUserContentModel.content_id == TrackModel.content_id)
190 .filter(and_(MetaUserContentModel.user_id == user.user_id, MetaUserContentModel.last_count_increment != None))
191 .order_by(
192 MetaUserContentModel.last_count_increment.desc()
193 ),
194 page,
195 )
197 try:
198 history_data = list(map(lambda x: {
199 "last_played_date": MetaUserContentBase.load(x[0])["last_count_increment"],
200 "track": TrackObject.load(x[1])
201 }, datas))
203 return pagination_resp(
204 message="History of listened track data successfully updated",
205 content=history_data,
206 page=page,
207 total_pages=total_pages
208 )
209 except Exception as error:
210 import traceback
211 traceback.print_exc()
212 current_app.logger.error(error)
213 return internal_err_resp()
215 @staticmethod
216 def add_bad_recommendation(user_uuid, content_id, data):
217 """ Add bad user recommendation """
218 if not (user := UserModel.query.filter_by(uuid=user_uuid).first()):
219 return err_resp("User not found!", 404)
221 if not (track := TrackModel.query.filter_by(content_id=content_id).first()):
222 return err_resp("Track not found!", 404)
224 try:
225 for type, value in data.items():
226 if type in REASON_CATEGORIES['track']:
227 for r in value:
229 new_bad_reco = BadRecommendationContentModel(
230 user_id=user.user_id,
231 content_id=track.content_id,
232 reason_categorie=type,
233 reason=r
234 )
236 db.session.add(new_bad_reco)
237 db.session.flush()
238 db.session.commit()
240 resp = message(True, "Bad recommendation has been registered.")
241 return resp, 201
243 except Exception as error:
244 current_app.logger.error(error)
245 return internal_err_resp()
247 @staticmethod
248 def add_additional_track(user_uuid, data):
249 """ Add additional track"""
250 if not (user := UserModel.query.filter_by(uuid=user_uuid).first()):
251 return err_resp("User not found!", 404)
253 # Check permissions
254 permissions = get_jwt_claims()['permissions']
255 if "add_content" not in permissions:
256 return err_resp("Permission missing", 403)
258 try:
260 new_additional_track = TrackAdditionalModel(
261 title=data['title'],
262 )
264 if 'year' in data:
265 new_additional_track.year = data['year']
266 if 'artist_name' in data:
267 new_additional_track.artist_name = data['artist_name']
268 if 'release' in data:
269 new_additional_track.release = data['release']
270 if 'track_mmid' in data:
271 new_additional_track.track_mmid = data['track_mmid']
272 if 'recording_mbid' in data:
273 new_additional_track.recording_mbid = data['recording_mbid']
274 if 'spotify_id' in data:
275 new_additional_track.spotify_id = data['spotify_id']
276 if 'covert_art_url' in data:
277 new_additional_track.covert_art_url = data['covert_art_url']
279 for genre_id in data["genres"]:
280 if (ge := GenreModel.query.filter_by(genre_id=genre_id).first()):
281 new_additional_track.genres.append(ge)
282 else:
283 return err_resp("Genre %s not found!" % genre_id, 404)
285 db.session.add(new_additional_track)
286 db.session.commit()
288 resp = message(True, "Track have been added to validation.")
289 return resp, 201
291 except Exception as error:
292 current_app.logger.error(error)
293 return internal_err_resp()
295 @staticmethod
296 def get_additional_track(connected_user_uuid, page):
297 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()):
298 return err_resp("User not found!", 404)
300 # Check permissions
301 permissions = get_jwt_claims()['permissions']
302 if "add_content" not in permissions:
303 return err_resp("Permission missing", 403)
305 tracks, total_pages = Paginator.get_from(
306 TrackAdditionalModel.query,
307 page,
308 )
310 try:
311 track_data = TrackAdditionalBase.loads(tracks)
313 return pagination_resp(
314 message="Additional track data sent",
315 content=track_data,
316 page=page,
317 total_pages=total_pages
318 )
320 except Exception as error:
321 current_app.logger.error(error)
322 return internal_err_resp()
324 @staticmethod
325 def validate_additional_track(connected_user_uuid, track_id):
326 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()):
327 return err_resp("User not found!", 404)
329 # Check permissions
330 permissions = get_jwt_claims()['permissions']
331 if "validate_added_content" not in permissions:
332 return err_resp("Permission missing", 403)
334 if not (track := TrackAdditionalModel.query.filter_by(track_id=track_id).first()):
335 return err_resp("Additional track not found!", 404)
337 try:
338 content = ContentModel(rating=None, genres=track.genres)
339 db.session.add(content)
340 db.session.flush()
342 new_track = TrackModel(
343 title=track.title,
344 year=track.year,
345 artist_name=track.artist_name,
346 release=track.release,
347 track_mmid=track.track_mmid,
348 recording_mbid=track.recording_mbid,
349 spotify_id=track.spotify_id,
350 covert_art_url=track.covert_art_url,
351 content=content
352 )
353 db.session.add(new_track)
354 db.session.delete(track)
356 db.session.commit()
358 resp = message(
359 True, "Additional track data successfully validated")
360 return resp, 201
362 except Exception as error:
363 current_app.logger.error(error)
364 return internal_err_resp()
366 @staticmethod
367 def decline_additional_track(connected_user_uuid, track_id):
368 if not (user := UserModel.query.filter_by(uuid=connected_user_uuid).first()):
369 return err_resp("User not found!", 404)
371 # Check permissions
372 permissions = get_jwt_claims()['permissions']
373 if "delete_content" not in permissions:
374 return err_resp("Permission missing", 403)
376 if not (track := TrackAdditionalModel.query.filter_by(track_id=track_id).first()):
377 return err_resp("Additional track not found!", 404)
379 try:
380 db.session.delete(track)
381 db.session.commit()
383 resp = message(True, "Additional track successfully deleted")
384 return resp, 201
386 except Exception as error:
387 current_app.logger.error(error)
388 return internal_err_resp()