Skip to content

Commit

Permalink
Apply requested changes for PR#4743
Browse files Browse the repository at this point in the history
  • Loading branch information
noliveleger committed Mar 14, 2024
1 parent 76d21ef commit 1f12a60
Show file tree
Hide file tree
Showing 17 changed files with 279 additions and 254 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 3.2.15 on 2023-12-18 18:30
# Generated by Django 3.2.15 on 2024-03-13 20:00

from django.conf import settings
from django.db import migrations, models
Expand All @@ -8,16 +8,15 @@
class Migration(migrations.Migration):

dependencies = [
('project_ownership', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('help', '0003_delete_inappmessagefile_model'),
]

operations = [
migrations.AddField(
model_name='inappmessage',
name='project_ownership_transfer',
field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='project_ownership.transfer'),
name='generic_related_objects',
field=models.JSONField(default=dict),
),
migrations.CreateModel(
name='InAppMessageUsers',
Expand Down
9 changes: 3 additions & 6 deletions kobo/apps/help/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,9 @@ class InAppMessage(AbstractMarkdownxModel):
valid_from = models.DateTimeField(default=EPOCH_BEGINNING)
valid_until = models.DateTimeField(default=EPOCH_BEGINNING)
last_editor = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
project_ownership_transfer = models.ForeignKey(
'project_ownership.Transfer',
null=True,
default=None,
on_delete=models.CASCADE,
)
# We do not want to use a generic foreign key or tightly couple this model
# with another one, so we use JSONField to store related object name and pk
generic_related_objects = models.JSONField(default=dict)

markdown_fields = ['snippet', 'body']

Expand Down
26 changes: 21 additions & 5 deletions kobo/apps/help/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.utils.translation import gettext as t
from rest_framework import serializers

from kobo.apps.project_ownership.models import Transfer
from kpi.utils.object_permission import get_database_user
from .models import InAppMessage, InAppMessageUserInteractions

Expand Down Expand Up @@ -77,22 +78,22 @@ class Meta:
read_only_fields = ('uid',)

def get_title(self, in_app_message: InAppMessage) -> str:
if not in_app_message.project_ownership_transfer:
if not in_app_message.generic_related_objects:
return in_app_message.title
return self._replace_placeholders(in_app_message, in_app_message.title)

def get_snippet(self, in_app_message: InAppMessage) -> str:
if not in_app_message.project_ownership_transfer:
if not in_app_message.generic_related_objects:
return in_app_message.snippet
return self._replace_placeholders(in_app_message, in_app_message.snippet)

def get_body(self, in_app_message: InAppMessage) -> str:
if not in_app_message.project_ownership_transfer:
if not in_app_message.generic_related_objects:
return in_app_message.body
return self._replace_placeholders(in_app_message, in_app_message.body)

def get_html(self, in_app_message: InAppMessage) -> dict:
if not in_app_message.project_ownership_transfer:
if not in_app_message.generic_related_objects:
return in_app_message.html

return {
Expand All @@ -107,10 +108,25 @@ def get_html(self, in_app_message: InAppMessage) -> dict:
def _replace_placeholders(
self, in_app_message: InAppMessage, value: str
) -> str:
if 'transfer' in in_app_message.generic_related_objects:
transfer_identifier = (
f'{Transfer._meta.app_label}.{Transfer._meta.model_name}'
)
transfer_id = in_app_message.generic_related_objects[transfer_identifier]
return self._replace_placeholders_for_transfer(value, transfer_id)

return t(value)

def _replace_placeholders_for_transfer(self, value: str, transfer_id: int):
request = self.context['request']
user = get_database_user(request.user)
transfer = in_app_message.project_ownership_transfer
value = t(value)

try:
transfer = Transfer.objects.get(pk=transfer_id)
except Transfer.DoesNotExist:
return value

value = value.replace('##username##', user.username)
value = value.replace('##project_name##', transfer.asset.name)
value = value.replace('##previous_owner##', transfer.invite.sender.username)
Expand Down
2 changes: 1 addition & 1 deletion kobo/apps/help/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,4 @@ def get_queryset(self):
Q(inappmessageusers__isnull=True) | Q(inappmessageusers__user=user),
valid_from__lte=timezone.now(),
valid_until__gte=timezone.now(),
).select_related('project_ownership_transfer').order_by('-pk')
).order_by('-pk')
8 changes: 4 additions & 4 deletions kobo/apps/project_ownership/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 3.2.15 on 2023-12-13 15:37
# Generated by Django 3.2.15 on 2024-03-13 20:01

from django.conf import settings
from django.db import migrations, models
Expand All @@ -23,7 +23,7 @@ class Migration(migrations.Migration):
('date_created', models.DateTimeField(default=django.utils.timezone.now)),
('date_modified', models.DateTimeField(default=django.utils.timezone.now)),
('uid', kpi.fields.kpi_uid.KpiUidField(_null=False, uid_prefix='poi')),
('status', models.CharField(choices=[('accepted', 'ACCEPTED'), ('cancelled', 'CANCELLED'), ('complete', 'COMPLETE'), ('declined', 'DECLINED'), ('failed', 'FAILED'), ('in_progress', 'IN PROGRESS'), ('pending', 'PENDING')], db_index=True, default='pending', max_length=11)),
('status', models.CharField(choices=[('accepted', 'Accepted'), ('cancelled', 'Cancelled'), ('complete', 'Complete'), ('declined', 'Declined'), ('expired', 'Expired'), ('failed', 'Failed'), ('in_progress', 'In Progress'), ('pending', 'Pending')], db_index=True, default='pending', max_length=11)),
('recipient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_ownership_responses', to=settings.AUTH_USER_MODEL)),
('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_ownership_requests', to=settings.AUTH_USER_MODEL)),
],
Expand Down Expand Up @@ -51,8 +51,8 @@ class Migration(migrations.Migration):
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('date_created', models.DateTimeField(default=django.utils.timezone.now)),
('date_modified', models.DateTimeField(default=django.utils.timezone.now)),
('status', models.CharField(choices=[('cancelled', 'CANCELLED'), ('failed', 'FAILED'), ('in_progress', 'IN PROGRESS'), ('pending', 'PENDING'), ('success', 'SUCCESS')], db_index=True, default='pending', max_length=11)),
('status_type', models.CharField(choices=[('attachments', 'ATTACHMENTS'), ('media_files', 'MEDIA_FILES'), ('global', 'GLOBAL'), ('submissions', 'SUBMISSIONS')], db_index=True, default='global', max_length=11)),
('status', models.CharField(choices=[('cancelled', 'Cancelled'), ('failed', 'Failed'), ('in_progress', 'In Progress'), ('pending', 'Pending'), ('success', 'Success')], db_index=True, default='pending', max_length=11)),
('status_type', models.CharField(choices=[('attachments', 'Attachments'), ('media_files', 'Media Files'), ('global', 'Global'), ('submissions', 'Submissions')], db_index=True, default='global', max_length=11)),
('error', models.TextField(null=True)),
('transfer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='statuses', to='project_ownership.transfer')),
],
Expand Down
18 changes: 0 additions & 18 deletions kobo/apps/project_ownership/models/base.py

This file was deleted.

41 changes: 17 additions & 24 deletions kobo/apps/project_ownership/models/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,28 @@

class InviteStatusChoices(models.TextChoices):

ACCEPTED = 'accepted', 'ACCEPTED'
CANCELLED = 'cancelled', 'CANCELLED'
COMPLETE = 'complete', 'COMPLETE'
DECLINED = 'declined', 'DECLINED'
EXPIRED = 'expired', 'EXPIRED'
FAILED = 'failed', 'FAILED'
IN_PROGRESS = 'in_progress', 'IN PROGRESS'
PENDING = 'pending', 'PENDING'
ACCEPTED = 'accepted'
CANCELLED = 'cancelled'
COMPLETE = 'complete'
DECLINED = 'declined'
EXPIRED = 'expired'
FAILED = 'failed'
IN_PROGRESS = 'in_progress'
PENDING = 'pending'


class TransferStatusChoices(models.TextChoices):

CANCELLED = 'cancelled', 'CANCELLED'
FAILED = 'failed', 'FAILED'
IN_PROGRESS = 'in_progress', 'IN PROGRESS'
PENDING = 'pending', 'PENDING'
SUCCESS = 'success', 'SUCCESS'
CANCELLED = 'cancelled'
FAILED = 'failed'
IN_PROGRESS = 'in_progress'
PENDING = 'pending'
SUCCESS = 'success'


class TransferStatusTypeChoices(models.TextChoices):

ATTACHMENTS = 'attachments', 'ATTACHMENTS'
MEDIA_FILES = 'media_files', 'MEDIA_FILES'
GLOBAL = 'global', 'GLOBAL'
SUBMISSIONS = 'submissions', 'SUBMISSIONS'

@classmethod
def default_statuses_dict(cls):
_default_dict = {}
for value in cls.values:
_default_dict[value] = TransferStatusChoices.PENDING.value
return _default_dict
ATTACHMENTS = 'attachments'
MEDIA_FILES = 'media_files'
GLOBAL = 'global'
SUBMISSIONS = 'submissions'
48 changes: 11 additions & 37 deletions kobo/apps/project_ownership/models/invite.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
from __future__ import annotations

from django.conf import settings
from django.db import models, transaction
from django.db import models
from django.utils import timezone

from kpi.fields import KpiUidField
from .base import TimeStampedModel
from .choices import InviteStatusChoices, TransferStatusChoices
from ..tasks import send_email_to_admins
from .choices import InviteStatusChoices


class Invite(TimeStampedModel):
class Invite(models.Model):

uid = KpiUidField(uid_prefix='poi')
sender = models.ForeignKey(
Expand All @@ -29,6 +27,8 @@ class Invite(TimeStampedModel):
default=InviteStatusChoices.PENDING,
db_index=True
)
date_created = models.DateTimeField(default=timezone.now)
date_modified = models.DateTimeField(default=timezone.now)

class Meta:
verbose_name = 'project ownership transfer invite'
Expand All @@ -37,37 +37,11 @@ def __str__(self):
return (
f'from {self.sender.username} to '
f'{self.recipient.username} '
f'({InviteStatusChoices(self.status).value})'
f'({InviteStatusChoices(self.status)})'
)

def update_status_from_transfers(self):
with transaction.atomic():
invite = self.__class__.objects.select_for_update().get(
pk=self.pk
)
previous_status = invite.status
is_complete = True

# One of the transfers has begun, mark the invite as `in_progress`
if invite.status == InviteStatusChoices.PENDING.value:
invite.status = InviteStatusChoices.IN_PROGRESS.value

for transfer in self.transfers.all():
if transfer.status == TransferStatusChoices.FAILED.value:
invite.status = InviteStatusChoices.FAILED.value
is_complete = False
break
elif transfer.status != TransferStatusChoices.SUCCESS.value:
is_complete = False

if is_complete:
invite.status = InviteStatusChoices.COMPLETE.value

if previous_status != invite.status:
invite.date_modified = timezone.now()
invite.save(update_fields=['status', 'date_modified'])
if invite.status == InviteStatusChoices.FAILED.value:
send_email_to_admins.delay(invite.uid)

if previous_status != invite.status:
self.refresh_from_db()
def save(self, *args, **kwargs):
update_fields = kwargs.get('update_fields', {})
if not update_fields or 'date_modified' in update_fields:
self.date_modified = timezone.now()
super().save(*args, **kwargs)
Loading

0 comments on commit 1f12a60

Please sign in to comment.