replace playlist delete page with playlist manage page

This commit is contained in:
Akbar Rahman 2023-01-10 20:56:55 +00:00
parent b633abdb6e
commit b136285c00
Signed by: alvierahman90
GPG Key ID: 20609519444A1269
7 changed files with 128 additions and 28 deletions

View File

@ -64,7 +64,7 @@ class Db:
self.rdb.set(Key.playlist_count(playlist_id), count) self.rdb.set(Key.playlist_count(playlist_id), count)
self.rdb.set(Key.playlist_counttype(playlist_id), counttype) self.rdb.set(Key.playlist_counttype(playlist_id), counttype)
def user_del_playlist(self, spotify_id, playlist_id): def user_del_playlist(self, spotify_id, playlist_id, delete_on_spotify = True):
self.rdb.srem(Key.user_playlists(spotify_id), playlist_id) self.rdb.srem(Key.user_playlists(spotify_id), playlist_id)
self.rdb.delete(Key.playlist_count(playlist_id)) self.rdb.delete(Key.playlist_count(playlist_id))
self.rdb.delete(Key.playlist_counttype(playlist_id)) self.rdb.delete(Key.playlist_counttype(playlist_id))

View File

@ -10,6 +10,7 @@ Jinja2==3.1.2
MarkupSafe==2.1.1 MarkupSafe==2.1.1
redis==4.4.0 redis==4.4.0
requests==2.28.1 requests==2.28.1
requests-futures==1.0.0
six==1.16.0 six==1.16.0
urllib3==1.26.13 urllib3==1.26.13
Werkzeug==2.2.2 Werkzeug==2.2.2

View File

@ -1,6 +1,7 @@
import os import os
from flask import Flask, render_template, request, make_response, redirect, url_for from flask import Flask, render_template, request, make_response, redirect, url_for
import requests as rq import requests as rq
from requests_futures.sessions import FuturesSession
import urllib.parse import urllib.parse
import base64 import base64
from datetime import date, datetime from datetime import date, datetime
@ -51,6 +52,9 @@ def isauth(cookies):
return user_secret == db.get_user_client_secret(user_id) return user_secret == db.get_user_client_secret(user_id)
def create_empty_message():
return { 'type':'', 'text': u'\u00A0'}
@app.route("/", methods=['GET', 'POST']) @app.route("/", methods=['GET', 'POST'])
def index(): def index():
@ -67,7 +71,7 @@ def index():
'redirect_uri': BASE_URL + url_for('cb'), 'redirect_uri': BASE_URL + url_for('cb'),
'response_type': 'code' 'response_type': 'code'
}), }),
message = { 'type':'', 'text': ''} message = create_empty_message()
)) ))
resp.set_cookie( resp.set_cookie(
'user_secret', 'user_secret',
@ -81,7 +85,7 @@ def index():
if request.method=='GET': if request.method=='GET':
message = request.args.get('message') message = request.args.get('message')
return render_template("index_authorised.html", message = json.loads(message) if message else "" ) return render_template("index_authorised.html", message = json.loads(message) if message else create_empty_message())
playlist_name = request.form.get('pname') playlist_name = request.form.get('pname')
@ -180,20 +184,73 @@ def logout():
resp.set_cookie('user_secret', '') resp.set_cookie('user_secret', '')
return resp return resp
@app.route('/delete') @app.route('/manage')
def delete(): def manage():
if not isauth(request.cookies): if not isauth(request.cookies):
return redirect(url_for('index')) return redirect(url_for('index'))
user_id = request.cookies.get('spotify_id') user_id = request.cookies.get('spotify_id')
playlist_id = request.args.get('playlist') playlist_id = request.args.get('playlist_id')
action = request.args.get('action')
def gen_populated_response(message = False):
session = FuturesSession()
futures = []
ids = db.get_user_playlists(user_id)
playlists = []
headers = { 'Authorization': f'Bearer {db.get_user_auth_token(user_id)}' }
for pl_id in ids:
futures.append(session.get(f"{SPOTIFY_API_ENDPOINT}/playlists/{pl_id}?fields=id,name", headers = headers))
for future in futures:
resp = future.result()
if resp.status_code != 200:
# fail silently for now...
# TODO maybe report this error l8r to user, log
print(f"NONZERO STATUS CODE: {resp.status_code=}")
print(f"{resp.content=}")
continue
resp = resp.json()
playlists.append(resp)
if not message:
message = create_empty_message()
if len(ids) == 0:
message['type'] = 'info'
message['text'] = 'no playlists managed by heartbeats'
message_str = request.args.get('message')
if message_str:
message = json.loads(message_str)
return render_template("manage.html", message=message, playlists=playlists)
if not playlist_id: if not playlist_id:
return render_template("delete.html", message={'type':'', 'text': ''}, playlist_ids=db.get_user_playlists(user_id)) return gen_populated_response()
db.user_del_playlist(user_id, playlist_id) if action in [ 'delete', 'unlink' ]:
actioned = 'deleted' if action == 'delete' else 'unlinked'
if action == 'delete':
headers = { 'Authorization': f'Bearer {db.get_user_auth_token(user_id)}' }
resp = rq.delete(
f"{SPOTIFY_API_ENDPOINT}/playlists/{playlist_id}/followers",
headers = headers
)
print(resp.content)
if resp.status_code != 200:
return redirect(url_for('manage', message=json.dumps({
'type': 'error',
'text': f'unable to {action} playlist {playlist_name}'
})))
return render_template("delete.html", message={
'type': 'info', db.user_del_playlist(user_id, playlist_id)
'text': f'successfully deleted playlist {playlist_id=}' playlist_name = request.args.get('playlist_name')
}, playlist_ids=db.get_user_playlists(user_id)) return redirect(url_for('manage', message=json.dumps({
'type': 'info',
'text': f'successfully {actioned} playlist {playlist_name}'
})))
return gen_populated_response(message={
'type': 'error',
'text': f'action not recognised: {action}'
})

View File

@ -28,6 +28,7 @@ a, a:visited {
#message { padding: 1em; } #message { padding: 1em; }
</style> </style>
<title>{% block title %}{% endblock %}</title> <title>{% block title %}{% endblock %}</title>
{% block extrahead %}{% endblock %}
</head> </head>
<body> <body>
<p class="messagetype{{message['type']}}"id="message">{{message['text']}}</p> <p class="messagetype{{message['type']}}"id="message">{{message['text']}}</p>

View File

@ -1,15 +0,0 @@
{% extends "base.html" %}
{% block title %}heartbeats | delete a playlist{% endblock %}
{% block body %}
<h1> delete a playlist </h1>
<ul>
{% for pid in playlist_ids %}
<li><a href="?playlist={{pid}}">{{pid}}</a></li>
{% endfor %}
</ul>
<a href="..">home</a>
{% endblock %}

View File

@ -22,5 +22,5 @@
<br> <br>
</form> </form>
<p><a href="./delete">delete a playlist</a>, <a href="./logout">logout</a></p> <p><a href="./manage">manage playlists</a>, <a href="./logout">logout</a></p>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,56 @@
{% extends "base.html" %}
{% block title %}heartbeats | manage playlists{% endblock %}
{% block extrahead %}
<style>
.playlists * {
padding: 0.5em;
}
.playlist {
display: flex;
justify-content: space-between;
align-content: last baseline;
}
.playlist .name {
width: 50%;
}
.playlist .actions a { padding: 0; }
.playlist .actions {
display: flex;
justify-content: space-between;
flex-grow: 1;
}
.playlist:nth-child(even) {
background-color: var(--bg-lc);
}
.playlists .actions a { padding: 0; }
span {
height: fit-content;
}
</style>
{% endblock %}
{% block body %}
<h1><span style="color: #1db954">manage</span> playlists</h1>
<div class="playlists">
{% for playlist in playlists %}
<div class="playlist">
<span class="name" title="{{playlist['name']}} ({{playlist['id']}})">{{playlist['name']}}</span>
<div class="actions">
<a href="?playlist_id={{playlist['id']}}&playlist_name={{playlist['name']}}&action=delete">delete</a>
<a href="?playlist_id={{playlist['id']}}&playlist_name={{playlist['name']}}&action=unlink">unlink without deleting</a>
</div>
</div>
{% endfor %}
</div>
<!--a href="..">home</a-->
{% endblock %}