Skip to content

Commit

Permalink
Merge pull request #593 from aiarena/staging
Browse files Browse the repository at this point in the history
Release v1.10.6
  • Loading branch information
lladdy authored Jun 24, 2023
2 parents 3944132 + 8150284 commit b78a5ba
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 15 deletions.
4 changes: 3 additions & 1 deletion aiarena/core/api/matches.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ def start_match(match: Match, arenaclient: ArenaClient) -> bool:
.get(competition=match.round.competition).elo
p.save()

match.started = timezone.now()
now = timezone.now()
match.started = now
match.first_started = now
match.assigned_to = arenaclient
match.save()
return True
Expand Down
1 change: 1 addition & 0 deletions aiarena/core/models/match.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class Match(models.Model, LockableModelMixin, RandomManagerMixin):
""" Represents a match between 2 bots. Usually this is within the context of a round, but doesn't have to be. """
map = models.ForeignKey(Map, on_delete=models.PROTECT)
created = models.DateTimeField(auto_now_add=True, db_index=True)
# todo: the functionality of the started and first_started fields does not appear to be fully implemented
started = models.DateTimeField(blank=True, null=True, editable=False, db_index=True)
first_started = models.DateTimeField(blank=True, null=True, editable=False, db_index=True)
"""The first time this match started. Different from the started field when multiple runs are attempted."""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.2.16 on 2023-06-05 03:19

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('patreon', '0006_patreonaccountbind_last_refresh_attempt_current_user_json'),
]

operations = [
migrations.AddField(
model_name='patreonaccountbind',
name='last_had_pledge',
field=models.DateTimeField(blank=True, null=True),
),
]
46 changes: 32 additions & 14 deletions aiarena/patreon/models.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import logging

from constance import config
from django.db import models
from django.utils import timezone

from aiarena.core.models import User
from aiarena.patreon.patreon import PatreonOAuth, PatreonApi

logger = logging.getLogger(__name__)

from django.db import models


class PatreonAccountBind(models.Model):
DAYS_GRACE_PERIOD = 7
"""The number of days after the patreon subscription expires that the user will still be considered a patron.
This is to account for the fact that the patreon API appears to randomly return 'none' for users that are still
patrons"""

user = models.OneToOneField(User, on_delete=models.CASCADE, blank=True, null=True)
access_token = models.CharField(max_length=64)
refresh_token = models.CharField(max_length=64)
Expand All @@ -27,6 +31,9 @@ class PatreonAccountBind(models.Model):
"""The user id of the patreon user"""
last_refresh_attempt_current_user_json = models.TextField(blank=True, null=True)
"""The JSON returned from Patreon's current_user endpoint on the last refresh attempt."""
last_had_pledge = models.DateTimeField(blank=True, null=True)
"""The datetime when the patreon API last return a pledge for this user.
This is used in order to give a grace period before removing a user's patreon level."""

def update_tokens(self):
self.last_token_refresh_attempt = timezone.now()
Expand All @@ -45,37 +52,48 @@ def update_user_patreon_tier(self):
api_client = PatreonApi(self.access_token)

user = api_client.current_user()
logger.info(f"Refreshing patreon for user {self.user.id} {self.user.username}")
self.last_refresh_attempt_current_user_json = str(user)

patreon_level = 'none'
if self.has_pledge(user):
patreon_level = self.get_pledge_reward_name(user, self.get_pledge_reward_id(user)).lower()

self.user.patreon_level = patreon_level
self.user.save()

self.patreon_user_id = self.get_patreon_user_id(user)
if self._has_pledge(user):
pledge = self._get_pledge_reward_name(user, self._get_pledge_reward_id(user)).lower()
logger.info(f"Pledge found: {pledge}")
self.user.patreon_level = pledge
self.user.save()
self.last_had_pledge = timezone.now()
# If the user has an existing patreon level but no pledge,
# then if we're past the grace period, remove the level.
elif self.user.patreon_level != 'none' and self._is_past_the_grace_period():
logger.info(f"Pledge not found: setting to none")
self.user.patreon_level = 'none'
self.user.save()

self.patreon_user_id = self._get_patreon_user_id(user)
self.save()
logger.info(f"Patreon user id: {self.patreon_user_id}")

def _is_past_the_grace_period(self):
return self.last_had_pledge is None or (timezone.now() - self.last_had_pledge).days > self.DAYS_GRACE_PERIOD

def has_pledge(self, user) -> bool:
def _has_pledge(self, user) -> bool:
if 'included' in user:
for entry in user['included']:
if entry['type'] == 'pledge':
return True
return False

def get_pledge_reward_id(self, user) -> str:
def _get_pledge_reward_id(self, user) -> str:
for entry in user['included']:
if entry['type'] == 'pledge':
return entry['relationships']['reward']['data']['id']
raise Exception('Unable to locate reward for pledge.')

def get_patreon_user_id(self, user) -> str:
def _get_patreon_user_id(self, user) -> str:
if 'data' in user and 'id' in user['data']:
return user['data']['id']
return None

def get_pledge_reward_name(self, user, id: str) -> str:
def _get_pledge_reward_name(self, user, id: str) -> str:
for entry in user['included']:
if entry['type'] == 'reward' and entry['id'] == id:
return entry['attributes']['title']
Expand Down

0 comments on commit b78a5ba

Please sign in to comment.