major player game data schema update

This commit is contained in:
zman 2023-12-05 10:59:57 -05:00
parent cd89bba8ad
commit 244af4792f
9 changed files with 329 additions and 83 deletions

View File

@ -4,7 +4,7 @@
<title>Simple Frontend</title>
<script>
function fetchData() {
fetch('http://localhost:8000/games')
fetch('http://localhost:8000/api/games')
.then(response => response.json())
.then(data => {
// Assuming 'data' is an array of games

View File

@ -9,15 +9,15 @@ from server.models import (
Game,
Guild,
Player,
PlayerGameProfile,
WowProfile,
ValorantProfile,
PlayerGuild,
PlayerGameData,
GuildGameDataSchema,
WowClasses,
)
def populate_games():
games = ["World of Warcraft", "Valorant"]
games = ["World of Warcraft", "Counter Strike: Global Offensive"]
for game in games:
g = Game.objects.get_or_create(name=game)[0]
@ -47,47 +47,170 @@ def populate_player_guilds():
)[0]
def populate_player_game_profiles():
player_game_profiles = [
{"player": "Pixel", "game": "World of Warcraft"},
{"player": "Zman", "game": "World of Warcraft"},
{"player": "Skip", "game": "Valorant"},
{"player": "Skip", "game": "World of Warcraft"},
def populate_wow_classes():
wow_classes = [
"Warrior",
"Mage",
"Rogue",
"Priest",
"Warlock",
"Druid",
"Hunter",
"Shaman",
"Paladin",
]
for profile in player_game_profiles:
p = PlayerGameProfile.objects.get_or_create(
player=Player.objects.get(name=profile["player"]),
game=Game.objects.get(name=profile["game"]),
)[0]
for wow_class in wow_classes:
w = WowClasses.objects.get_or_create(name=wow_class)[0]
def populate_wow_profiles():
wow_profiles = [
{"player": "Pixel", "level": 60, "class_name": "Mage"},
{"player": "Zman", "level": 60, "class_name": "Warrior"},
{"player": "Skip", "level": 60, "class_name": "Rogue"},
]
for profile in wow_profiles:
p = WowProfile.objects.get_or_create(
player_game_profile=PlayerGameProfile.objects.get(
player=Player.objects.get(name=profile["player"]),
game=Game.objects.get(name="World of Warcraft"),
),
level=profile["level"],
class_name=profile["class_name"],
)[0]
def populate_guild_game_data_schema():
wow_gamer_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"playerName": {"type": "string"},
"playerDiscordId": {"type": "string"},
"playerAvailabilities": {
"type": "array",
"items": {
"type": "object",
"properties": {
"day": {"type": "string"},
"time": {"type": "string"},
"timeZone": {"type": "string"},
},
"required": ["day", "time", "timeZone"],
},
},
"playerRaids": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
},
"required": ["name"],
},
},
"characters": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"class": {"type": "string"},
"level": {"type": "number"},
},
"required": ["name", "class", "level"],
},
},
},
"required": ["playerName"],
}
wow_gamer1 = {
"playerName": "Pixel",
"discordId": "sseagull_caw",
"playerAvailabilities": [
{"day": "Monday", "time": "20:00", "timeZone": "America/New_York"},
{"day": "Wednesday", "time": "20:00", "timeZone": "America/New_York"},
{"day": "Friday", "time": "20:00", "timeZone": "America/New_York"},
],
"playerRaids": [{"name": "Molten Core"}, {"name": "Blackwing Lair"}],
"characters": [
{"name": "Pixelwar", "class": "Warrior", "level": 60},
{"name": "Pixelmage", "class": "Mage", "level": 60},
],
}
wow_gamer2 = {
"playerName": "Zman",
"discordId": "zmanplex",
"playerAvailabilities": [
{"day": "Monday", "time": "20:30", "timeZone": "America/Chicago"},
{"day": "Wednesday", "time": "20:30", "timeZone": "America/Chicago"},
{"day": "Friday", "time": "20:30", "timeZone": "America/Chicago"},
],
"playerRaids": [{"name": "Naxxramas"}, {"name": "Blackwing Lair"}],
"characters": [
{"name": "Zmanlock", "class": "Warlock", "level": 60},
{"name": "Zmanhunt", "class": "Hunter", "level": 60},
],
}
csgo_epic_nerd_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"playerName": {"type": "string"},
"playerDiscordId": {"type": "string"},
"playerRank": {"type": "string"},
"playerFavoriteMaps": {
"type": "array",
"items": {"type": "string"},
},
"playerFavoriteWeapons": {
"type": "array",
"items": {"type": "string"},
},
"playerAvailabilities": {
"type": "array",
"items": {
"type": "object",
"properties": {
"day": {"type": "string"},
"time": {"type": "string"},
"timeZone": {"type": "string"},
},
"required": ["day", "time", "timeZone"],
},
},
},
"required": ["playerName"],
}
csgo_epic_nerd1 = {
"playerName": "Skip",
"discordId": "tenpull",
"playerRank": "Global Elite",
"playerFavoriteMaps": ["Dust 2", "Mirage"],
"playerFavoriteWeapons": ["AWP", "AK-47"],
"playerAvailabilities": [
{"day": "Monday", "time": "20:00", "timeZone": "America/New_York"},
{"day": "Wednesday", "time": "20:00", "timeZone": "America/New_York"},
{"day": "Friday", "time": "20:00", "timeZone": "America/New_York"},
],
}
def populate_valorant_profiles():
valorant_profiles = [{"player": "Skip", "rank": "Diamond"}]
for profile in valorant_profiles:
p = ValorantProfile.objects.get_or_create(
player_game_profile=PlayerGameProfile.objects.get(
player=Player.objects.get(name=profile["player"]),
game=Game.objects.get(name="Valorant"),
),
rank=profile["rank"],
)[0]
# get or create schema
s = GuildGameDataSchema.objects.get_or_create(
game=Game.objects.get(name="World of Warcraft"),
guild=Guild.objects.get(name="Gamers"),
schema=wow_gamer_schema,
)[0]
# get or create player game data
p1 = PlayerGameData.objects.get_or_create(
player=Player.objects.get(name=wow_gamer1["playerName"]),
game=Game.objects.get(name="World of Warcraft"),
data=wow_gamer1,
)[0]
p2 = PlayerGameData.objects.get_or_create(
player=Player.objects.get(name=wow_gamer2["playerName"]),
game=Game.objects.get(name="World of Warcraft"),
data=wow_gamer2,
)[0]
# get or create schema
s = GuildGameDataSchema.objects.get_or_create(
game=Game.objects.get(name="Counter Strike: Global Offensive"),
guild=Guild.objects.get(name="Epic Nerds"),
schema=csgo_epic_nerd_schema,
)[0]
# get or create player game data
p1 = PlayerGameData.objects.get_or_create(
player=Player.objects.get(name=csgo_epic_nerd1["playerName"]),
game=Game.objects.get(name="Counter Strike: Global Offensive"),
data=csgo_epic_nerd1,
)[0]
def populate():
@ -95,9 +218,9 @@ def populate():
populate_games()
populate_guilds()
populate_players()
populate_player_game_profiles()
populate_wow_profiles()
populate_valorant_profiles()
populate_player_guilds()
populate_wow_classes()
populate_guild_game_data_schema()
if __name__ == "__main__":

Binary file not shown.

View File

@ -0,0 +1,75 @@
# Generated by Django 4.2.7 on 2023-12-05 14:47
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('server', '0003_remove_player_guild_playerguild'),
]
operations = [
migrations.CreateModel(
name='GuildGameDataSchema',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('schema', models.JSONField()),
('game', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='schemas', to='server.game')),
('guild', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='schemas', to='server.guild')),
],
options={
'verbose_name': 'Guild Game Data Schema',
'verbose_name_plural': 'Guild Game Data Schemas',
},
),
migrations.CreateModel(
name='PlayerGameData',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('creation_date', models.DateTimeField(auto_now_add=True, verbose_name='date created')),
('data', models.JSONField()),
('game', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='player_profiles', to='server.game')),
('player', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='game_profiles', to='server.player')),
],
options={
'verbose_name': 'Player Game Data',
'verbose_name_plural': 'Player Game Data',
},
),
migrations.CreateModel(
name='WowClasses',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=200)),
('creation_date', models.DateTimeField(auto_now_add=True, verbose_name='date created')),
],
options={
'verbose_name': 'WoW Class',
'verbose_name_plural': 'WoW Classes',
},
),
migrations.RemoveField(
model_name='valorantprofile',
name='player_game_profile',
),
migrations.RemoveField(
model_name='wowprofile',
name='player_game_profile',
),
migrations.AddField(
model_name='playerguild',
name='role',
field=models.CharField(default='member', max_length=200),
),
migrations.DeleteModel(
name='PlayerGameProfile',
),
migrations.DeleteModel(
name='ValorantProfile',
),
migrations.DeleteModel(
name='WowProfile',
),
]

View File

@ -5,6 +5,7 @@ class Guild(models.Model):
"""
This model is used to store the guild data.
"""
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=200)
tag = models.CharField(max_length=10)
@ -22,6 +23,7 @@ class Player(models.Model):
"""
This model is used to store the player data.
"""
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=200)
creation_date = models.DateTimeField("date created", auto_now_add=True)
@ -38,10 +40,13 @@ class PlayerGuild(models.Model):
"""
This model is used to store the player's guild data.
"""
id = models.AutoField(primary_key=True)
player = models.ForeignKey(Player, on_delete=models.CASCADE, related_name="guilds")
guild = models.ForeignKey(Guild, on_delete=models.CASCADE, related_name="players")
role = models.CharField(max_length=200) # admin, officer, member, etc. eventually tie to permissions and account stuff
role = models.CharField(
max_length=200, default="member"
) # admin, officer, member, etc. eventually tie to permissions and account stuff
creation_date = models.DateTimeField("date created", auto_now_add=True)
def __str__(self):
@ -56,6 +61,7 @@ class Game(models.Model):
"""
This model is used to store the game data.
"""
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=200)
creation_date = models.DateTimeField("date created", auto_now_add=True)
@ -74,6 +80,7 @@ class PlayerGameData(models.Model):
Anything can be stored in the data field, but it will
be validated against the schema before being stored.
"""
id = models.AutoField(primary_key=True)
player = models.ForeignKey(
Player, on_delete=models.CASCADE, related_name="game_profiles"
@ -100,13 +107,10 @@ class GuildGameDataSchema(models.Model):
Player Game Data will be validated against this schema.
"""
id = models.AutoField(primary_key=True)
guild = models.ForeignKey(
Guild, on_delete=models.CASCADE, related_name="schemas"
)
game = models.ForeignKey(
Game, on_delete=models.CASCADE, related_name="schemas"
)
guild = models.ForeignKey(Guild, on_delete=models.CASCADE, related_name="schemas")
game = models.ForeignKey(Game, on_delete=models.CASCADE, related_name="schemas")
schema = models.JSONField()
def __str__(self):
@ -122,6 +126,7 @@ class WowClasses(models.Model):
Example of a model that could be used to pre-populate
dropdowns in the UI.
"""
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=200)
creation_date = models.DateTimeField("date created", auto_now_add=True)

View File

@ -1,3 +1,5 @@
from jsonschema import validate
from jsonschema.exceptions import ValidationError
from rest_framework import serializers
from .models import (
Guild,
@ -39,11 +41,21 @@ class PlayerGameDataSerializer(serializers.ModelSerializer):
def validate_data(self, value):
game_id = self.initial_data["game"]
# pull schema from guildgameschema
schema = GuildGameDataSchema.objects.get(game=game_id)
# validate data against schema
# if valid, return value
# if not valid, raise serializers.ValidationError("Invalid data")
try:
schema_obj = GuildGameDataSchema.objects.get(
game=game_id, guild=self.initial_data["guild"]
)
schema = schema_obj.schema
validate(value, schema)
except GuildGameDataSchema.DoesNotExist:
raise serializers.ValidationError(
"Schema does not exist for this guild and game"
)
except ValidationError as e:
raise serializers.ValidationError(e.message)
return value

View File

@ -53,6 +53,7 @@ INSTALLED_APPS = [
"rest_framework",
"server",
"corsheaders",
"drf_yasg",
]
MIDDLEWARE = [

View File

@ -1,26 +1,56 @@
from django.urls import path, include
from django.urls import path, include, re_path
from django.contrib import admin
from rest_framework.routers import DefaultRouter
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
from .views import (
GameViewSet,
GuildViewSet,
PlayerViewSet,
PlayerGameProfileViewSet,
WowProfileViewSet,
ValorantProfileViewSet,
hello_world,
PlayerGameDataViewSet,
GuildGameDataSchemaViewSet,
PlayerGuildViewSet,
WowClassesViewSet,
)
router = DefaultRouter()
router.register(r"games", GameViewSet)
router.register(r"guilds", GuildViewSet)
router.register(r"players", PlayerViewSet)
router.register(r"player-game-profiles", PlayerGameProfileViewSet)
router.register(r"wow-profiles", WowProfileViewSet)
router.register(r"valorant-profiles", ValorantProfileViewSet)
router.register(r"playergamedata", PlayerGameDataViewSet)
router.register(r"guildgamedataschema", GuildGameDataSchemaViewSet)
router.register(r"playerguild", PlayerGuildViewSet)
router.register(r"wowclasses", WowClassesViewSet)
schema_view = get_schema_view(
openapi.Info(
title="Guild Data API",
default_version="v1",
description="API for Guild Data",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="yourmom@lole.com"),
license=openapi.License(name="License"),
),
public=True,
permission_classes=(permissions.AllowAny,),
)
urlpatterns = [
path("", hello_world, name="index"),
path("", include(router.urls)),
path("admin/", admin.site.urls),
path("api/", include(router.urls)),
# Swagger
re_path(
r"^swagger(?P<format>\.json|\.yaml)$",
schema_view.without_ui(cache_timeout=0),
name="schema-json",
),
re_path(
r"^swagger/$",
schema_view.with_ui("swagger", cache_timeout=0),
name="schema-swagger-ui",
),
]

View File

@ -4,19 +4,19 @@ from .models import (
Game,
Guild,
Player,
PlayerGameProfile,
WowProfile,
ValorantProfile,
PlayerGuild,
PlayerGameData,
GuildGameDataSchema,
WowClasses,
)
from .serializers import (
GameSerializer,
GuildSerializer,
PlayerSerializer,
PlayerGameProfileSerializer,
WowProfileSerializer,
ValorantProfileSerializer,
PlayerGuildSerializer,
PlayerGameDataSerializer,
GuildGameDataSchemaSerializer,
WowClassesSerializer,
)
@ -39,21 +39,21 @@ class PlayerViewSet(viewsets.ModelViewSet):
serializer_class = PlayerSerializer
class PlayerGameProfileViewSet(viewsets.ModelViewSet):
queryset = PlayerGameProfile.objects.all()
serializer_class = PlayerGameProfileSerializer
class PlayerGameDataViewSet(viewsets.ModelViewSet):
queryset = PlayerGameData.objects.all()
serializer_class = PlayerGameDataSerializer
class WowProfileViewSet(viewsets.ModelViewSet):
queryset = WowProfile.objects.all()
serializer_class = WowProfileSerializer
class ValorantProfileViewSet(viewsets.ModelViewSet):
queryset = ValorantProfile.objects.all()
serializer_class = ValorantProfileSerializer
class GuildGameDataSchemaViewSet(viewsets.ModelViewSet):
queryset = GuildGameDataSchema.objects.all()
serializer_class = GuildGameDataSchemaSerializer
class PlayerGuildViewSet(viewsets.ModelViewSet):
queryset = PlayerGuild.objects.all()
serializer_class = PlayerGuildSerializer
class WowClassesViewSet(viewsets.ModelViewSet):
queryset = WowClasses.objects.all()
serializer_class = WowClassesSerializer