[scrobbles] Fix tests around visbility
This commit is contained in:
22
PROJECT.org
22
PROJECT.org
@ -88,7 +88,7 @@ fetching and simple saving.
|
|||||||
*** Metadata sources
|
*** Metadata sources
|
||||||
**** Scraper
|
**** Scraper
|
||||||
|
|
||||||
* Backlog [0/14] :vrobbler:project:personal:
|
* Backlog [1/16] :vrobbler:project:personal:
|
||||||
** TODO [#C] Create small utility to clean up tracks scrobbled with wonky playback times :vrobbler:personal:bug:music:scrobbles:
|
** TODO [#C] Create small utility to clean up tracks scrobbled with wonky playback times :vrobbler:personal:bug:music:scrobbles:
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:ID: 702462cf-d54b-48c6-8a7c-78b8de751deb
|
:ID: 702462cf-d54b-48c6-8a7c-78b8de751deb
|
||||||
@ -534,7 +534,27 @@ async with the POST data stored in the log["raw_data"] and used by the celery en
|
|||||||
to go try to enrich the media instance. Should this enrichment fail, tag the scrobble as "enrichment-failed"
|
to go try to enrich the media instance. Should this enrichment fail, tag the scrobble as "enrichment-failed"
|
||||||
log a warning and move on.
|
log a warning and move on.
|
||||||
|
|
||||||
|
** TODO [#A] Allow updating all a user's scrobble visibility at once :scrobbles:sharing:feature:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ID: 9ed2ec65-bf69-4300-965c-6a7d3ef7ea03
|
||||||
|
:END:
|
||||||
|
|
||||||
|
*** Description
|
||||||
|
|
||||||
|
We now have the ability to share or unshare scrobbles and create private links. We should add a toggle
|
||||||
|
in the user's settings that will bulk make all their scrobbles public or private, so that a user
|
||||||
|
can either share everything, or lock their account down.
|
||||||
|
|
||||||
|
This should not affect scrobbles that are in the "Shared" visibility state.
|
||||||
|
|
||||||
|
Additionally, users's should have links in their settings to see what scrobbles
|
||||||
|
are either public, shared or private. Probably this could be done with a
|
||||||
|
?visbility=<> filter on the /scrobbles/ page.
|
||||||
|
|
||||||
|
** DONE [#A] Fix broken tests with new sharing and add tests :scrobbles:sharing:tests:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ID: 10ecd169-eaee-8554-d4ee-f1d34bfad99f
|
||||||
|
:END:
|
||||||
* Version 48.3 [1/1]
|
* Version 48.3 [1/1]
|
||||||
** DONE [#A] Fix bug in missing sqids dep :dependencies:project:
|
** DONE [#A] Fix bug in missing sqids dep :dependencies:project:
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
|||||||
@ -8,7 +8,8 @@ from django.urls import reverse
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from music.models import Album, Artist, Track
|
from music.models import Album, Artist, Track
|
||||||
from podcasts.models import PodcastEpisode
|
from podcasts.models import PodcastEpisode
|
||||||
from scrobbles.models import Scrobble
|
from scrobbles.models import Scrobble, ShareViewLog
|
||||||
|
from scrobbles.sqids import encode_scrobble_share
|
||||||
from tasks.models import Task
|
from tasks.models import Task
|
||||||
|
|
||||||
|
|
||||||
@ -512,6 +513,7 @@ def test_scrobble_detail_view_with_notes_as_flat_list(client):
|
|||||||
task=task,
|
task=task,
|
||||||
media_type="Task",
|
media_type="Task",
|
||||||
user=user,
|
user=user,
|
||||||
|
visibility="public",
|
||||||
log={
|
log={
|
||||||
"notes": ["First note", "Second note"],
|
"notes": ["First note", "Second note"],
|
||||||
"description": "Test description",
|
"description": "Test description",
|
||||||
@ -534,6 +536,7 @@ def test_scrobble_detail_view_with_notes_as_dict_timestamps(client):
|
|||||||
task=task,
|
task=task,
|
||||||
media_type="Task",
|
media_type="Task",
|
||||||
user=user,
|
user=user,
|
||||||
|
visibility="public",
|
||||||
log={
|
log={
|
||||||
"notes": [
|
"notes": [
|
||||||
{"2024-01-01 10:00:00": "Note at first timestamp"},
|
{"2024-01-01 10:00:00": "Note at first timestamp"},
|
||||||
@ -562,6 +565,7 @@ def test_scrobble_detail_view_with_notes_and_labels(client):
|
|||||||
task=task,
|
task=task,
|
||||||
media_type="Task",
|
media_type="Task",
|
||||||
user=user,
|
user=user,
|
||||||
|
visibility="public",
|
||||||
log={
|
log={
|
||||||
"notes": [
|
"notes": [
|
||||||
{"2024-01-01 10:00:00": "Note with label"},
|
{"2024-01-01 10:00:00": "Note with label"},
|
||||||
@ -739,3 +743,293 @@ def test_gps_webhook_creates_location(client, valid_auth_token):
|
|||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert "scrobble_id" in response.data
|
assert "scrobble_id" in response.data
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_share_view_shared_visibility(client):
|
||||||
|
user = get_user_model().objects.create_user(
|
||||||
|
username="shareuser", password="testpass"
|
||||||
|
)
|
||||||
|
task = Task.objects.create(title="Test Task")
|
||||||
|
scrobble = Scrobble.objects.create(
|
||||||
|
task=task, media_type="Task", user=user, visibility="shared",
|
||||||
|
timestamp=timezone.now(),
|
||||||
|
)
|
||||||
|
url = reverse(
|
||||||
|
"scrobbles:shared-detail",
|
||||||
|
kwargs={"sqid": encode_scrobble_share(scrobble.id, scrobble.share_token_version)},
|
||||||
|
)
|
||||||
|
response = client.get(url)
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_share_view_public_visibility(client):
|
||||||
|
user = get_user_model().objects.create_user(
|
||||||
|
username="shareuser2", password="testpass"
|
||||||
|
)
|
||||||
|
task = Task.objects.create(title="Test Task")
|
||||||
|
scrobble = Scrobble.objects.create(
|
||||||
|
task=task, media_type="Task", user=user, visibility="public",
|
||||||
|
timestamp=timezone.now(),
|
||||||
|
)
|
||||||
|
url = reverse(
|
||||||
|
"scrobbles:shared-detail",
|
||||||
|
kwargs={"sqid": encode_scrobble_share(scrobble.id, scrobble.share_token_version)},
|
||||||
|
)
|
||||||
|
response = client.get(url)
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_share_view_private_visibility_returns_404(client):
|
||||||
|
user = get_user_model().objects.create_user(
|
||||||
|
username="shareuser3", password="testpass"
|
||||||
|
)
|
||||||
|
task = Task.objects.create(title="Test Task")
|
||||||
|
scrobble = Scrobble.objects.create(
|
||||||
|
task=task, media_type="Task", user=user, visibility="private",
|
||||||
|
timestamp=timezone.now(),
|
||||||
|
)
|
||||||
|
url = reverse(
|
||||||
|
"scrobbles:shared-detail",
|
||||||
|
kwargs={"sqid": encode_scrobble_share(scrobble.id, scrobble.share_token_version)},
|
||||||
|
)
|
||||||
|
response = client.get(url)
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_share_view_invalid_sqid_returns_404(client):
|
||||||
|
url = reverse("scrobbles:shared-detail", kwargs={"sqid": "InvalidSqid123"})
|
||||||
|
response = client.get(url)
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_share_view_expired_token_returns_404(client):
|
||||||
|
user = get_user_model().objects.create_user(
|
||||||
|
username="shareuser4", password="testpass"
|
||||||
|
)
|
||||||
|
task = Task.objects.create(title="Test Task")
|
||||||
|
scrobble = Scrobble.objects.create(
|
||||||
|
task=task, media_type="Task", user=user, visibility="shared",
|
||||||
|
timestamp=timezone.now(),
|
||||||
|
)
|
||||||
|
old_sqid = encode_scrobble_share(scrobble.id, scrobble.share_token_version)
|
||||||
|
scrobble.regenerate_share_token()
|
||||||
|
url = reverse("scrobbles:shared-detail", kwargs={"sqid": old_sqid})
|
||||||
|
response = client.get(url)
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_share_view_increments_count_and_logs_view(client):
|
||||||
|
user = get_user_model().objects.create_user(
|
||||||
|
username="shareuser5", password="testpass"
|
||||||
|
)
|
||||||
|
task = Task.objects.create(title="Test Task")
|
||||||
|
scrobble = Scrobble.objects.create(
|
||||||
|
task=task, media_type="Task", user=user, visibility="shared",
|
||||||
|
timestamp=timezone.now(),
|
||||||
|
)
|
||||||
|
assert scrobble.share_view_count == 0
|
||||||
|
|
||||||
|
url = reverse(
|
||||||
|
"scrobbles:shared-detail",
|
||||||
|
kwargs={"sqid": encode_scrobble_share(scrobble.id, scrobble.share_token_version)},
|
||||||
|
)
|
||||||
|
response = client.get(url)
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
scrobble.refresh_from_db()
|
||||||
|
assert scrobble.share_view_count == 1
|
||||||
|
assert ShareViewLog.objects.filter(scrobble=scrobble).count() == 1
|
||||||
|
|
||||||
|
log_entry = ShareViewLog.objects.filter(scrobble=scrobble).first()
|
||||||
|
assert log_entry.ip_address == "127.0.0.1"
|
||||||
|
assert log_entry.user_agent == ""
|
||||||
|
assert log_entry.referrer == ""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_explore_view_shows_only_public_scrobbles(client):
|
||||||
|
user = get_user_model().objects.create_user(
|
||||||
|
username="exploreuser", password="testpass"
|
||||||
|
)
|
||||||
|
public_task = Task.objects.create(title="Public Task Title")
|
||||||
|
shared_task = Task.objects.create(title="Shared Task Title")
|
||||||
|
private_task = Task.objects.create(title="Private Task Title")
|
||||||
|
ts = timezone.now()
|
||||||
|
public_scrobble = Scrobble.objects.create(
|
||||||
|
task=public_task, media_type="Task", user=user, visibility="public",
|
||||||
|
timestamp=ts,
|
||||||
|
)
|
||||||
|
Scrobble.objects.create(
|
||||||
|
task=shared_task, media_type="Task", user=user, visibility="shared",
|
||||||
|
timestamp=ts,
|
||||||
|
)
|
||||||
|
Scrobble.objects.create(
|
||||||
|
task=private_task, media_type="Task", user=user, visibility="private",
|
||||||
|
timestamp=ts,
|
||||||
|
)
|
||||||
|
|
||||||
|
url = reverse("scrobbles:explore")
|
||||||
|
response = client.get(url)
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
content = response.content.decode()
|
||||||
|
assert "Public Task Title" in content
|
||||||
|
assert "Shared Task Title" not in content
|
||||||
|
assert "Private Task Title" not in content
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_change_visibility_owner_can_change(client):
|
||||||
|
user = get_user_model().objects.create_user(
|
||||||
|
username="visuser", password="testpass"
|
||||||
|
)
|
||||||
|
task = Task.objects.create(title="Test Task")
|
||||||
|
scrobble = Scrobble.objects.create(
|
||||||
|
task=task, media_type="Task", user=user, visibility="private",
|
||||||
|
timestamp=timezone.now(),
|
||||||
|
)
|
||||||
|
|
||||||
|
client.force_login(user)
|
||||||
|
url = reverse("scrobbles:change-visibility", kwargs={"uuid": scrobble.uuid})
|
||||||
|
response = client.post(url, {"visibility": "shared"})
|
||||||
|
assert response.status_code == 302
|
||||||
|
|
||||||
|
scrobble.refresh_from_db()
|
||||||
|
assert scrobble.visibility == "shared"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_change_visibility_non_owner_gets_404(client):
|
||||||
|
owner = get_user_model().objects.create_user(
|
||||||
|
username="owner", password="testpass"
|
||||||
|
)
|
||||||
|
other = get_user_model().objects.create_user(
|
||||||
|
username="other", password="testpass"
|
||||||
|
)
|
||||||
|
task = Task.objects.create(title="Test Task")
|
||||||
|
scrobble = Scrobble.objects.create(
|
||||||
|
task=task, media_type="Task", user=owner, visibility="private",
|
||||||
|
timestamp=timezone.now(),
|
||||||
|
)
|
||||||
|
|
||||||
|
client.force_login(other)
|
||||||
|
url = reverse("scrobbles:change-visibility", kwargs={"uuid": scrobble.uuid})
|
||||||
|
response = client.post(url, {"visibility": "shared"})
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
scrobble.refresh_from_db()
|
||||||
|
assert scrobble.visibility == "private"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_change_visibility_anonymous_redirects_to_login(client):
|
||||||
|
user = get_user_model().objects.create_user(
|
||||||
|
username="anontest", password="testpass"
|
||||||
|
)
|
||||||
|
task = Task.objects.create(title="Test Task")
|
||||||
|
scrobble = Scrobble.objects.create(
|
||||||
|
task=task, media_type="Task", user=user, visibility="private",
|
||||||
|
timestamp=timezone.now(),
|
||||||
|
)
|
||||||
|
url = reverse("scrobbles:change-visibility", kwargs={"uuid": scrobble.uuid})
|
||||||
|
response = client.post(url, {"visibility": "shared"})
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert "/login/" in response.url
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_regenerate_share_token_invalidates_old_sqid(client):
|
||||||
|
user = get_user_model().objects.create_user(
|
||||||
|
username="regentest", password="testpass"
|
||||||
|
)
|
||||||
|
task = Task.objects.create(title="Test Task")
|
||||||
|
scrobble = Scrobble.objects.create(
|
||||||
|
task=task, media_type="Task", user=user, visibility="shared",
|
||||||
|
timestamp=timezone.now(),
|
||||||
|
)
|
||||||
|
old_sqid = encode_scrobble_share(scrobble.id, scrobble.share_token_version)
|
||||||
|
|
||||||
|
client.force_login(user)
|
||||||
|
url = reverse("scrobbles:regenerate-share-token", kwargs={"uuid": scrobble.uuid})
|
||||||
|
response = client.post(url)
|
||||||
|
assert response.status_code == 302
|
||||||
|
|
||||||
|
scrobble.refresh_from_db()
|
||||||
|
assert scrobble.share_token_version == 1
|
||||||
|
|
||||||
|
old_url = reverse("scrobbles:shared-detail", kwargs={"sqid": old_sqid})
|
||||||
|
old_response = client.get(old_url)
|
||||||
|
assert old_response.status_code == 404
|
||||||
|
|
||||||
|
new_sqid = encode_scrobble_share(scrobble.id, scrobble.share_token_version)
|
||||||
|
new_url = reverse("scrobbles:shared-detail", kwargs={"sqid": new_sqid})
|
||||||
|
new_response = client.get(new_url)
|
||||||
|
assert new_response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_share_analytics_owner_can_view(client):
|
||||||
|
user = get_user_model().objects.create_user(
|
||||||
|
username="analyticsuser", password="testpass"
|
||||||
|
)
|
||||||
|
task = Task.objects.create(title="Test Task")
|
||||||
|
scrobble = Scrobble.objects.create(
|
||||||
|
task=task, media_type="Task", user=user, visibility="shared",
|
||||||
|
timestamp=timezone.now(),
|
||||||
|
)
|
||||||
|
|
||||||
|
client.force_login(user)
|
||||||
|
url = reverse("scrobbles:share-analytics", kwargs={"uuid": scrobble.uuid})
|
||||||
|
response = client.get(url)
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_share_analytics_non_owner_gets_404(client):
|
||||||
|
owner = get_user_model().objects.create_user(
|
||||||
|
username="analyticsowner", password="testpass"
|
||||||
|
)
|
||||||
|
other = get_user_model().objects.create_user(
|
||||||
|
username="analyticsother", password="testpass"
|
||||||
|
)
|
||||||
|
task = Task.objects.create(title="Test Task")
|
||||||
|
scrobble = Scrobble.objects.create(
|
||||||
|
task=task, media_type="Task", user=owner, visibility="shared",
|
||||||
|
timestamp=timezone.now(),
|
||||||
|
)
|
||||||
|
|
||||||
|
client.force_login(other)
|
||||||
|
url = reverse("scrobbles:share-analytics", kwargs={"uuid": scrobble.uuid})
|
||||||
|
response = client.get(url)
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_share_analytics_shows_view_logs(client):
|
||||||
|
user = get_user_model().objects.create_user(
|
||||||
|
username="analyticsviews", password="testpass"
|
||||||
|
)
|
||||||
|
task = Task.objects.create(title="Test Task")
|
||||||
|
scrobble = Scrobble.objects.create(
|
||||||
|
task=task, media_type="Task", user=user, visibility="shared",
|
||||||
|
timestamp=timezone.now(),
|
||||||
|
)
|
||||||
|
|
||||||
|
sqid = encode_scrobble_share(scrobble.id, scrobble.share_token_version)
|
||||||
|
share_url = reverse("scrobbles:shared-detail", kwargs={"sqid": sqid})
|
||||||
|
client.get(share_url)
|
||||||
|
client.get(share_url)
|
||||||
|
|
||||||
|
client.force_login(user)
|
||||||
|
url = reverse("scrobbles:share-analytics", kwargs={"uuid": scrobble.uuid})
|
||||||
|
response = client.get(url)
|
||||||
|
assert response.status_code == 200
|
||||||
|
content = response.content.decode()
|
||||||
|
assert "127.0.0.1" in content
|
||||||
|
assert ShareViewLog.objects.filter(scrobble=scrobble).count() == 2
|
||||||
|
|||||||
Reference in New Issue
Block a user