Merge branch 'stable' into develop
This commit is contained in:
commit
0602de6d81
16 changed files with 155 additions and 21 deletions
|
|
@ -1,4 +1,4 @@
|
|||
__version__ = "1.2.8"
|
||||
__version__ = "1.2.9"
|
||||
__version_info__ = tuple(
|
||||
[
|
||||
int(num) if num.isdigit() else num
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ def get_spa_file(spa_url, name):
|
|||
utils.join_url(spa_url, name),
|
||||
)
|
||||
response.raise_for_status()
|
||||
response.encoding = "utf-8"
|
||||
content = response.text
|
||||
caches["local"].set(cache_key, content, settings.FUNKWHALE_SPA_HTML_CACHE_DURATION)
|
||||
return content
|
||||
|
|
|
|||
|
|
@ -30,8 +30,11 @@ def verify_date(raw_date):
|
|||
delta = datetime.timedelta(seconds=DATE_HEADER_VALID_FOR)
|
||||
now = timezone.now()
|
||||
if dt < now - delta or dt > now + delta:
|
||||
logger.debug(
|
||||
f"Request Date {raw_date} is too too far in the future or in the past"
|
||||
)
|
||||
raise forms.ValidationError(
|
||||
f"Request Date {raw_date} is too far in the future or in the past"
|
||||
"Request Date is too far in the future or in the past"
|
||||
)
|
||||
|
||||
return dt
|
||||
|
|
|
|||
|
|
@ -98,12 +98,28 @@ class ManageUserSerializer(serializers.ModelSerializer):
|
|||
class ManageInvitationSerializer(serializers.ModelSerializer):
|
||||
users = ManageUserSimpleSerializer(many=True, required=False)
|
||||
owner = ManageUserSimpleSerializer(required=False)
|
||||
invited_user = ManageUserSimpleSerializer(required=False)
|
||||
code = serializers.CharField(required=False, allow_null=True)
|
||||
|
||||
class Meta:
|
||||
model = users_models.Invitation
|
||||
fields = ("id", "owner", "code", "expiration_date", "creation_date", "users")
|
||||
read_only_fields = ["id", "expiration_date", "owner", "creation_date", "users"]
|
||||
fields = (
|
||||
"id",
|
||||
"owner",
|
||||
"invited_user",
|
||||
"code",
|
||||
"expiration_date",
|
||||
"creation_date",
|
||||
"users",
|
||||
)
|
||||
read_only_fields = [
|
||||
"id",
|
||||
"expiration_date",
|
||||
"owner",
|
||||
"invited_user",
|
||||
"creation_date",
|
||||
"users",
|
||||
]
|
||||
|
||||
def validate_code(self, value):
|
||||
if not value:
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class Command(BaseCommand):
|
|||
|
||||
@transaction.atomic
|
||||
def handle(self, *args, **options):
|
||||
skipped = models.Uploads.objects.filter(import_status="skipped")
|
||||
skipped = models.Upload.objects.filter(import_status="skipped")
|
||||
count = len(skipped)
|
||||
if options["force"]:
|
||||
skipped.delete()
|
||||
|
|
|
|||
|
|
@ -668,8 +668,12 @@ class UploadQuerySet(common_models.NullsLastQuerySet):
|
|||
libraries = Library.objects.viewable_by(actor)
|
||||
|
||||
if include:
|
||||
return self.filter(library__in=libraries, import_status="finished")
|
||||
return self.exclude(library__in=libraries, import_status="finished")
|
||||
return self.filter(
|
||||
library__in=libraries, import_status__in=["finished", "skipped"]
|
||||
)
|
||||
return self.exclude(
|
||||
library__in=libraries, import_status__in=["finished", "skipped"]
|
||||
)
|
||||
|
||||
def local(self, include=True):
|
||||
query = models.Q(library__actor__domain_id=settings.FEDERATION_HOSTNAME)
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ class InvitationFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
|
|||
|
||||
class Params:
|
||||
expired = factory.Trait(expiration_date=factory.LazyFunction(timezone.now))
|
||||
with_invited_user = factory.Trait(
|
||||
invited_user=factory.SubFactory("funkwhale_api.users.factories.UserFactory")
|
||||
)
|
||||
|
||||
|
||||
class PasswordSetter(factory.PostGenerationMethodCall):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
# Generated by Django 3.2.16 on 2022-11-19 18:19
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
def update_invitation_table(apps, schema_editor):
|
||||
User = apps.get_model("users", "User")
|
||||
Invitation = apps.get_model("users", "Invitation")
|
||||
for user in User.objects.all():
|
||||
if user.invitation:
|
||||
Invitation.objects.filter(id=user.invitation.id).update(invited_user_id=user.id)
|
||||
|
||||
|
||||
def rewind(*args, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0021_auto_20210703_1810'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='invitation',
|
||||
name='invited_user',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='user_invitations', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='invitation',
|
||||
name='owner',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='invitations', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.RunPython(update_invitation_table, rewind),
|
||||
]
|
||||
|
|
@ -335,6 +335,9 @@ class Invitation(models.Model):
|
|||
owner = models.ForeignKey(
|
||||
User, related_name="invitations", on_delete=models.CASCADE
|
||||
)
|
||||
invited_user = models.ForeignKey(
|
||||
User, related_name="user_invitations", null=True, on_delete=models.CASCADE
|
||||
)
|
||||
code = models.CharField(max_length=50, unique=True)
|
||||
|
||||
objects = InvitationQuerySet.as_manager()
|
||||
|
|
@ -349,6 +352,10 @@ class Invitation(models.Model):
|
|||
|
||||
return super().save(**kwargs)
|
||||
|
||||
def set_invited_user(self, user):
|
||||
self.invited_user = user
|
||||
super().save()
|
||||
|
||||
|
||||
class Application(oauth2_models.AbstractApplication):
|
||||
scope = models.TextField(blank=True)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,9 @@ class RegisterView(registration_views.RegisterView):
|
|||
if not user.is_active:
|
||||
# manual approval, we need to send the confirmation e-mail by hand
|
||||
authentication.send_email_confirmation(self.request, user)
|
||||
if user.invitation:
|
||||
user.invitation.set_invited_user(user)
|
||||
|
||||
return user
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -211,7 +211,8 @@ def test_library(factories):
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"status,expected", [("pending", False), ("errored", False), ("finished", True)]
|
||||
"status,expected",
|
||||
[("pending", False), ("errored", False), ("finished", True), ("skipped", True)],
|
||||
)
|
||||
def test_playable_by_correct_status(status, expected, factories):
|
||||
upload = factories["music.Upload"](
|
||||
|
|
|
|||
|
|
@ -105,6 +105,13 @@ def test_invitation_generates_random_code_on_save(factories):
|
|||
assert len(invitation.code) >= 6
|
||||
|
||||
|
||||
def test_invitation_get_deleted_when_user_is_deleted(factories):
|
||||
invitation = factories["users.Invitation"](with_invited_user=True)
|
||||
invitation.invited_user.delete()
|
||||
|
||||
assert models.Invitation.objects.count() == 0
|
||||
|
||||
|
||||
def test_invitation_expires_after_delay(factories, settings):
|
||||
delay = settings.USERS_INVITATION_EXPIRATION_DAYS
|
||||
invitation = factories["users.Invitation"]()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue