parent
99da3f2800
commit
319d4374e8
|
|
@ -159,4 +159,7 @@ cython_debug/
|
||||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
|
# static
|
||||||
|
staticfiles/
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/3.0/ref/settings/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
@ -23,9 +24,9 @@ TEMPLATES_DIR = os.path.join(BASE_DIR + '/templates')
|
||||||
SECRET_KEY = '!2g)+m+_h9fq9%il5+t5#qnj^9502or6$=2!$==v=i2*c#7q*m'
|
SECRET_KEY = '!2g)+m+_h9fq9%il5+t5#qnj^9502or6$=2!$==v=i2*c#7q*m'
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = True
|
DEBUG = False
|
||||||
|
|
||||||
ALLOWED_HOSTS = []
|
ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'beyond-heroes.com', 'www.beyond-heroes.com']
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
@ -33,26 +34,43 @@ ALLOWED_HOSTS = []
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
'crispy_forms',
|
'crispy_forms',
|
||||||
'crispy_bootstrap4',
|
'crispy_bootstrap4',
|
||||||
|
|
||||||
'blog.apps.BlogConfig',
|
'blog.apps.BlogConfig',
|
||||||
'users.apps.UsersConfig',
|
'users.apps.UsersConfig',
|
||||||
|
'api.apps.APIConfig',
|
||||||
|
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
|
'django.contrib.sites', # for django-allauth
|
||||||
|
|
||||||
|
'corsheaders',
|
||||||
|
'dj_rest_auth',
|
||||||
|
'rest_framework',
|
||||||
|
'rest_framework.authtoken',
|
||||||
|
# 'allauth',
|
||||||
|
# 'allauth.account',
|
||||||
|
# 'allauth.socialaccount',
|
||||||
|
# 'dj_rest_auth.registration', # for api side user registration
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'corsheaders.middleware.CorsMiddleware', # cors-headers
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
# 'allauth.account.middleware.AccountMiddleware',
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
CORS_ORIGIN_WHITELIST = ( 'http://localhost:3000', 'http://www.beyond-heroes.com')
|
||||||
|
|
||||||
ROOT_URLCONF = 'BH.urls'
|
ROOT_URLCONF = 'BH.urls'
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
|
|
@ -103,6 +121,17 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
REST_FRAMEWORK = {
|
||||||
|
'DEFAULT_PERMISSION_CLASSES': [
|
||||||
|
# 'rest_framework.permissions.AllowAny',
|
||||||
|
'rest_framework.permissions.IsAuthenticated',
|
||||||
|
],
|
||||||
|
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||||
|
# 'rest_framework.authentication.SessionAuthentication', # causes CSRF Token conflicts in API
|
||||||
|
'rest_framework.authentication.TokenAuthentication',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/3.0/topics/i18n/
|
# https://docs.djangoproject.com/en/3.0/topics/i18n/
|
||||||
|
|
@ -121,6 +150,8 @@ USE_TZ = True
|
||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
# https://docs.djangoproject.com/en/3.0/howto/static-files/
|
# https://docs.djangoproject.com/en/3.0/howto/static-files/
|
||||||
|
|
||||||
|
# remember to `python manage.py collectstatic`
|
||||||
|
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
MEDIA_ROOT = os.path.join(BASE_DIR + '/media')
|
MEDIA_ROOT = os.path.join(BASE_DIR + '/media')
|
||||||
MEDIA_URL = '/media/'
|
MEDIA_URL = '/media/'
|
||||||
|
|
@ -128,3 +159,8 @@ MEDIA_URL = '/media/'
|
||||||
CRISPY_TEMPLATE_PACK = 'bootstrap4'
|
CRISPY_TEMPLATE_PACK = 'bootstrap4'
|
||||||
LOGIN_REDIRECT_URL = 'Home'
|
LOGIN_REDIRECT_URL = 'Home'
|
||||||
LOGIN_URL = 'Login'
|
LOGIN_URL = 'Login'
|
||||||
|
|
||||||
|
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' # prints to console
|
||||||
|
# SITE_ID = 1 # for django-allauth
|
||||||
|
|
||||||
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""TechBlog URL Configuration
|
"""BH URL Configuration
|
||||||
|
|
||||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
https://docs.djangoproject.com/en/3.0/topics/http/urls/
|
https://docs.djangoproject.com/en/3.0/topics/http/urls/
|
||||||
|
|
@ -20,8 +20,12 @@ from django.urls import path, include
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', include('blog.urls')),
|
path('', include('blog.urls')),
|
||||||
path('users/', include('users.urls')),
|
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
|
path('api/v1/', include('api.urls')),
|
||||||
|
path('users/', include('users.urls')),
|
||||||
|
path('api-auth/', include('rest_framework.urls')),
|
||||||
|
path('api/v1/dj-rest-auth/', include('dj_rest_auth.urls')),
|
||||||
|
# path('api/v1/dj-rest-auth/register/', include('dj_rest_auth.registration.urls')),
|
||||||
]
|
]
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
from .models import *
|
||||||
|
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
|
admin.site.register(Province)
|
||||||
|
admin.site.register(AssaultTroop)
|
||||||
|
admin.site.register(Player)
|
||||||
|
admin.site.register(Server)
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class APIConfig(AppConfig):
|
||||||
|
name = 'api'
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
# Generated by Django 5.2.9 on 2026-02-19 10:09
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Player',
|
||||||
|
fields=[
|
||||||
|
('id', models.IntegerField(primary_key=True, serialize=False)),
|
||||||
|
('name', models.CharField(max_length=50)),
|
||||||
|
('faction', models.IntegerField()),
|
||||||
|
('server', models.CharField(max_length=20)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'ordering': ['id'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Province',
|
||||||
|
fields=[
|
||||||
|
('id', models.IntegerField(primary_key=True, serialize=False)),
|
||||||
|
('name', models.CharField(max_length=100)),
|
||||||
|
('faction', models.IntegerField()),
|
||||||
|
('map', models.CharField(max_length=255)),
|
||||||
|
('mov_speed', models.IntegerField()),
|
||||||
|
('ats', models.JSONField(null=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'ordering': ['id'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Server',
|
||||||
|
fields=[
|
||||||
|
('id', models.IntegerField(primary_key=True, serialize=False)),
|
||||||
|
('players', models.IntegerField()),
|
||||||
|
('capacity', models.IntegerField()),
|
||||||
|
('region', models.CharField(max_length=3)),
|
||||||
|
('address', models.CharField(max_length=20)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'ordering': ['id'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='AssaultTroop',
|
||||||
|
fields=[
|
||||||
|
('id', models.IntegerField(primary_key=True, serialize=False)),
|
||||||
|
('name', models.CharField(max_length=100)),
|
||||||
|
('faction', models.IntegerField()),
|
||||||
|
('type', models.IntegerField()),
|
||||||
|
('province', models.IntegerField()),
|
||||||
|
('orders', models.JSONField(null=True)),
|
||||||
|
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ats', to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'ordering': ['id'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
from django.db import models
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.db.models.fields import CharField, IntegerField
|
||||||
|
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
|
class Province(models.Model):
|
||||||
|
id = models.IntegerField(primary_key = True)
|
||||||
|
name = models.CharField(max_length = 100, blank = False)
|
||||||
|
faction = models.IntegerField() # 0 - Neutral, 1 - Allies, 2 - Axis
|
||||||
|
map = models.CharField(max_length=255)
|
||||||
|
mov_speed = models.IntegerField()
|
||||||
|
ats = models.JSONField(null=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['id']
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.name} - {self.faction}"
|
||||||
|
|
||||||
|
|
||||||
|
class AssaultTroop(models.Model):
|
||||||
|
id = models.IntegerField(primary_key = True)
|
||||||
|
name = models.CharField(max_length = 100, blank = False)
|
||||||
|
faction = models.IntegerField() # 0 - Neutral, 1 - Allies, 2 - Axis
|
||||||
|
type = models.IntegerField()
|
||||||
|
province = models.IntegerField() # Province ID (-1 for not deployed)
|
||||||
|
orders = models.JSONField(null=True)
|
||||||
|
owner = models.ForeignKey(
|
||||||
|
'auth.User',
|
||||||
|
related_name='ats',
|
||||||
|
on_delete=models.CASCADE
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['id']
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.name} - {self.province},{self.faction}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Player(models.Model):
|
||||||
|
id = models.IntegerField(primary_key = True)
|
||||||
|
name = models.CharField(max_length = 50, blank = False)
|
||||||
|
faction = models.IntegerField()
|
||||||
|
server = CharField(max_length = 20, blank = False)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['id']
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Server(models.Model):
|
||||||
|
id = IntegerField(primary_key = True)
|
||||||
|
players = IntegerField() # total current players
|
||||||
|
capacity = IntegerField() # max player capacity
|
||||||
|
region = CharField(max_length = 3, blank = False) # 3 letter abb. for region
|
||||||
|
address = CharField(max_length = 20, blank = False)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['id']
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.address} - {self.region}"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
from rest_framework import permissions
|
||||||
|
|
||||||
|
class IsSuperUserOrReadOnly(permissions.BasePermission):
|
||||||
|
def has_permission(self, request, view):
|
||||||
|
if request.method in permissions.SAFE_METHODS:
|
||||||
|
return True
|
||||||
|
return request.user.is_superuser
|
||||||
|
|
||||||
|
|
||||||
|
class IsStaff(permissions.BasePermission):
|
||||||
|
def has_permission(self, request, view):
|
||||||
|
return request.user.is_staff
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
from rest_framework import serializers
|
||||||
|
from .models import *
|
||||||
|
|
||||||
|
class ProvinceSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Province
|
||||||
|
fields = ['id', 'name', 'faction', 'map', 'mov_speed', 'ats']
|
||||||
|
|
||||||
|
|
||||||
|
class AssaultTroopSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = AssaultTroop
|
||||||
|
fields = ['id', 'name', 'faction', 'type', 'province', 'deployed', 'orders', 'owner']
|
||||||
|
|
||||||
|
|
||||||
|
class PlayerSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Player
|
||||||
|
fields = ['id', 'name', 'faction', 'server']
|
||||||
|
|
||||||
|
|
||||||
|
class ServerSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Server
|
||||||
|
fields = ['id', 'players', 'capacity', 'region', 'address']
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
from django import template
|
||||||
|
from django.template.defaultfilters import stringfilter
|
||||||
|
|
||||||
|
import markdown as md
|
||||||
|
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
@register.filter()
|
||||||
|
@stringfilter
|
||||||
|
def markdown(value):
|
||||||
|
return md.markdown(value, extensions=['markdown.extensions.fenced_code'])
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
from django.urls import path
|
||||||
|
from .views import *
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('provinces/', ProvincesView.as_view()),
|
||||||
|
path('provinces/<int:pk>/', ProvinceView.as_view()),
|
||||||
|
path('assault_troops/', AssaultTroopsView.as_view()),
|
||||||
|
path('assault_troops/<int:nm>/', AssaultTroopView.as_view()),
|
||||||
|
path('players/', PlayersView.as_view()),
|
||||||
|
path('players/<int:nm>/', PlayerView.as_view()),
|
||||||
|
path('servers/', ServersView.as_view()),
|
||||||
|
path('servers/<int:nm>/', ServerView.as_view()),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
from rest_framework import generics, permissions
|
||||||
|
from .models import *
|
||||||
|
from .serializers import *
|
||||||
|
from .permissions import *
|
||||||
|
|
||||||
|
|
||||||
|
class ProvincesView(generics.ListCreateAPIView):
|
||||||
|
permission_classes = (IsSuperUserOrReadOnly,)
|
||||||
|
queryset = Province.objects.all()
|
||||||
|
serializer_class = ProvinceSerializer
|
||||||
|
|
||||||
|
class ProvinceView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
permission_classes = (IsSuperUserOrReadOnly,)
|
||||||
|
queryset = Province.objects.all()
|
||||||
|
serializer_class = ProvinceSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class AssaultTroopsView(generics.ListCreateAPIView):
|
||||||
|
permission_classes = (IsSuperUserOrReadOnly,)
|
||||||
|
queryset = AssaultTroop.objects.all()
|
||||||
|
serializer_class = AssaultTroopSerializer
|
||||||
|
|
||||||
|
class AssaultTroopView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
permission_classes = (IsSuperUserOrReadOnly,)
|
||||||
|
queryset = AssaultTroop.objects.all()
|
||||||
|
serializer_class = AssaultTroopSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class PlayersView(generics.ListCreateAPIView):
|
||||||
|
permission_classes = (IsStaff,) # Only Staff can see player info, i.e. authorized servers
|
||||||
|
queryset = Player.objects.all()
|
||||||
|
serializer_class = PlayerSerializer
|
||||||
|
|
||||||
|
class PlayerView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
permission_classes = (IsStaff)
|
||||||
|
queryset = Player.objects.all()
|
||||||
|
serializer_class = PlayerSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class ServersView(generics.ListCreateAPIView):
|
||||||
|
permission_classes = (IsSuperUserOrReadOnly,)
|
||||||
|
queryset = Server.objects.all()
|
||||||
|
serializer_class = ServerSerializer
|
||||||
|
|
||||||
|
class ServerView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
permission_classes = (IsSuperUserOrReadOnly,)
|
||||||
|
queryset = Server.objects.all()
|
||||||
|
serializer_class = ServerSerializer
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 5.2.9 on 2026-02-19 10:09
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('blog', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='blog',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='post',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 5.2.9 on 2026-02-19 10:09
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('users', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='profile',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
Loading…
Reference in New Issue