2018-03-03 10:20:21 +00:00
|
|
|
import pytest
|
2017-12-24 18:15:21 +00:00
|
|
|
from django.urls import reverse
|
|
|
|
|
|
|
|
from funkwhale_api.users.models import User
|
|
|
|
|
|
|
|
|
2018-05-21 16:45:31 +00:00
|
|
|
def test_can_create_user_via_api(preferences, api_client, db):
|
2018-06-09 13:36:16 +00:00
|
|
|
url = reverse("rest_register")
|
2017-12-24 18:15:21 +00:00
|
|
|
data = {
|
2018-06-09 13:36:16 +00:00
|
|
|
"username": "test1",
|
|
|
|
"email": "test1@test.com",
|
|
|
|
"password1": "testtest",
|
|
|
|
"password2": "testtest",
|
2017-12-24 18:15:21 +00:00
|
|
|
}
|
2018-06-09 13:36:16 +00:00
|
|
|
preferences["users__registration_enabled"] = True
|
2018-05-21 16:45:31 +00:00
|
|
|
response = api_client.post(url, data)
|
2017-12-24 18:15:21 +00:00
|
|
|
assert response.status_code == 201
|
|
|
|
|
2018-06-09 13:36:16 +00:00
|
|
|
u = User.objects.get(email="test1@test.com")
|
|
|
|
assert u.username == "test1"
|
2017-12-24 18:15:21 +00:00
|
|
|
|
|
|
|
|
2018-07-22 11:05:43 +00:00
|
|
|
@pytest.mark.parametrize("username", ["wrong.name", "wrong-name", "éaeu", "wrong name"])
|
|
|
|
def test_username_only_accepts_letters_and_underscores(
|
|
|
|
username, preferences, api_client, db
|
|
|
|
):
|
|
|
|
url = reverse("rest_register")
|
|
|
|
data = {
|
|
|
|
"username": username,
|
|
|
|
"email": "test1@test.com",
|
|
|
|
"password1": "testtest",
|
|
|
|
"password2": "testtest",
|
|
|
|
}
|
|
|
|
preferences["users__registration_enabled"] = True
|
|
|
|
response = api_client.post(url, data)
|
|
|
|
assert response.status_code == 400
|
|
|
|
|
|
|
|
|
2018-05-21 16:45:31 +00:00
|
|
|
def test_can_restrict_usernames(settings, preferences, db, api_client):
|
2018-06-09 13:36:16 +00:00
|
|
|
url = reverse("rest_register")
|
|
|
|
preferences["users__registration_enabled"] = True
|
|
|
|
settings.USERNAME_BLACKLIST = ["funkwhale"]
|
2018-03-24 19:31:36 +00:00
|
|
|
data = {
|
2018-06-09 13:36:16 +00:00
|
|
|
"username": "funkwhale",
|
|
|
|
"email": "contact@funkwhale.io",
|
|
|
|
"password1": "testtest",
|
|
|
|
"password2": "testtest",
|
2018-03-24 19:31:36 +00:00
|
|
|
}
|
|
|
|
|
2018-05-21 16:45:31 +00:00
|
|
|
response = api_client.post(url, data)
|
2018-03-24 19:31:36 +00:00
|
|
|
|
|
|
|
assert response.status_code == 400
|
2018-06-09 13:36:16 +00:00
|
|
|
assert "username" in response.data
|
2018-03-24 19:31:36 +00:00
|
|
|
|
|
|
|
|
2018-05-21 16:45:31 +00:00
|
|
|
def test_can_disable_registration_view(preferences, api_client, db):
|
2018-06-09 13:36:16 +00:00
|
|
|
url = reverse("rest_register")
|
2017-12-24 18:15:21 +00:00
|
|
|
data = {
|
2018-06-09 13:36:16 +00:00
|
|
|
"username": "test1",
|
|
|
|
"email": "test1@test.com",
|
|
|
|
"password1": "testtest",
|
|
|
|
"password2": "testtest",
|
2017-12-24 18:15:21 +00:00
|
|
|
}
|
2018-06-09 13:36:16 +00:00
|
|
|
preferences["users__registration_enabled"] = False
|
2018-05-21 16:45:31 +00:00
|
|
|
response = api_client.post(url, data)
|
2017-12-24 18:15:21 +00:00
|
|
|
assert response.status_code == 403
|
|
|
|
|
|
|
|
|
2018-06-19 20:23:22 +00:00
|
|
|
def test_can_signup_with_invitation(preferences, factories, api_client):
|
|
|
|
url = reverse("rest_register")
|
2018-06-21 17:41:40 +00:00
|
|
|
invitation = factories["users.Invitation"](code="Hello")
|
2018-06-19 20:23:22 +00:00
|
|
|
data = {
|
|
|
|
"username": "test1",
|
|
|
|
"email": "test1@test.com",
|
|
|
|
"password1": "testtest",
|
|
|
|
"password2": "testtest",
|
|
|
|
"invitation": "hello",
|
|
|
|
}
|
|
|
|
preferences["users__registration_enabled"] = False
|
|
|
|
response = api_client.post(url, data)
|
|
|
|
assert response.status_code == 201
|
|
|
|
u = User.objects.get(email="test1@test.com")
|
|
|
|
assert u.username == "test1"
|
|
|
|
assert u.invitation == invitation
|
|
|
|
|
|
|
|
|
|
|
|
def test_can_signup_with_invitation_invalid(preferences, factories, api_client):
|
|
|
|
url = reverse("rest_register")
|
2018-06-21 17:51:12 +00:00
|
|
|
factories["users.Invitation"](code="hello")
|
2018-06-19 20:23:22 +00:00
|
|
|
data = {
|
|
|
|
"username": "test1",
|
|
|
|
"email": "test1@test.com",
|
|
|
|
"password1": "testtest",
|
|
|
|
"password2": "testtest",
|
|
|
|
"invitation": "nope",
|
|
|
|
}
|
|
|
|
response = api_client.post(url, data)
|
|
|
|
assert response.status_code == 400
|
|
|
|
assert "invitation" in response.data
|
|
|
|
|
|
|
|
|
2018-05-18 16:48:46 +00:00
|
|
|
def test_can_fetch_data_from_api(api_client, factories):
|
2018-06-09 13:36:16 +00:00
|
|
|
url = reverse("api:v1:users:users-me")
|
2018-05-18 16:48:46 +00:00
|
|
|
response = api_client.get(url)
|
2017-12-24 18:15:21 +00:00
|
|
|
# login required
|
|
|
|
assert response.status_code == 401
|
|
|
|
|
2018-06-09 13:36:16 +00:00
|
|
|
user = factories["users.User"](permission_library=True)
|
|
|
|
api_client.login(username=user.username, password="test")
|
2018-05-18 16:48:46 +00:00
|
|
|
response = api_client.get(url)
|
2017-12-24 18:15:21 +00:00
|
|
|
assert response.status_code == 200
|
2018-06-09 13:36:16 +00:00
|
|
|
assert response.data["username"] == user.username
|
|
|
|
assert response.data["is_staff"] == user.is_staff
|
|
|
|
assert response.data["is_superuser"] == user.is_superuser
|
|
|
|
assert response.data["email"] == user.email
|
|
|
|
assert response.data["name"] == user.name
|
|
|
|
assert response.data["permissions"] == user.get_permissions()
|
2017-12-26 13:47:27 +00:00
|
|
|
|
|
|
|
|
2018-05-21 16:45:31 +00:00
|
|
|
def test_can_get_token_via_api(api_client, factories):
|
2018-06-09 13:36:16 +00:00
|
|
|
user = factories["users.User"]()
|
|
|
|
url = reverse("api:v1:token")
|
|
|
|
payload = {"username": user.username, "password": "test"}
|
2017-12-26 13:47:27 +00:00
|
|
|
|
2018-05-21 16:45:31 +00:00
|
|
|
response = api_client.post(url, payload)
|
2017-12-26 13:47:27 +00:00
|
|
|
assert response.status_code == 200
|
2018-06-09 13:36:16 +00:00
|
|
|
assert "token" in response.data
|
2017-12-26 13:47:27 +00:00
|
|
|
|
|
|
|
|
2018-05-21 16:45:31 +00:00
|
|
|
def test_can_get_token_via_api_inactive(api_client, factories):
|
2018-06-09 13:36:16 +00:00
|
|
|
user = factories["users.User"](is_active=False)
|
|
|
|
url = reverse("api:v1:token")
|
|
|
|
payload = {"username": user.username, "password": "test"}
|
2018-05-21 16:45:31 +00:00
|
|
|
|
|
|
|
response = api_client.post(url, payload)
|
|
|
|
assert response.status_code == 400
|
|
|
|
|
|
|
|
|
|
|
|
def test_can_refresh_token_via_api(api_client, factories, mocker):
|
2017-12-26 13:47:27 +00:00
|
|
|
# first, we get a token
|
2018-06-09 13:36:16 +00:00
|
|
|
user = factories["users.User"]()
|
|
|
|
url = reverse("api:v1:token")
|
|
|
|
payload = {"username": user.username, "password": "test"}
|
2017-12-26 13:47:27 +00:00
|
|
|
|
2018-05-21 16:45:31 +00:00
|
|
|
response = api_client.post(url, payload)
|
2017-12-26 13:47:27 +00:00
|
|
|
assert response.status_code == 200
|
|
|
|
|
2018-06-09 13:36:16 +00:00
|
|
|
token = response.data["token"]
|
|
|
|
url = reverse("api:v1:token_refresh")
|
|
|
|
response = api_client.post(url, {"token": token})
|
2017-12-26 13:47:27 +00:00
|
|
|
|
|
|
|
assert response.status_code == 200
|
2018-06-09 13:36:16 +00:00
|
|
|
assert "token" in response.data
|
2017-12-26 14:56:04 +00:00
|
|
|
|
|
|
|
|
2018-05-21 16:45:31 +00:00
|
|
|
def test_changing_password_updates_secret_key(logged_in_api_client):
|
|
|
|
user = logged_in_api_client.user
|
2017-12-26 14:56:04 +00:00
|
|
|
password = user.password
|
|
|
|
secret_key = user.secret_key
|
2018-06-09 13:36:16 +00:00
|
|
|
payload = {"old_password": "test", "new_password1": "new", "new_password2": "new"}
|
|
|
|
url = reverse("change_password")
|
2017-12-26 14:56:04 +00:00
|
|
|
|
2018-06-09 15:41:59 +00:00
|
|
|
logged_in_api_client.post(url, payload)
|
2017-12-26 14:56:04 +00:00
|
|
|
|
|
|
|
user.refresh_from_db()
|
|
|
|
|
|
|
|
assert user.secret_key != secret_key
|
|
|
|
assert user.password != password
|
2018-03-03 10:20:21 +00:00
|
|
|
|
|
|
|
|
2018-06-09 13:36:16 +00:00
|
|
|
def test_can_request_password_reset(factories, api_client, mailoutbox):
|
|
|
|
user = factories["users.User"]()
|
|
|
|
payload = {"email": user.email}
|
2018-05-06 09:30:41 +00:00
|
|
|
emails = len(mailoutbox)
|
2018-06-09 13:36:16 +00:00
|
|
|
url = reverse("rest_password_reset")
|
2018-05-06 09:30:41 +00:00
|
|
|
|
|
|
|
response = api_client.post(url, payload)
|
|
|
|
assert response.status_code == 200
|
|
|
|
assert len(mailoutbox) > emails
|
|
|
|
|
|
|
|
|
2018-03-03 10:20:21 +00:00
|
|
|
def test_user_can_patch_his_own_settings(logged_in_api_client):
|
|
|
|
user = logged_in_api_client.user
|
2018-06-09 13:36:16 +00:00
|
|
|
payload = {"privacy_level": "me"}
|
|
|
|
url = reverse("api:v1:users:users-detail", kwargs={"username": user.username})
|
2018-03-03 10:20:21 +00:00
|
|
|
|
|
|
|
response = logged_in_api_client.patch(url, payload)
|
|
|
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
user.refresh_from_db()
|
|
|
|
|
2018-06-09 13:36:16 +00:00
|
|
|
assert user.privacy_level == "me"
|
2018-03-03 10:20:21 +00:00
|
|
|
|
|
|
|
|
2018-05-09 20:18:33 +00:00
|
|
|
def test_user_can_request_new_subsonic_token(logged_in_api_client):
|
|
|
|
user = logged_in_api_client.user
|
2018-06-09 13:36:16 +00:00
|
|
|
user.subsonic_api_token = "test"
|
2018-05-09 20:18:33 +00:00
|
|
|
user.save()
|
|
|
|
|
|
|
|
url = reverse(
|
2018-06-09 13:36:16 +00:00
|
|
|
"api:v1:users:users-subsonic-token", kwargs={"username": user.username}
|
|
|
|
)
|
2018-05-09 20:18:33 +00:00
|
|
|
|
|
|
|
response = logged_in_api_client.post(url)
|
|
|
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
user.refresh_from_db()
|
2018-06-09 13:36:16 +00:00
|
|
|
assert user.subsonic_api_token != "test"
|
2018-05-09 20:18:33 +00:00
|
|
|
assert user.subsonic_api_token is not None
|
2018-06-09 13:36:16 +00:00
|
|
|
assert response.data == {"subsonic_api_token": user.subsonic_api_token}
|
2018-05-09 20:18:33 +00:00
|
|
|
|
|
|
|
|
2018-06-10 10:06:46 +00:00
|
|
|
def test_user_can_get_subsonic_token(logged_in_api_client):
|
2018-05-09 20:18:33 +00:00
|
|
|
user = logged_in_api_client.user
|
2018-06-09 13:36:16 +00:00
|
|
|
user.subsonic_api_token = "test"
|
2018-05-09 20:18:33 +00:00
|
|
|
user.save()
|
|
|
|
|
|
|
|
url = reverse(
|
2018-06-09 13:36:16 +00:00
|
|
|
"api:v1:users:users-subsonic-token", kwargs={"username": user.username}
|
|
|
|
)
|
2018-05-09 20:18:33 +00:00
|
|
|
|
|
|
|
response = logged_in_api_client.get(url)
|
|
|
|
|
|
|
|
assert response.status_code == 200
|
2018-06-09 13:36:16 +00:00
|
|
|
assert response.data == {"subsonic_api_token": "test"}
|
2018-05-18 16:48:46 +00:00
|
|
|
|
|
|
|
|
2018-05-09 20:18:33 +00:00
|
|
|
def test_user_can_delete_subsonic_token(logged_in_api_client):
|
|
|
|
user = logged_in_api_client.user
|
2018-06-09 13:36:16 +00:00
|
|
|
user.subsonic_api_token = "test"
|
2018-05-09 20:18:33 +00:00
|
|
|
user.save()
|
|
|
|
|
|
|
|
url = reverse(
|
2018-06-09 13:36:16 +00:00
|
|
|
"api:v1:users:users-subsonic-token", kwargs={"username": user.username}
|
|
|
|
)
|
2018-05-09 20:18:33 +00:00
|
|
|
|
|
|
|
response = logged_in_api_client.delete(url)
|
|
|
|
|
|
|
|
assert response.status_code == 204
|
|
|
|
user.refresh_from_db()
|
|
|
|
assert user.subsonic_api_token is None
|
|
|
|
|
|
|
|
|
2018-06-09 13:36:16 +00:00
|
|
|
@pytest.mark.parametrize("method", ["put", "patch"])
|
|
|
|
def test_user_cannot_patch_another_user(method, logged_in_api_client, factories):
|
|
|
|
user = factories["users.User"]()
|
|
|
|
payload = {"privacy_level": "me"}
|
|
|
|
url = reverse("api:v1:users:users-detail", kwargs={"username": user.username})
|
2018-03-03 10:20:21 +00:00
|
|
|
|
|
|
|
handler = getattr(logged_in_api_client, method)
|
|
|
|
response = handler(url, payload)
|
|
|
|
|
|
|
|
assert response.status_code == 403
|
2018-07-13 12:10:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_user_can_patch_their_own_avatar(logged_in_api_client, avatar):
|
|
|
|
user = logged_in_api_client.user
|
|
|
|
url = reverse("api:v1:users:users-detail", kwargs={"username": user.username})
|
|
|
|
content = avatar.read()
|
|
|
|
avatar.seek(0)
|
|
|
|
payload = {"avatar": avatar}
|
|
|
|
response = logged_in_api_client.patch(url, payload)
|
|
|
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
user.refresh_from_db()
|
|
|
|
|
|
|
|
assert user.avatar.read() == content
|
2018-07-22 10:20:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_creating_user_creates_actor_as_well(
|
|
|
|
api_client, factories, mocker, preferences
|
|
|
|
):
|
|
|
|
actor = factories["federation.Actor"]()
|
|
|
|
url = reverse("rest_register")
|
|
|
|
data = {
|
|
|
|
"username": "test1",
|
|
|
|
"email": "test1@test.com",
|
|
|
|
"password1": "testtest",
|
|
|
|
"password2": "testtest",
|
|
|
|
}
|
|
|
|
preferences["users__registration_enabled"] = True
|
|
|
|
mocker.patch("funkwhale_api.users.models.create_actor", return_value=actor)
|
|
|
|
response = api_client.post(url, data)
|
|
|
|
|
|
|
|
assert response.status_code == 201
|
|
|
|
|
|
|
|
user = User.objects.get(username="test1")
|
|
|
|
|
|
|
|
assert user.actor == actor
|