Skip to content

Commit

Permalink
Merge pull request #287 from aiarena/staging
Browse files Browse the repository at this point in the history
Release v1.4.2
  • Loading branch information
lladdy authored Jul 12, 2021
2 parents e1e6c1e + aa8a04c commit d31aa48
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 23 deletions.
4 changes: 2 additions & 2 deletions aiarena/core/management/commands/seed.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

from aiarena import settings
from aiarena.core.models import User, Map, Bot, News, \
CompetitionParticipation, MapPool
CompetitionParticipation, MapPool, WebsiteUser
from aiarena.core.tests.testing_utils import TestingClient
from aiarena.core.tests.tests import BaseTestMixin
from aiarena.core.utils import EnvironmentType

def run_seed(matches, token):
devadmin = User.objects.create_superuser(username='devadmin', password='x', email='[email protected]')
devadmin = WebsiteUser.objects.create_superuser(username='devadmin', password='x', email='[email protected]')

client = TestingClient()
client.login(devadmin)
Expand Down
38 changes: 38 additions & 0 deletions aiarena/core/migrations/0029_websiteuser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Generated by Django 3.0.14 on 2021-05-05 22:40

from django.conf import settings
import django.contrib.auth.models
from django.db import migrations, models
import django.db.models.deletion


def migrate_website_users(apps, schema_editor):
User = apps.get_model('core', 'User')
WebsiteUser = apps.get_model('core', 'WebsiteUser')
for website_user in User.objects.filter(type='WEBSITE_USER'):
website_user.__class__ = WebsiteUser # convert to new class
website_user.save()

class Migration(migrations.Migration):

dependencies = [
('core', '0028_auto_20210419_2336'),
]

operations = [
migrations.CreateModel(
name='WebsiteUser',
fields=[
('user_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)),
('single_use_match_requests', models.IntegerField(blank=True, default=0)),
],
options={
'verbose_name': 'WebsiteUser',
},
bases=('core.user',),
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
migrations.RunPython(migrate_website_users),
]
3 changes: 2 additions & 1 deletion aiarena/core/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
from .relative_result import RelativeResult
from .result import Result
from .round import Round
from .tag import Tag
from .trophy import Trophy
from .trophy import TrophyIcon
from .tag import Tag
from .user import User
from .website_user import WebsiteUser
18 changes: 13 additions & 5 deletions aiarena/core/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@

from constance import config
from django.contrib.auth.models import AbstractUser
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.urls import reverse
from django.utils import timezone
from django.utils.functional import cached_property
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.functional import cached_property

from django.utils.translation import gettext_lazy as _

from aiarena.core.models.mixins import LockableModelMixin

logger = logging.getLogger(__name__)


class User(AbstractUser):
class User(AbstractUser, LockableModelMixin):
PATREON_LEVELS = (
('none', 'None'),
('bronze', 'Bronze'),
Expand Down Expand Up @@ -120,9 +121,16 @@ def is_arenaclient(self):
except ArenaClient.DoesNotExist:
return False

@property
def is_websiteuser(self):
from .website_user import WebsiteUser # avoid circular reference
try:
return (self.websiteuser is not None)
except WebsiteUser.DoesNotExist:
return False


@receiver(pre_save, sender=User)
def pre_save_user(sender, instance, **kwargs):
if instance.type != 'WEBSITE_USER':
if not instance.is_websiteuser:
instance.set_unusable_password()
35 changes: 35 additions & 0 deletions aiarena/core/models/website_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import logging

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

from .user import User

logger = logging.getLogger(__name__)


class WebsiteUser(User):
"""Represents a website user/bot author"""
single_use_match_requests = models.IntegerField(default=0, blank=True)
"""UNUSED AS OF YET"""
"""Single-use match requests that go on top of any periodic match requests a user might have.
Periodic match requests are used first before these."""

@property
def requested_matches_limit(self):
return self.REQUESTED_MATCHES_LIMIT_MAP[self.patreon_level] + self.extra_periodic_match_requests

@property
def match_request_count_left(self):
from .match import Match
from .result import Result
return self.requested_matches_limit \
- Match.objects.only('id').filter(requested_by=self,
created__gte=timezone.now() - config.REQUESTED_MATCHES_LIMIT_PERIOD).count() \
+ Result.objects.only('id').filter(submitted_by=self, type='MatchCancelled',
created__gte=timezone.now() - config.REQUESTED_MATCHES_LIMIT_PERIOD).count()


class Meta:
verbose_name = 'WebsiteUser'
24 changes: 12 additions & 12 deletions aiarena/core/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from aiarena.core.api import Matches
from aiarena.core.management.commands import cleanupreplays
from aiarena.core.models import User, Bot, Map, Match, Result, MatchParticipation, Competition, Round, ArenaClient, \
CompetitionParticipation, MapPool, MatchTag, Tag
CompetitionParticipation, MapPool, WebsiteUser, Tag
from aiarena.core.models.game_mode import GameMode
from aiarena.core.utils import calculate_md5

Expand Down Expand Up @@ -307,11 +307,11 @@ def _generate_extra_bots(self):


def _generate_extra_users(self):
self.regularUser2 = User.objects.create_user(username='regular_user2', password='x',
self.regularUser2 = WebsiteUser.objects.create_user(username='regular_user2', password='x',
email='[email protected]')
self.regularUser3 = User.objects.create_user(username='regular_user3', password='x',
self.regularUser3 = WebsiteUser.objects.create_user(username='regular_user3', password='x',
email='[email protected]')
self.regularUser4 = User.objects.create_user(username='regular_user4', password='x',
self.regularUser4 = WebsiteUser.objects.create_user(username='regular_user4', password='x',
email='[email protected]')


Expand All @@ -323,7 +323,7 @@ class LoggedInMixin(BaseTestMixin):

def setUp(self):
super().setUp()
self.staffUser1 = User.objects.create_user(username='staff_user', password='x',
self.staffUser1 = WebsiteUser.objects.create_user(username='staff_user', password='x',
email='[email protected]',
is_staff=True,
is_superuser=True,
Expand All @@ -333,7 +333,7 @@ def setUp(self):
type='ARENA_CLIENT', trusted=True, owner=self.staffUser1)
Token.objects.create(user=self.arenaclientUser1)

self.regularUser1 = User.objects.create_user(username='regular_user1', password='x',
self.regularUser1 = WebsiteUser.objects.create_user(username='regular_user1', password='x',
email='[email protected]')


Expand Down Expand Up @@ -489,7 +489,7 @@ def _send_tags(self, bot1_tags, bot2_tags, results_resp_code=201):
def test_results_with_tags(self):
az_symbols = 'abcdefghijklmnopqrstuvwxyz'
num_symbols = '0123456789'
extra_symbols = ' _ _ '
extra_symbols = ' _ _ '
game_mode = GameMode.objects.first()

self.client.force_login(self.arenaclientUser1)
Expand All @@ -505,14 +505,14 @@ def test_results_with_tags(self):
match_tags = Match.objects.get(id=match_response.data['id']).tags.all()
self.assertTrue(match_tags.count()==1)
for mt in match_tags:
self.assertEqual(mt.user, self.staffUser1)
self.assertEqual(mt.user.websiteuser, self.staffUser1)

Matches.request_match(self.staffUser1, self.staffUser1Bot2, self.regularUser1Bot1, game_mode=game_mode)
match_response, result_response = self._send_tags(None, ['abc'])
match_tags = Match.objects.get(id=match_response.data['id']).tags.all()
self.assertTrue(match_tags.count()==1)
for mt in match_tags:
self.assertEqual(mt.user, self.regularUser1)
self.assertEqual(mt.user.websiteuser, self.regularUser1)

# Check that tags are correct, stripped and attributed to the correct user
_temp_tag1 = 'tes1t_ test2'
Expand Down Expand Up @@ -562,7 +562,7 @@ def test_results_with_tags(self):
# This is to prevent tags from causing a result to fail submission
Matches.request_match(self.staffUser1, self.staffUser1Bot2, self.regularUser1Bot1, game_mode=game_mode)
match_response, result_response = self._send_tags(
bot1_tags=['!', '2', 'A', '', az_symbols+num_symbols+extra_symbols],
bot1_tags=['!', '2', 'A', '', az_symbols+num_symbols+extra_symbols],
bot2_tags=['123']
)
match_tags = Match.objects.get(id=match_response.data['id']).tags.all()
Expand All @@ -572,13 +572,13 @@ def test_results_with_tags(self):
# Too many tags
Matches.request_match(self.staffUser1, self.staffUser1Bot2, self.regularUser1Bot1, game_mode=game_mode)
match_response, result_response = self._send_tags(
bot1_tags=[str(i) for i in range(50)],
bot1_tags=[str(i) for i in range(50)],
bot2_tags=[str(i) for i in range(50)]
)
match_tags = Match.objects.get(id=match_response.data['id']).tags.all()
self.assertTrue(match_tags.count()==64)




class CompetitionsTestCase(FullDataSetMixin, TransactionTestCase):
Expand Down
37 changes: 36 additions & 1 deletion aiarena/frontend/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from aiarena.core.models import ArenaClient, Bot, Map, Match, MatchParticipation, Result, Round, Competition, \
CompetitionBotMatchupStats, CompetitionParticipation, Trophy, TrophyIcon, User, News, MapPool, MatchTag, Tag, \
ArenaClientStatus
ArenaClientStatus, WebsiteUser
from aiarena.core.models.game import Game
from aiarena.core.models.game_mode import GameMode
from aiarena.patreon.models import PatreonAccountBind
Expand Down Expand Up @@ -409,3 +409,38 @@ class UserAdmin(admin.ModelAdmin):
'can_request_games_for_another_authors_bot',
)
raw_id_fields = ('groups', 'user_permissions')


@admin.register(WebsiteUser)
class WebsiteUserAdmin(admin.ModelAdmin):
search_fields = ('username',)
list_display = (
'id',
'password',
'last_login',
'is_superuser',
'username',
'first_name',
'last_name',
'is_staff',
'is_active',
'date_joined',
'email',
'patreon_level',
'type',
'extra_active_competition_participations',
'extra_periodic_match_requests',
'receive_email_comms',
'can_request_games_for_another_authors_bot',
'single_use_match_requests'
)
list_filter = (
'last_login',
'is_superuser',
'is_staff',
'is_active',
'date_joined',
'receive_email_comms',
'can_request_games_for_another_authors_bot',
)
raw_id_fields = ('groups', 'user_permissions')
2 changes: 1 addition & 1 deletion aiarena/frontend/templates/500.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

{% block content %}
<div class="divider"><span></span><span><h2>Whoops...</h2></span><span></span></div>
<div id="inner_content"><center>There was some error ¯\_(ツ)_/¯</center></div>
<div id="inner_content"><center>There was some error ¯\_(ツ)_/¯<br/><br/>Please contact our staff if this issue continues so we can investigate.</center></div>
{% endblock %}
2 changes: 1 addition & 1 deletion aiarena/frontend/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -986,7 +986,7 @@ def _get_map(self, form):
def form_valid(self, form):
if config.ALLOW_REQUESTED_MATCHES:
if form.cleaned_data['bot1'] != form.cleaned_data['bot2']:
if self.request.user.match_request_count_left >= form.cleaned_data['match_count']:
if self.request.user.websiteuser.match_request_count_left >= form.cleaned_data['match_count']:

with transaction.atomic(): # do this all in one commit
match_list = []
Expand Down

0 comments on commit d31aa48

Please sign in to comment.