69 lines
2.3 KiB
Python
69 lines
2.3 KiB
Python
from django.db import transaction
|
|
from django.utils import timezone
|
|
from rest_framework.exceptions import ValidationError
|
|
|
|
from progression.models import RewardTransaction, UserAbility
|
|
|
|
from .models import ContentInteraction, ContentItem, VideoProgress
|
|
|
|
|
|
ABILITY_TO_DIMENSION = {
|
|
ContentItem.Ability.VISION: UserAbility.Dimension.VISION,
|
|
ContentItem.Ability.HUMANITIES: UserAbility.Dimension.HUMANITIES,
|
|
ContentItem.Ability.DETECTION: UserAbility.Dimension.DETECTION,
|
|
ContentItem.Ability.MODELING: UserAbility.Dimension.MODELING,
|
|
ContentItem.Ability.CONNECTION: UserAbility.Dimension.CONNECTION,
|
|
}
|
|
|
|
|
|
@transaction.atomic
|
|
def complete_video(user, content):
|
|
if content.kind != ContentItem.Kind.VIDEO:
|
|
raise ValidationError("只有视频内容可以提交观看完成")
|
|
|
|
progress, _ = VideoProgress.objects.select_for_update().get_or_create(
|
|
user=user,
|
|
content=content,
|
|
)
|
|
progress.position_seconds = max(progress.position_seconds, content.duration_seconds)
|
|
progress.completed = True
|
|
progress.completed_at = progress.completed_at or timezone.now()
|
|
|
|
reward = None
|
|
dimension = ABILITY_TO_DIMENSION.get(content.ability_dimension)
|
|
if dimension and not progress.reward_granted:
|
|
transaction_key = f"video-complete:{content.id}"
|
|
reward_tx, created = RewardTransaction.objects.get_or_create(
|
|
user=user,
|
|
idempotency_key=transaction_key,
|
|
defaults={
|
|
"source": "video_complete",
|
|
"rewards": {"ability": dimension, "fragments": 1},
|
|
},
|
|
)
|
|
if created:
|
|
ability, _ = UserAbility.objects.select_for_update().get_or_create(
|
|
user=user,
|
|
dimension=dimension,
|
|
)
|
|
ability.fragments += 1
|
|
ability.save(update_fields=["fragments"])
|
|
progress.reward_granted = True
|
|
reward = reward_tx.rewards
|
|
|
|
progress.save(
|
|
update_fields=[
|
|
"position_seconds",
|
|
"completed",
|
|
"completed_at",
|
|
"reward_granted",
|
|
"updated_at",
|
|
]
|
|
)
|
|
ContentInteraction.objects.get_or_create(
|
|
user=user,
|
|
content=content,
|
|
action=ContentInteraction.Action.COMPLETE,
|
|
)
|
|
return progress, reward
|