Compare commits

...

3 Commits
master ... api

Author SHA1 Message Date
Jukoga b0afa5c7be Rename markdown extras files and update Docker commands for API migrations 2025-12-16 17:27:05 +01:00
Surya 50aed1a48a Update requirements.txt 2025-12-16 15:00:33 +01:00
Surya 02a6904834 Added API 2025-12-16 19:25:43 +05:30
16 changed files with 335 additions and 2 deletions

View File

@ -40,12 +40,14 @@ INSTALLED_APPS = [
'crispy_forms',
'crispy_bootstrap4',
'blog.apps.BlogConfig',
'api.apps.APIConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
]
MIDDLEWARE = [
@ -112,6 +114,13 @@ AUTH_PASSWORD_VALIDATORS = [
},
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
)
}
# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/
@ -138,3 +147,8 @@ MEDIA_URL = '/media/'
CRISPY_TEMPLATE_PACK = 'bootstrap4'
LOGIN_REDIRECT_URL = 'News'
LOGIN_URL = 'Login'
# Default primary key field type
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

View File

@ -20,6 +20,7 @@ from django.urls import path, include
urlpatterns = [
path('', include('blog.urls')),
path('api/', include('api.urls')),
path('admin/', admin.site.urls),
]

0
api/__init__.py Normal file
View File

9
api/admin.py Normal file
View File

@ -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)

5
api/apps.py Normal file
View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class APIConfig(AppConfig):
name = 'api'

70
api/models.py Normal file
View File

@ -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}"

25
api/serializers.py Normal file
View File

@ -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']

3
api/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

13
api/urls.py Normal file
View File

@ -0,0 +1,13 @@
from django.urls import path
from .views import *
urlpatterns = [
path('provinces/', ProvincesView),
path('provinces/<int:nm>/', ProvinceView),
path('assault_troops/', AssaultTroopsView),
path('assault_troops/<int:nm>/', AssaultTroopView),
path('players/', PlayersView),
path('players/<int:nm>/', PlayerView),
path('servers/', ServersView),
path('servers/<int:nm>/', ServerView),
]

180
api/views.py Normal file
View File

@ -0,0 +1,180 @@
from django.shortcuts import render, HttpResponseRedirect, Http404
from rest_framework.parsers import JSONParser
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from .models import *
from .serializers import *
# Create your views here.
@csrf_exempt
def ProvincesView(request):
if request.method == 'GET':
items = Province.objects.all()
serializer = ProvinceSerializer(items, many = True)
return JsonResponse(serializer.data, safe = False)
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = ProvinceSerializer(data = data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data,status = 201)
return JsonResponse(serializer.errors,status = 400)
@csrf_exempt
def AssaultTroopsView(request):
if request.method == 'GET':
items = AssaultTroop.objects.all()
serializer = AssaultTroopSerializer(items, many = True)
return JsonResponse(serializer.data, safe = False)
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = AssaultTroopSerializer(data = data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data,status = 201)
return JsonResponse(serializer.errors,status = 400)
@csrf_exempt
def ProvinceView(request, nm):
try:
item = Province.objects.get(id = nm)
except Province.DoesNotExist:
raise Http404('Not found')
if request.method == 'GET':
serializer = ProvinceSerializer(item)
return JsonResponse(serializer.data)
if request.method == 'PUT':
data = JSONParser().parse(request)
serializer = ProvinceSerializer(item,data =data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data)
return JsonResponse(serializer.errors, status =400)
if request.method == "DELETE":
item.delete()
return HttpResponse(status =204)
@csrf_exempt
def AssaultTroopView(request, nm):
try:
item = AssaultTroop.objects.get(id = nm)
except AssaultTroop.DoesNotExist:
raise Http404('Not found')
if request.method == 'GET':
serializer = AssaultTroopSerializer(item)
return JsonResponse(serializer.data)
if request.method == 'PUT':
data = JSONParser().parse(request)
serializer = AssaultTroopSerializer(item,data =data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data)
return JsonResponse(serializer.errors, status =400)
if request.method == "DELETE":
item.delete()
return HttpResponse(status =204)
@csrf_exempt
def PlayersView(request):
if request.method == 'GET':
items = Player.objects.all()
serializer = PlayerSerializer(items, many = True)
return JsonResponse(serializer.data, safe = False)
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = PlayerSerializer(data = data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data,status = 201)
return JsonResponse(serializer.errors,status = 400)
@csrf_exempt
def ServersView(request):
if request.method == 'GET':
items = Server.objects.all()
serializer = ServerSerializer(items, many = True)
return JsonResponse(serializer.data, safe = False)
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = ServerSerializer(data = data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data,status = 201)
return JsonResponse(serializer.errors,status = 400)
@csrf_exempt
def PlayerView(request, nm):
try:
item = Player.objects.get(id = nm)
except Player.DoesNotExist:
raise Http404('Not found')
if request.method == 'GET':
serializer = PlayerSerializer(item)
return JsonResponse(serializer.data)
if request.method == 'PUT':
data = JSONParser().parse(request)
serializer = PlayerSerializer(item,data =data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data)
return JsonResponse(serializer.errors, status =400)
if request.method == "DELETE":
item.delete()
return HttpResponse(status =204)
@csrf_exempt
def ServerView(request, nm):
try:
item = Server.objects.get(id = nm)
except Server.DoesNotExist:
raise Http404('Not found')
if request.method == 'GET':
serializer = ServerSerializer(item)
return JsonResponse(serializer.data)
if request.method == 'PUT':
data = JSONParser().parse(request)
serializer = ServerSerializer(item,data =data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data)
return JsonResponse(serializer.errors, status =400)
if request.method == "DELETE":
item.delete()
return HttpResponse(status =204)

View File

@ -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'])

View File

@ -10,6 +10,7 @@ services:
network_mode: "host"
command: >
sh -c "python manage.py makemigrations blog --noinput &&
python manage.py makemigrations api --noinput &&
python manage.py migrate --noinput &&
python manage.py collectstatic --noinput &&
gunicorn BH.wsgi:application --bind 0.0.0.0:3030 --workers ${GUNICORN_WORKERS:-3}"

Binary file not shown.

View File

@ -1,7 +1,7 @@
{% extends 'base.html' %}
{% block content %}
{% load markdown_extras %}
{% load blog_markdown_extras %}
<div class="container mt-5">
<div class="card mb-3">

View File

@ -1,7 +1,7 @@
{% extends 'base.html' %}
{% block content %}
{% load markdown_extras %}
{% load blog_markdown_extras %}
<!-- Main Content -->
<div class="container mt-5">
<div class="row">