Added InviteCode system
This commit is contained in:
parent
d91681a7ec
commit
3d98f297d9
@ -31,7 +31,7 @@ def load_insecure_key():
|
|||||||
|
|
||||||
SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY") or load_insecure_key()
|
SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY") or load_insecure_key()
|
||||||
|
|
||||||
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ") or "*"
|
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "*").split(" ")
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.admin import UserAdmin
|
from django.contrib.auth.admin import UserAdmin
|
||||||
|
|
||||||
from .models import Player, Log
|
from .models import Player, Log, InviteCode
|
||||||
|
|
||||||
admin.site.register(Log)
|
admin.site.register(Log)
|
||||||
admin.site.register(Player)
|
admin.site.register(Player)
|
||||||
|
admin.site.register(InviteCode)
|
||||||
@ -8,7 +8,7 @@ from crispy_forms.helper import FormHelper
|
|||||||
from crispy_forms.layout import Submit
|
from crispy_forms.layout import Submit
|
||||||
|
|
||||||
from users.models import Player
|
from users.models import Player
|
||||||
from users.validators import usernameValidator, username_change_validator
|
from users.validators import username_validator, username_change_validator, invitecode_validator
|
||||||
from bloonsa_game.models import Config as BloonsaConfig
|
from bloonsa_game.models import Config as BloonsaConfig
|
||||||
|
|
||||||
class UserRegisterForm(UserCreationForm):
|
class UserRegisterForm(UserCreationForm):
|
||||||
@ -23,12 +23,20 @@ class UserRegisterForm(UserCreationForm):
|
|||||||
self.helper.form_action = '/users/register'
|
self.helper.form_action = '/users/register'
|
||||||
self.helper.add_input(Submit('submit', 'Create'))
|
self.helper.add_input(Submit('submit', 'Create'))
|
||||||
|
|
||||||
|
invite_code = forms.CharField(max_length=64,
|
||||||
|
label="invite_code",
|
||||||
|
empty_value="code",
|
||||||
|
# help_text="",
|
||||||
|
required=True,
|
||||||
|
validators=[invitecode_validator,])
|
||||||
|
|
||||||
username = forms.CharField(min_length=3,
|
username = forms.CharField(min_length=3,
|
||||||
max_length=16,
|
max_length=16,
|
||||||
label="Username",
|
label="Username",
|
||||||
required=True,
|
required=True,
|
||||||
validators=[usernameValidator,],
|
validators=[username_validator,],
|
||||||
help_text=_("3-16 chars, alphanumeric and _- pls"))
|
#help_text=_("3-16 chars, alphanumeric and _- pls")
|
||||||
|
)
|
||||||
|
|
||||||
password1 = forms.CharField(
|
password1 = forms.CharField(
|
||||||
label="Password",
|
label="Password",
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
# Generated by Django 5.1.6 on 2025-02-20 21:11
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('users', '0025_alter_player_avatar'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='InviteCode',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('title', models.TextField(max_length=64)),
|
||||||
|
('code', models.TextField(max_length=64)),
|
||||||
|
('active', models.BooleanField(default=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='log',
|
||||||
|
name='action',
|
||||||
|
field=models.IntegerField(choices=[(0, 'Logged in'), (1, 'Registered'), (2, 'Logged out'), (3, 'Edited account settings'), (100, 'Loaded a level via ingame ID box'), (101, 'Loaded a level via URL'), (102, 'Loaded a random level'), (103, 'Submitted a score on level_id'), (104, 'Rated a level')]),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='player',
|
||||||
|
name='invite_code',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='users.invitecode'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -4,10 +4,18 @@ from django.contrib.auth.models import User
|
|||||||
from django_resized import ResizedImageField
|
from django_resized import ResizedImageField
|
||||||
|
|
||||||
|
|
||||||
|
class InviteCode(models.Model):
|
||||||
|
title = models.TextField(max_length=64)
|
||||||
|
code = models.TextField(max_length=64)
|
||||||
|
active = models.BooleanField(default=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.title} | code: {self.code}"
|
||||||
|
|
||||||
class Player(models.Model):
|
class Player(models.Model):
|
||||||
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="player")
|
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="player")
|
||||||
# Profile
|
# Profile
|
||||||
bio = models.TextField(max_length=128, null=True)
|
bio = models.TextField(max_length=128, null=True, blank=True)
|
||||||
avatar = ResizedImageField(default="defaults/avatars.jpg",
|
avatar = ResizedImageField(default="defaults/avatars.jpg",
|
||||||
size=[256, 256],
|
size=[256, 256],
|
||||||
upload_to="avatars",
|
upload_to="avatars",
|
||||||
@ -21,6 +29,7 @@ class Player(models.Model):
|
|||||||
creation_date = models.DateTimeField(default=timezone.now)
|
creation_date = models.DateTimeField(default=timezone.now)
|
||||||
latest_activity = models.DateTimeField(default=timezone.now)
|
latest_activity = models.DateTimeField(default=timezone.now)
|
||||||
suspected_cheater = models.BooleanField(default=False) # This should be set when tripping the anti-cheat
|
suspected_cheater = models.BooleanField(default=False) # This should be set when tripping the anti-cheat
|
||||||
|
invite_code = models.ForeignKey(InviteCode, null=True, blank=True, on_delete=models.CASCADE)
|
||||||
# States
|
# States
|
||||||
suspended = models.BooleanField(default=False) # This is a shadow-ban, stats will still save but not all will show up on leaderboards
|
suspended = models.BooleanField(default=False) # This is a shadow-ban, stats will still save but not all will show up on leaderboards
|
||||||
banned = models.BooleanField(default=False) # Account gets logged out upon logging in
|
banned = models.BooleanField(default=False) # Account gets logged out upon logging in
|
||||||
@ -50,6 +59,8 @@ class Player(models.Model):
|
|||||||
return f"{states}{self.user} - {self.latest_ip}".strip(" ")
|
return f"{states}{self.user} - {self.latest_ip}".strip(" ")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Log(models.Model):
|
class Log(models.Model):
|
||||||
class Actions(models.IntegerChoices):
|
class Actions(models.IntegerChoices):
|
||||||
login = 0, "Logged in"
|
login = 0, "Logged in"
|
||||||
@ -68,4 +79,5 @@ class Log(models.Model):
|
|||||||
note = models.TextField(null=True)
|
note = models.TextField(null=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.player.user.username} - {self.get_action_display()} <{self.note or ''}>"
|
return f"{self.player.user.username} - {self.get_action_display()} <{self.note or ''}>"
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,9 @@ class BloonsaUtil:
|
|||||||
if not request.user.is_authenticated:
|
if not request.user.is_authenticated:
|
||||||
return
|
return
|
||||||
if hasattr(request.user, "player"):
|
if hasattr(request.user, "player"):
|
||||||
|
if not hasattr(request.user.player, "bloonsa_config"):
|
||||||
|
bloonsa_config = Config(player=request.user.player)
|
||||||
|
bloonsa_config.save()
|
||||||
return request.user.player
|
return request.user.player
|
||||||
ip = self.get_ip(request=request)
|
ip = self.get_ip(request=request)
|
||||||
player = Player(user=request.user,
|
player = Player(user=request.user,
|
||||||
|
|||||||
@ -3,9 +3,10 @@ import string
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
from users.models import Player
|
from users.models import Player, InviteCode
|
||||||
|
|
||||||
def usernameValidator(username):
|
|
||||||
|
def username_validator(username):
|
||||||
if User.objects.filter(username__iexact=username).first() is not None:
|
if User.objects.filter(username__iexact=username).first() is not None:
|
||||||
raise ValidationError("Sorry, this username is already in use")
|
raise ValidationError("Sorry, this username is already in use")
|
||||||
|
|
||||||
@ -23,3 +24,10 @@ def username_change_validator(username):
|
|||||||
charset = set(string.ascii_letters + string.digits + "_-")
|
charset = set(string.ascii_letters + string.digits + "_-")
|
||||||
if not all(x in charset for x in username):
|
if not all(x in charset for x in username):
|
||||||
raise ValidationError("Username may only contain normal letters, numbers and _-")
|
raise ValidationError("Username may only contain normal letters, numbers and _-")
|
||||||
|
|
||||||
|
def invitecode_validator(invitecode):
|
||||||
|
if len(invitecode) > 64:
|
||||||
|
raise ValidationError("Invite code too long")
|
||||||
|
|
||||||
|
if not InviteCode.objects.filter(code=invitecode).exists():
|
||||||
|
raise ValidationError("Invite code doesn't exist")
|
||||||
@ -5,7 +5,7 @@ from django.shortcuts import render, redirect
|
|||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
from users.forms import UserRegisterForm, UserLoginForm, PlayerUpdateForm, UserUpdateForm, BloonsaConfigUpdateForm
|
from users.forms import UserRegisterForm, UserLoginForm, PlayerUpdateForm, UserUpdateForm, BloonsaConfigUpdateForm
|
||||||
from users.models import Player
|
from users.models import Player, InviteCode
|
||||||
from users.util import bloonsa_util, actions
|
from users.util import bloonsa_util, actions
|
||||||
|
|
||||||
|
|
||||||
@ -37,9 +37,14 @@ class RegisterView(TemplateView):
|
|||||||
form = UserRegisterForm(request.POST)
|
form = UserRegisterForm(request.POST)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
return render(request=request, template_name="users/register.html", context={"form": form})
|
return render(request=request, template_name="users/register.html", context={"form": form})
|
||||||
|
|
||||||
|
invite_code = InviteCode.objects.get(code=form.cleaned_data["invite_code"])
|
||||||
user = form.save()
|
user = form.save()
|
||||||
player = bloonsa_util.init_player(request=request)
|
|
||||||
login(request=request, user=user)
|
login(request=request, user=user)
|
||||||
|
player = bloonsa_util.init_player(request=request)
|
||||||
|
player.invite_code = invite_code
|
||||||
|
player.save()
|
||||||
|
|
||||||
bloonsa_util.log(player=player,
|
bloonsa_util.log(player=player,
|
||||||
action=actions.login)
|
action=actions.login)
|
||||||
return redirect("bloonsa_game:game")
|
return redirect("bloonsa_game:game")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user