2019-07-29 11:44:10 +01:00
|
|
|
from flask import Blueprint, session, request, jsonify
|
2019-08-08 12:25:53 +01:00
|
|
|
|
2019-08-12 00:34:04 +01:00
|
|
|
import os
|
2019-08-08 12:25:53 +01:00
|
|
|
import datetime
|
|
|
|
import json
|
2019-08-17 18:30:13 +01:00
|
|
|
import logging
|
2019-08-08 12:25:53 +01:00
|
|
|
|
2019-07-29 11:44:10 +01:00
|
|
|
from google.cloud import firestore
|
2019-08-02 12:54:18 +01:00
|
|
|
from google.cloud import pubsub_v1
|
2019-08-08 12:25:53 +01:00
|
|
|
from google.cloud import tasks_v2
|
|
|
|
from google.protobuf import timestamp_pb2
|
2019-07-30 16:25:01 +01:00
|
|
|
from werkzeug.security import check_password_hash, generate_password_hash
|
2019-07-29 11:44:10 +01:00
|
|
|
|
2019-08-10 17:53:50 +01:00
|
|
|
from spotify.tasks.run_user_playlist import run_user_playlist as run_user_playlist
|
2019-08-12 00:34:04 +01:00
|
|
|
from spotify.tasks.play_user_playlist import play_user_playlist as play_user_playlist
|
2019-08-10 17:53:50 +01:00
|
|
|
|
2019-07-31 12:24:10 +01:00
|
|
|
import spotify.api.database as database
|
|
|
|
|
2019-07-29 11:44:10 +01:00
|
|
|
blueprint = Blueprint('api', __name__)
|
|
|
|
db = firestore.Client()
|
2019-08-02 12:54:18 +01:00
|
|
|
publisher = pubsub_v1.PublisherClient()
|
2019-08-08 12:25:53 +01:00
|
|
|
|
2019-08-17 18:30:13 +01:00
|
|
|
tasker = tasks_v2.CloudTasksClient()
|
2019-08-08 12:25:53 +01:00
|
|
|
task_path = tasker.queue_path('sarsooxyz', 'europe-west2', 'spotify-executions')
|
2019-08-02 12:54:18 +01:00
|
|
|
run_playlist_topic_path = publisher.topic_path('sarsooxyz', 'run_user_playlist')
|
2019-07-29 11:44:10 +01:00
|
|
|
|
2019-08-17 18:30:13 +01:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2019-07-29 11:44:10 +01:00
|
|
|
|
|
|
|
@blueprint.route('/playlists', methods=['GET'])
|
|
|
|
def get_playlists():
|
|
|
|
|
|
|
|
if 'username' in session:
|
|
|
|
|
2019-07-31 12:24:10 +01:00
|
|
|
pulled_user = database.get_user_doc_ref(session['username'])
|
2019-07-29 11:44:10 +01:00
|
|
|
|
2019-07-31 12:24:10 +01:00
|
|
|
playlists = database.get_user_playlists_collection(pulled_user.id)
|
2019-07-29 11:44:10 +01:00
|
|
|
|
|
|
|
response = {
|
2019-07-30 16:25:01 +01:00
|
|
|
'playlists': [i.to_dict() for i in playlists.stream()]
|
2019-07-29 11:44:10 +01:00
|
|
|
}
|
|
|
|
|
2019-07-30 16:25:01 +01:00
|
|
|
return jsonify(response), 200
|
|
|
|
|
|
|
|
else:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.warning('user not logged in')
|
2019-07-31 12:24:10 +01:00
|
|
|
return jsonify({'error': 'not logged in'}), 401
|
2019-07-30 16:25:01 +01:00
|
|
|
|
|
|
|
|
2019-07-31 20:31:01 +01:00
|
|
|
@blueprint.route('/playlist', methods=['GET', 'POST', 'PUT', 'DELETE'])
|
|
|
|
def playlist():
|
2019-07-30 16:25:01 +01:00
|
|
|
|
|
|
|
if 'username' in session:
|
|
|
|
|
2019-07-31 12:24:10 +01:00
|
|
|
user_ref = database.get_user_doc_ref(session['username'])
|
|
|
|
playlists = database.get_user_playlists_collection(user_ref.id)
|
2019-07-30 16:25:01 +01:00
|
|
|
|
2019-07-31 20:31:01 +01:00
|
|
|
if request.method == 'GET' or request.method == 'DELETE':
|
2019-07-30 16:25:01 +01:00
|
|
|
playlist_name = request.args.get('name', None)
|
|
|
|
|
|
|
|
if playlist_name:
|
|
|
|
|
2019-07-31 12:24:10 +01:00
|
|
|
queried_playlist = [i for i in playlists.where(u'name', u'==', playlist_name).stream()]
|
2019-07-30 16:25:01 +01:00
|
|
|
|
2019-07-31 12:24:10 +01:00
|
|
|
if len(queried_playlist) == 0:
|
2019-07-30 16:25:01 +01:00
|
|
|
return jsonify({'error': 'no playlist found'}), 404
|
2019-07-31 12:24:10 +01:00
|
|
|
elif len(queried_playlist) > 1:
|
2019-07-30 16:25:01 +01:00
|
|
|
return jsonify({'error': 'multiple playlists found'}), 500
|
|
|
|
|
2019-07-31 20:31:01 +01:00
|
|
|
if request.method == "GET":
|
|
|
|
|
|
|
|
return jsonify(queried_playlist[0].to_dict()), 200
|
|
|
|
|
|
|
|
elif request.method == 'DELETE':
|
|
|
|
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.info(f'deleted {session["username"]} / {queried_playlist[0].to_dict()["name"]}')
|
2019-07-31 20:31:01 +01:00
|
|
|
playlists.document(queried_playlist[0].id).delete()
|
|
|
|
|
|
|
|
return jsonify({"message": 'playlist deleted', "status": "success"}), 200
|
2019-07-30 16:25:01 +01:00
|
|
|
|
|
|
|
else:
|
2019-07-31 12:24:10 +01:00
|
|
|
return jsonify({"error": 'no name requested'}), 400
|
2019-07-30 16:25:01 +01:00
|
|
|
|
|
|
|
elif request.method == 'POST' or request.method == 'PUT':
|
|
|
|
|
|
|
|
request_json = request.get_json()
|
|
|
|
|
|
|
|
if 'name' not in request_json:
|
|
|
|
return jsonify({'error': "no name provided"}), 400
|
|
|
|
|
|
|
|
playlist_name = request_json['name']
|
2019-08-05 21:43:09 +01:00
|
|
|
|
2019-07-31 12:24:10 +01:00
|
|
|
playlist_parts = request_json.get('parts', None)
|
2019-08-04 02:11:33 +01:00
|
|
|
playlist_references = request_json.get('playlist_references', None)
|
2019-08-05 21:43:09 +01:00
|
|
|
|
2019-07-31 12:24:10 +01:00
|
|
|
playlist_id = request_json.get('id', None)
|
2019-07-31 20:31:01 +01:00
|
|
|
playlist_shuffle = request_json.get('shuffle', None)
|
2019-08-03 12:10:24 +01:00
|
|
|
playlist_type = request_json.get('type', None)
|
2019-08-05 21:43:09 +01:00
|
|
|
|
2019-08-03 12:10:24 +01:00
|
|
|
playlist_day_boundary = request_json.get('day_boundary', None)
|
2019-08-17 18:30:13 +01:00
|
|
|
playlist_add_this_month = request_json.get('add_this_month', None)
|
|
|
|
playlist_add_last_month = request_json.get('add_last_month', None)
|
2019-07-31 12:24:10 +01:00
|
|
|
|
2019-08-05 18:29:46 +01:00
|
|
|
playlist_recommendation = request_json.get('include_recommendations', None)
|
|
|
|
playlist_recommendation_sample = request_json.get('recommendation_sample', None)
|
|
|
|
|
2019-07-31 12:24:10 +01:00
|
|
|
queried_playlist = [i for i in playlists.where(u'name', u'==', playlist_name).stream()]
|
|
|
|
|
|
|
|
if request.method == 'PUT':
|
|
|
|
|
|
|
|
if len(queried_playlist) != 0:
|
|
|
|
return jsonify({'error': 'playlist already exists'}), 400
|
|
|
|
|
2019-07-31 20:31:01 +01:00
|
|
|
# if playlist_id is None or playlist_shuffle is None:
|
|
|
|
# return jsonify({'error': 'parts and id required'}), 400
|
2019-07-31 12:24:10 +01:00
|
|
|
|
2019-08-02 12:54:18 +01:00
|
|
|
from spotify.api.spotify import create_playlist as create_playlist
|
|
|
|
|
2019-08-03 12:10:24 +01:00
|
|
|
to_add = {
|
2019-07-31 12:24:10 +01:00
|
|
|
'name': playlist_name,
|
2019-08-05 18:29:46 +01:00
|
|
|
'parts': playlist_parts if playlist_parts is not None else [],
|
|
|
|
'playlist_references': playlist_references if playlist_references is not None else [],
|
|
|
|
'include_recommendations': playlist_recommendation if playlist_recommendation is not None else False,
|
|
|
|
'recommendation_sample': playlist_recommendation_sample if playlist_recommendation_sample is not None else 10,
|
2019-08-03 21:35:08 +01:00
|
|
|
'playlist_id': None,
|
2019-08-05 21:43:09 +01:00
|
|
|
'shuffle': playlist_shuffle if playlist_shuffle is not None else False,
|
|
|
|
'type': playlist_type if playlist_type is not None else 'default'
|
2019-08-03 12:10:24 +01:00
|
|
|
}
|
|
|
|
|
2019-08-03 21:35:08 +01:00
|
|
|
if user_ref.get().to_dict()['spotify_linked']:
|
|
|
|
new_playlist_id = create_playlist(session['username'], playlist_name)
|
|
|
|
to_add['playlist_id'] = new_playlist_id
|
|
|
|
|
2019-08-03 12:10:24 +01:00
|
|
|
if playlist_type == 'recents':
|
|
|
|
to_add['day_boundary'] = playlist_day_boundary if playlist_day_boundary is not None else 21
|
2019-08-17 18:30:13 +01:00
|
|
|
to_add['add_this_month'] = playlist_add_this_month if playlist_add_this_month is not None else False
|
|
|
|
to_add['add_last_month'] = playlist_add_last_month if playlist_add_last_month is not None else False
|
2019-08-03 12:10:24 +01:00
|
|
|
|
2019-08-03 21:35:08 +01:00
|
|
|
playlists.document().set(to_add)
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.info(f'added {session["username"]} / {playlist_name}')
|
2019-07-31 12:24:10 +01:00
|
|
|
|
2019-08-05 21:43:09 +01:00
|
|
|
return jsonify({"message": 'playlist added', "status": "success"}), 201
|
2019-07-31 12:24:10 +01:00
|
|
|
|
2019-07-31 20:31:01 +01:00
|
|
|
elif request.method == 'POST':
|
2019-07-31 12:24:10 +01:00
|
|
|
|
|
|
|
if len(queried_playlist) == 0:
|
|
|
|
return jsonify({'error': "playlist doesn't exist"}), 400
|
2019-07-30 16:25:01 +01:00
|
|
|
|
2019-07-31 12:24:10 +01:00
|
|
|
if len(queried_playlist) > 1:
|
|
|
|
return jsonify({'error': "multiple playlists exist"}), 500
|
|
|
|
|
|
|
|
playlist_doc = playlists.document(queried_playlist[0].id)
|
|
|
|
|
|
|
|
dic = {}
|
|
|
|
|
2019-08-03 12:10:24 +01:00
|
|
|
if playlist_parts is not None:
|
|
|
|
if playlist_parts == -1:
|
|
|
|
dic['parts'] = []
|
|
|
|
else:
|
|
|
|
dic['parts'] = playlist_parts
|
2019-07-31 12:24:10 +01:00
|
|
|
|
2019-08-04 02:11:33 +01:00
|
|
|
if playlist_references is not None:
|
|
|
|
if playlist_references == -1:
|
|
|
|
dic['playlist_references'] = []
|
|
|
|
else:
|
|
|
|
dic['playlist_references'] = playlist_references
|
|
|
|
|
2019-08-05 21:43:09 +01:00
|
|
|
if playlist_id is not None:
|
2019-07-31 12:24:10 +01:00
|
|
|
dic['playlist_id'] = playlist_id
|
|
|
|
|
2019-07-31 20:31:01 +01:00
|
|
|
if playlist_shuffle is not None:
|
|
|
|
dic['shuffle'] = playlist_shuffle
|
|
|
|
|
2019-08-03 12:10:24 +01:00
|
|
|
if playlist_day_boundary is not None:
|
|
|
|
dic['day_boundary'] = playlist_day_boundary
|
|
|
|
|
2019-08-17 18:30:13 +01:00
|
|
|
if playlist_add_this_month is not None:
|
|
|
|
dic['add_this_month'] = playlist_add_this_month
|
|
|
|
|
|
|
|
if playlist_add_last_month is not None:
|
|
|
|
dic['add_last_month'] = playlist_add_last_month
|
|
|
|
|
2019-08-05 18:29:46 +01:00
|
|
|
if playlist_recommendation is not None:
|
|
|
|
dic['include_recommendations'] = playlist_recommendation
|
|
|
|
|
|
|
|
if playlist_recommendation_sample is not None:
|
|
|
|
dic['recommendation_sample'] = playlist_recommendation_sample
|
|
|
|
|
2019-08-12 00:34:04 +01:00
|
|
|
if playlist_type is not None:
|
|
|
|
dic['type'] = playlist_type
|
|
|
|
|
2019-08-05 21:43:09 +01:00
|
|
|
if len(dic) == 0:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.warning(f'no changes to make for {session["username"]} / {playlist_name}')
|
2019-08-05 21:43:09 +01:00
|
|
|
return jsonify({"message": 'no changes to make', "status": "error"}), 400
|
|
|
|
|
2019-07-31 12:24:10 +01:00
|
|
|
playlist_doc.update(dic)
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.info(f'updated {session["username"]} / {playlist_name}')
|
2019-07-31 12:24:10 +01:00
|
|
|
|
|
|
|
return jsonify({"message": 'playlist updated', "status": "success"}), 200
|
2019-07-29 11:44:10 +01:00
|
|
|
|
|
|
|
else:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.warning('user not logged in')
|
2019-07-31 12:24:10 +01:00
|
|
|
return jsonify({'error': 'not logged in'}), 401
|
2019-07-29 11:44:10 +01:00
|
|
|
|
|
|
|
|
2019-08-03 21:35:08 +01:00
|
|
|
@blueprint.route('/user', methods=['GET', 'POST'])
|
2019-07-29 11:44:10 +01:00
|
|
|
def user():
|
|
|
|
|
|
|
|
if 'username' in session:
|
|
|
|
|
2019-08-03 21:35:08 +01:00
|
|
|
if request.method == 'GET':
|
2019-07-29 11:44:10 +01:00
|
|
|
|
2019-08-03 21:35:08 +01:00
|
|
|
pulled_user = database.get_user_doc_ref(session['username']).get().to_dict()
|
|
|
|
|
|
|
|
response = {
|
|
|
|
'username': pulled_user['username'],
|
|
|
|
'type': pulled_user['type'],
|
|
|
|
'spotify_linked': pulled_user['spotify_linked'],
|
|
|
|
'validated': pulled_user['validated']
|
|
|
|
}
|
|
|
|
|
|
|
|
return jsonify(response), 200
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
if database.get_user_doc_ref(session['username']).get().to_dict()['type'] != 'admin':
|
|
|
|
return jsonify({'status': 'error', 'message': 'unauthorized'}), 401
|
|
|
|
|
|
|
|
request_json = request.get_json()
|
|
|
|
|
|
|
|
if 'username' not in request_json:
|
|
|
|
return jsonify({'status': 'error', 'message': 'no username provided'}), 400
|
|
|
|
|
|
|
|
actionable_user = database.get_user_doc_ref(request_json['username'])
|
|
|
|
|
2019-08-05 21:43:09 +01:00
|
|
|
if actionable_user.get().exists is False:
|
|
|
|
return jsonify({"message": 'non-existent user', "status": "error"}), 400
|
|
|
|
|
2019-08-03 21:35:08 +01:00
|
|
|
dic = {}
|
|
|
|
|
|
|
|
if 'locked' in request_json:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.info(f'updating lock {request_json["username"]} / {request_json["locked"]}')
|
2019-08-03 21:35:08 +01:00
|
|
|
dic['locked'] = request_json['locked']
|
|
|
|
|
2019-08-05 21:43:09 +01:00
|
|
|
if 'spotify_linked' in request_json:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.info(f'deauthing {request_json["username"]}')
|
2019-08-05 21:43:09 +01:00
|
|
|
if request_json['spotify_linked'] is False:
|
|
|
|
dic.update({
|
|
|
|
'access_token': None,
|
|
|
|
'refresh_token': None,
|
|
|
|
'spotify_linked': False
|
|
|
|
})
|
|
|
|
|
|
|
|
if len(dic) == 0:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.warning(f'no updates for {request_json["username"]}')
|
2019-08-05 21:43:09 +01:00
|
|
|
return jsonify({"message": 'no changes to make', "status": "error"}), 400
|
2019-08-03 21:35:08 +01:00
|
|
|
|
2019-08-05 21:43:09 +01:00
|
|
|
actionable_user.update(dic)
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.info(f'updated {request_json["username"]}')
|
2019-08-05 21:43:09 +01:00
|
|
|
|
|
|
|
return jsonify({'message': 'account updated', 'status': 'succeeded'}), 200
|
2019-08-03 21:35:08 +01:00
|
|
|
|
|
|
|
else:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.warning('user not logged in')
|
2019-08-03 21:35:08 +01:00
|
|
|
return jsonify({'error': 'not logged in'}), 401
|
|
|
|
|
|
|
|
|
|
|
|
@blueprint.route('/users', methods=['GET'])
|
|
|
|
def users():
|
|
|
|
|
|
|
|
if 'username' in session:
|
|
|
|
|
|
|
|
if database.get_user_doc_ref(session['username']).get().to_dict()['type'] != 'admin':
|
|
|
|
return jsonify({'status': 'unauthorised'}), 401
|
|
|
|
|
|
|
|
dic = {
|
|
|
|
'accounts': []
|
2019-07-29 11:44:10 +01:00
|
|
|
}
|
|
|
|
|
2019-08-03 21:35:08 +01:00
|
|
|
for account in [i.to_dict() for i in db.collection(u'spotify_users').stream()]:
|
|
|
|
|
|
|
|
user_dic = {
|
|
|
|
'username': account['username'],
|
|
|
|
'type': account['type'],
|
|
|
|
'spotify_linked': account['spotify_linked'],
|
|
|
|
'locked': account['locked'],
|
|
|
|
'last_login': account['last_login']
|
|
|
|
}
|
|
|
|
|
|
|
|
dic['accounts'].append(user_dic)
|
|
|
|
|
2019-08-05 21:43:09 +01:00
|
|
|
return jsonify(dic), 200
|
2019-07-30 16:25:01 +01:00
|
|
|
|
|
|
|
else:
|
2019-07-31 12:24:10 +01:00
|
|
|
return jsonify({'error': 'not logged in'}), 401
|
2019-07-30 16:25:01 +01:00
|
|
|
|
|
|
|
|
|
|
|
@blueprint.route('/user/password', methods=['POST'])
|
|
|
|
def change_password():
|
|
|
|
|
|
|
|
request_json = request.get_json()
|
|
|
|
|
|
|
|
if 'username' in session:
|
|
|
|
|
|
|
|
if 'new_password' in request_json and 'current_password' in request_json:
|
|
|
|
|
|
|
|
if len(request_json['new_password']) == 0:
|
2019-07-31 12:24:10 +01:00
|
|
|
return jsonify({"error": 'zero length password'}), 400
|
2019-07-30 16:25:01 +01:00
|
|
|
|
|
|
|
if len(request_json['new_password']) > 30:
|
2019-07-31 12:24:10 +01:00
|
|
|
return jsonify({"error": 'password too long'}), 400
|
2019-07-30 16:25:01 +01:00
|
|
|
|
2019-07-31 12:24:10 +01:00
|
|
|
current_user = database.get_user_doc_ref(session['username'])
|
2019-07-30 16:25:01 +01:00
|
|
|
|
|
|
|
if check_password_hash(current_user.get().to_dict()['password'], request_json['current_password']):
|
|
|
|
|
|
|
|
current_user.update({'password': generate_password_hash(request_json['new_password'])})
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.info(f'password udpated {session["username"]}')
|
2019-07-30 16:25:01 +01:00
|
|
|
|
2019-08-05 21:43:09 +01:00
|
|
|
return jsonify({"message": 'password changed', "status": "success"}), 200
|
2019-07-30 16:25:01 +01:00
|
|
|
|
|
|
|
else:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.warning(f"incorrect password {session['username']}")
|
2019-08-05 21:43:09 +01:00
|
|
|
return jsonify({'error': 'wrong password provided'}), 401
|
2019-07-30 16:25:01 +01:00
|
|
|
|
|
|
|
else:
|
2019-07-31 12:24:10 +01:00
|
|
|
return jsonify({'error': 'malformed request, no old_password/new_password'}), 400
|
2019-07-29 11:44:10 +01:00
|
|
|
|
|
|
|
else:
|
2019-07-31 12:24:10 +01:00
|
|
|
return jsonify({'error': 'not logged in'}), 401
|
2019-08-02 12:54:18 +01:00
|
|
|
|
|
|
|
|
2019-08-12 00:34:04 +01:00
|
|
|
@blueprint.route('/playlist/play', methods=['POST'])
|
|
|
|
def play_playlist():
|
|
|
|
|
|
|
|
if 'username' in session:
|
|
|
|
|
|
|
|
request_json = request.get_json()
|
|
|
|
|
|
|
|
request_parts = request_json.get('parts', None)
|
|
|
|
request_playlist_type = request_json.get('playlist_type', 'default')
|
|
|
|
request_playlists = request_json.get('playlists', None)
|
|
|
|
request_shuffle = request_json.get('shuffle', False)
|
|
|
|
request_include_recommendations = request_json.get('include_recommendations', True)
|
|
|
|
request_recommendation_sample = request_json.get('recommendation_sample', 10)
|
|
|
|
request_day_boundary = request_json.get('day_boundary', 10)
|
2019-08-17 18:30:13 +01:00
|
|
|
request_add_this_month = request_json.get('add_this_month', False)
|
|
|
|
request_add_last_month = request_json.get('add_last_month', False)
|
|
|
|
|
|
|
|
logger.info(f'playing {session["username"]}')
|
2019-08-12 00:34:04 +01:00
|
|
|
|
|
|
|
if request_parts or request_playlists:
|
|
|
|
if len(request_parts) > 0 or len(request_playlists) > 0:
|
|
|
|
|
2019-08-17 18:30:13 +01:00
|
|
|
if os.environ.get('DEPLOY_DESTINATION', None) == 'PROD':
|
2019-08-12 00:34:04 +01:00
|
|
|
create_play_user_playlist_task(session['username'],
|
|
|
|
parts=request_parts,
|
|
|
|
playlist_type=request_playlist_type,
|
|
|
|
playlists=request_playlists,
|
|
|
|
shuffle=request_shuffle,
|
|
|
|
include_recommendations=request_include_recommendations,
|
|
|
|
recommendation_sample=request_recommendation_sample,
|
2019-08-17 18:30:13 +01:00
|
|
|
day_boundary=request_day_boundary,
|
|
|
|
add_this_month=request_add_this_month,
|
|
|
|
add_last_month=request_add_last_month)
|
2019-08-12 00:34:04 +01:00
|
|
|
else:
|
|
|
|
play_user_playlist(session['username'],
|
|
|
|
parts=request_parts,
|
|
|
|
playlist_type=request_playlist_type,
|
|
|
|
playlists=request_playlists,
|
|
|
|
shuffle=request_shuffle,
|
|
|
|
include_recommendations=request_include_recommendations,
|
|
|
|
recommendation_sample=request_recommendation_sample,
|
2019-08-17 18:30:13 +01:00
|
|
|
day_boundary=request_day_boundary,
|
|
|
|
add_this_month=request_add_this_month,
|
|
|
|
add_last_month=request_add_last_month)
|
2019-08-12 00:34:04 +01:00
|
|
|
|
|
|
|
return jsonify({'message': 'execution requested', 'status': 'success'}), 200
|
|
|
|
|
|
|
|
else:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.error(f'insufficient playlist/part lengths {session["username"]}')
|
2019-08-12 00:34:04 +01:00
|
|
|
return jsonify({'error': 'insufficient playlist sources'}), 400
|
|
|
|
|
|
|
|
else:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.error(f'no playlists/parts {session["username"]}')
|
2019-08-12 00:34:04 +01:00
|
|
|
return jsonify({'error': 'insufficient playlist sources'}), 400
|
|
|
|
|
|
|
|
else:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.warning('user not logged in')
|
2019-08-12 00:34:04 +01:00
|
|
|
return jsonify({'error': 'not logged in'}), 401
|
|
|
|
|
|
|
|
|
|
|
|
@blueprint.route('/playlist/play/task', methods=['POST'])
|
|
|
|
def play_playlist_task():
|
|
|
|
if request.headers.get('X-AppEngine-QueueName', None):
|
|
|
|
payload = request.get_data(as_text=True)
|
|
|
|
if payload:
|
|
|
|
payload = json.loads(payload)
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.info(f'playing {payload["username"]}')
|
2019-08-12 00:34:04 +01:00
|
|
|
|
|
|
|
play_user_playlist(payload['username'],
|
|
|
|
parts=payload['parts'],
|
|
|
|
playlist_type=payload['playlist_type'],
|
|
|
|
playlists=payload['playlists'],
|
|
|
|
shuffle=payload['shuffle'],
|
|
|
|
include_recommendations=payload['include_recommendations'],
|
|
|
|
recommendation_sample=payload['recommendation_sample'],
|
2019-08-17 18:30:13 +01:00
|
|
|
day_boundary=payload['day_boundary'],
|
|
|
|
add_this_month=payload['add_this_month'],
|
|
|
|
add_last_month=payload['add_last_month'])
|
2019-08-12 00:34:04 +01:00
|
|
|
|
|
|
|
return jsonify({'message': 'executed playlist', 'status': 'success'}), 200
|
|
|
|
else:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.warning('non tasks request')
|
2019-08-12 00:34:04 +01:00
|
|
|
return jsonify({'error': 'unauthorized'}), 401
|
|
|
|
|
|
|
|
|
2019-08-02 12:54:18 +01:00
|
|
|
@blueprint.route('/playlist/run', methods=['GET'])
|
|
|
|
def run_playlist():
|
|
|
|
|
|
|
|
if 'username' in session:
|
|
|
|
|
|
|
|
playlist_name = request.args.get('name', None)
|
|
|
|
|
|
|
|
if playlist_name:
|
|
|
|
|
2019-08-17 18:30:13 +01:00
|
|
|
if os.environ.get('DEPLOY_DESTINATION', None) == 'PROD':
|
2019-08-12 00:34:04 +01:00
|
|
|
create_run_user_playlist_task(session['username'], playlist_name)
|
|
|
|
else:
|
|
|
|
run_user_playlist(session['username'], playlist_name)
|
2019-08-02 12:54:18 +01:00
|
|
|
|
|
|
|
return jsonify({'message': 'execution requested', 'status': 'success'}), 200
|
|
|
|
|
|
|
|
else:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.warning('no playlist requested')
|
2019-08-02 12:54:18 +01:00
|
|
|
return jsonify({"error": 'no name requested'}), 400
|
|
|
|
|
|
|
|
else:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.warning('user not logged in')
|
2019-08-02 12:54:18 +01:00
|
|
|
return jsonify({'error': 'not logged in'}), 401
|
2019-08-03 23:36:14 +01:00
|
|
|
|
|
|
|
|
2019-08-08 12:25:53 +01:00
|
|
|
@blueprint.route('/playlist/run/task', methods=['POST'])
|
|
|
|
def run_playlist_task():
|
|
|
|
|
|
|
|
if request.headers.get('X-AppEngine-QueueName', None):
|
|
|
|
payload = request.get_data(as_text=True)
|
|
|
|
if payload:
|
|
|
|
payload = json.loads(payload)
|
2019-08-10 17:53:50 +01:00
|
|
|
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.info(f'running {payload["username"]} / {payload["name"]}')
|
|
|
|
|
2019-08-10 17:53:50 +01:00
|
|
|
run_user_playlist(payload['username'], payload['name'])
|
|
|
|
|
2019-08-08 12:25:53 +01:00
|
|
|
return jsonify({'message': 'executed playlist', 'status': 'success'}), 200
|
|
|
|
else:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.warning('non tasks request')
|
2019-08-08 12:25:53 +01:00
|
|
|
return jsonify({'error': 'unauthorized'}), 401
|
|
|
|
|
|
|
|
|
2019-08-03 23:36:14 +01:00
|
|
|
@blueprint.route('/playlist/run/user', methods=['GET'])
|
|
|
|
def run_user():
|
|
|
|
|
|
|
|
if 'username' in session:
|
|
|
|
|
|
|
|
if database.get_user_doc_ref(session['username']).get().to_dict()['type'] == 'admin':
|
|
|
|
user_name = request.args.get('username', session['username'])
|
|
|
|
else:
|
|
|
|
user_name = session['username']
|
|
|
|
|
|
|
|
execute_user(user_name)
|
|
|
|
|
|
|
|
return jsonify({'message': 'executed user', 'status': 'success'}), 200
|
|
|
|
|
|
|
|
else:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.warning('user not logged in')
|
2019-08-03 23:36:14 +01:00
|
|
|
return jsonify({'error': 'not logged in'}), 401
|
|
|
|
|
|
|
|
|
2019-08-08 12:25:53 +01:00
|
|
|
@blueprint.route('/playlist/run/user/task', methods=['POST'])
|
|
|
|
def run_user_task():
|
|
|
|
|
|
|
|
if request.headers.get('X-AppEngine-QueueName', None):
|
|
|
|
payload = request.get_data(as_text=True)
|
|
|
|
if payload:
|
|
|
|
execute_user(payload)
|
|
|
|
return jsonify({'message': 'executed user', 'status': 'success'}), 200
|
|
|
|
else:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.warning('non tasks request')
|
2019-08-08 12:25:53 +01:00
|
|
|
return jsonify({'error': 'unauthorized'}), 401
|
|
|
|
|
|
|
|
|
2019-08-03 23:36:14 +01:00
|
|
|
@blueprint.route('/playlist/run/users', methods=['GET'])
|
|
|
|
def run_users():
|
|
|
|
|
|
|
|
if 'username' in session:
|
|
|
|
|
|
|
|
if database.get_user_doc_ref(session['username']).get().to_dict()['type'] != 'admin':
|
|
|
|
return jsonify({'status': 'error', 'message': 'unauthorized'}), 401
|
|
|
|
|
|
|
|
execute_all_users()
|
|
|
|
|
|
|
|
return jsonify({'message': 'executed all users', 'status': 'success'}), 200
|
|
|
|
|
|
|
|
else:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.warning('user not logged in')
|
2019-08-03 23:36:14 +01:00
|
|
|
return jsonify({'error': 'not logged in'}), 401
|
|
|
|
|
|
|
|
|
|
|
|
@blueprint.route('/playlist/run/users/cron', methods=['GET'])
|
|
|
|
def run_users_cron():
|
|
|
|
|
2019-08-05 21:43:09 +01:00
|
|
|
if request.headers.get('X-Appengine-Cron', None):
|
2019-08-03 23:36:14 +01:00
|
|
|
execute_all_users()
|
|
|
|
return jsonify({'status': 'success'}), 200
|
|
|
|
else:
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.warning('user not logged in')
|
2019-08-03 23:36:14 +01:00
|
|
|
return jsonify({'status': 'error', 'message': 'unauthorised'}), 401
|
|
|
|
|
|
|
|
|
|
|
|
def execute_all_users():
|
|
|
|
|
2019-08-08 12:25:53 +01:00
|
|
|
seconds_delay = 0
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.info('running')
|
2019-08-08 12:25:53 +01:00
|
|
|
|
2019-08-05 21:43:09 +01:00
|
|
|
for iter_user in [i.to_dict() for i in db.collection(u'spotify_users').stream()]:
|
|
|
|
|
2019-08-03 23:36:14 +01:00
|
|
|
if iter_user['spotify_linked'] and not iter_user['locked']:
|
2019-08-08 12:25:53 +01:00
|
|
|
|
|
|
|
task = {
|
|
|
|
'app_engine_http_request': { # Specify the type of request.
|
|
|
|
'http_method': 'POST',
|
|
|
|
'relative_uri': '/api/playlist/run/user/task',
|
|
|
|
'body': iter_user['username'].encode()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d = datetime.datetime.utcnow() + datetime.timedelta(seconds=seconds_delay)
|
|
|
|
|
|
|
|
# Create Timestamp protobuf.
|
|
|
|
timestamp = timestamp_pb2.Timestamp()
|
|
|
|
timestamp.FromDatetime(d)
|
|
|
|
|
|
|
|
# Add the timestamp to the tasks.
|
|
|
|
task['schedule_time'] = timestamp
|
|
|
|
|
|
|
|
tasker.create_task(task_path, task)
|
|
|
|
|
|
|
|
seconds_delay += 30
|
2019-08-03 23:36:14 +01:00
|
|
|
|
|
|
|
|
|
|
|
def execute_user(username):
|
|
|
|
|
|
|
|
playlists = [i.to_dict() for i in
|
|
|
|
database.get_user_playlists_collection(database.get_user_query_stream(username)[0].id).stream()]
|
|
|
|
|
2019-08-08 12:25:53 +01:00
|
|
|
seconds_delay = 0
|
2019-08-17 18:30:13 +01:00
|
|
|
logger.info(f'running {username}')
|
2019-08-08 12:25:53 +01:00
|
|
|
|
2019-08-03 23:36:14 +01:00
|
|
|
for iterate_playlist in playlists:
|
2019-08-04 02:11:33 +01:00
|
|
|
if len(iterate_playlist['parts']) > 0 or len(iterate_playlist['playlist_references']) > 0:
|
2019-08-05 21:43:09 +01:00
|
|
|
if iterate_playlist.get('playlist_id', None):
|
2019-08-08 12:25:53 +01:00
|
|
|
|
2019-08-17 18:30:13 +01:00
|
|
|
if os.environ.get('DEPLOY_DESTINATION', None) == 'PROD':
|
2019-08-12 00:34:04 +01:00
|
|
|
create_run_user_playlist_task(username, iterate_playlist['name'], seconds_delay)
|
|
|
|
else:
|
|
|
|
run_playlist(username, iterate_playlist['name'])
|
|
|
|
|
|
|
|
seconds_delay += 6
|
2019-08-08 12:25:53 +01:00
|
|
|
|
|
|
|
|
2019-08-12 00:34:04 +01:00
|
|
|
def create_run_user_playlist_task(username, playlist_name, delay=0):
|
|
|
|
|
|
|
|
task = {
|
|
|
|
'app_engine_http_request': { # Specify the type of request.
|
|
|
|
'http_method': 'POST',
|
|
|
|
'relative_uri': '/api/playlist/run/task',
|
|
|
|
'body': json.dumps({
|
|
|
|
'username': username,
|
|
|
|
'name': playlist_name
|
|
|
|
}).encode()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if delay > 0:
|
|
|
|
|
|
|
|
d = datetime.datetime.utcnow() + datetime.timedelta(seconds=delay)
|
|
|
|
|
|
|
|
# Create Timestamp protobuf.
|
|
|
|
timestamp = timestamp_pb2.Timestamp()
|
|
|
|
timestamp.FromDatetime(d)
|
|
|
|
|
|
|
|
# Add the timestamp to the tasks.
|
|
|
|
task['schedule_time'] = timestamp
|
|
|
|
|
|
|
|
tasker.create_task(task_path, task)
|
|
|
|
|
|
|
|
|
|
|
|
def create_play_user_playlist_task(username,
|
|
|
|
parts=None,
|
|
|
|
playlist_type='default',
|
|
|
|
playlists=None,
|
|
|
|
shuffle=False,
|
|
|
|
include_recommendations=False,
|
|
|
|
recommendation_sample=10,
|
|
|
|
day_boundary=10,
|
2019-08-17 18:30:13 +01:00
|
|
|
add_this_month=False,
|
|
|
|
add_last_month=False,
|
2019-08-12 00:34:04 +01:00
|
|
|
delay=0):
|
|
|
|
task = {
|
|
|
|
'app_engine_http_request': { # Specify the type of request.
|
|
|
|
'http_method': 'POST',
|
|
|
|
'relative_uri': '/api/playlist/play/task',
|
|
|
|
'body': json.dumps({
|
|
|
|
'username': username,
|
|
|
|
'playlist_type': playlist_type,
|
|
|
|
'parts': parts,
|
|
|
|
'playlists': playlists,
|
|
|
|
'shuffle': shuffle,
|
|
|
|
'include_recommendations': include_recommendations,
|
|
|
|
'recommendation_sample': recommendation_sample,
|
2019-08-17 18:30:13 +01:00
|
|
|
'day_boundary': day_boundary,
|
|
|
|
'add_this_month': add_this_month,
|
|
|
|
'add_last_month': add_last_month
|
2019-08-12 00:34:04 +01:00
|
|
|
}).encode()
|
|
|
|
}
|
|
|
|
}
|
2019-08-08 12:25:53 +01:00
|
|
|
|
2019-08-12 00:34:04 +01:00
|
|
|
if delay > 0:
|
|
|
|
d = datetime.datetime.utcnow() + datetime.timedelta(seconds=delay)
|
2019-08-08 12:25:53 +01:00
|
|
|
|
2019-08-12 00:34:04 +01:00
|
|
|
# Create Timestamp protobuf.
|
|
|
|
timestamp = timestamp_pb2.Timestamp()
|
|
|
|
timestamp.FromDatetime(d)
|
2019-08-08 12:25:53 +01:00
|
|
|
|
2019-08-12 00:34:04 +01:00
|
|
|
# Add the timestamp to the tasks.
|
|
|
|
task['schedule_time'] = timestamp
|
2019-08-08 12:25:53 +01:00
|
|
|
|
2019-08-12 00:34:04 +01:00
|
|
|
tasker.create_task(task_path, task)
|
2019-08-03 23:36:14 +01:00
|
|
|
|
|
|
|
|
2019-08-10 17:53:50 +01:00
|
|
|
def push_run_user_playlist_message(username, name):
|
2019-08-03 23:36:14 +01:00
|
|
|
|
|
|
|
data = u'{}'.format(name)
|
|
|
|
data = data.encode('utf-8')
|
|
|
|
|
|
|
|
publisher.publish(run_playlist_topic_path, data=data, username=username)
|