diff --git a/.gitignore b/.gitignore index cffd79f..0e1ea32 100644 --- a/.gitignore +++ b/.gitignore @@ -163,3 +163,6 @@ cython_debug/ # static staticfiles/ + +# database +db.sqlite3 diff --git a/BH/settings.py b/BH/settings.py index 83ff08e..b87b28e 100644 --- a/BH/settings.py +++ b/BH/settings.py @@ -24,7 +24,7 @@ TEMPLATES_DIR = os.path.join(BASE_DIR + '/templates') 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! -DEBUG = False +DEBUG = True ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'beyond-heroes.com', 'www.beyond-heroes.com'] @@ -127,7 +127,7 @@ REST_FRAMEWORK = { 'rest_framework.permissions.IsAuthenticated', ], 'DEFAULT_AUTHENTICATION_CLASSES': ( - # 'rest_framework.authentication.SessionAuthentication', # causes CSRF Token conflicts in API + 'rest_framework.authentication.SessionAuthentication', # causes CSRF Token conflicts in API 'rest_framework.authentication.TokenAuthentication', ) } @@ -161,6 +161,6 @@ LOGIN_REDIRECT_URL = 'Home' LOGIN_URL = 'Login' EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' # prints to console -# SITE_ID = 1 # for django-allauth +SITE_ID = 1 # for django-allauth DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/api/filters.py b/api/filters.py new file mode 100644 index 0000000..b250d48 --- /dev/null +++ b/api/filters.py @@ -0,0 +1,8 @@ +from rest_framework.filters import BaseFilterBackend +from users.models import * + +class UserDataFilterBackend(BaseFilterBackend): + def filter_queryset(self, request, queryset, view): + queryset = queryset.filter(user__id=request.user.id) + + return queryset diff --git a/api/permissions.py b/api/permissions.py index 26cdde2..9ef600d 100644 --- a/api/permissions.py +++ b/api/permissions.py @@ -10,3 +10,15 @@ class IsSuperUserOrReadOnly(permissions.BasePermission): class IsStaff(permissions.BasePermission): def has_permission(self, request, view): return request.user.is_staff + + +class IsSuperUserOrAuthReadOnly(permissions.BasePermission): + def has_permission(self, request, view): + if request.method in permissions.SAFE_METHODS: + return request.user != None + return request.user.is_superuser + + +class IsSuperUser(permissions.BasePermission): + def has_permission(self, request, view): + return request.user.is_superuser diff --git a/api/serializers.py b/api/serializers.py index 400fa05..1f0cca8 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -10,7 +10,7 @@ class ProvinceSerializer(serializers.ModelSerializer): class AssaultTroopSerializer(serializers.ModelSerializer): class Meta: model = AssaultTroop - fields = ['id', 'name', 'faction', 'type', 'province', 'deployed', 'orders', 'owner'] + fields = ['id', 'name', 'faction', 'type', 'province', 'orders', 'owner'] class PlayerSerializer(serializers.ModelSerializer): diff --git a/api/urls.py b/api/urls.py index 327296f..8a07d97 100644 --- a/api/urls.py +++ b/api/urls.py @@ -10,4 +10,6 @@ urlpatterns = [ path('players//', PlayerView.as_view()), path('servers/', ServersView.as_view()), path('servers//', ServerView.as_view()), + path('user_data/', UserDataView.as_view()), + path('user_data//', UserDatumView.as_view()), ] diff --git a/api/views.py b/api/views.py index 30ac0d5..a4adcd0 100644 --- a/api/views.py +++ b/api/views.py @@ -1,48 +1,75 @@ from rest_framework import generics, permissions +from django.views.decorators.csrf import csrf_exempt +from django.utils.decorators import method_decorator from .models import * +from .filters import * from .serializers import * from .permissions import * +from users.models import * +from users.serializers import * - +@method_decorator(csrf_exempt, name='dispatch') class ProvincesView(generics.ListCreateAPIView): permission_classes = (IsSuperUserOrReadOnly,) queryset = Province.objects.all() serializer_class = ProvinceSerializer +@method_decorator(csrf_exempt, name='dispatch') class ProvinceView(generics.RetrieveUpdateDestroyAPIView): permission_classes = (IsSuperUserOrReadOnly,) queryset = Province.objects.all() serializer_class = ProvinceSerializer +@method_decorator(csrf_exempt, name='dispatch') class AssaultTroopsView(generics.ListCreateAPIView): permission_classes = (IsSuperUserOrReadOnly,) queryset = AssaultTroop.objects.all() serializer_class = AssaultTroopSerializer +@method_decorator(csrf_exempt, name='dispatch') class AssaultTroopView(generics.RetrieveUpdateDestroyAPIView): permission_classes = (IsSuperUserOrReadOnly,) queryset = AssaultTroop.objects.all() serializer_class = AssaultTroopSerializer +@method_decorator(csrf_exempt, name='dispatch') class PlayersView(generics.ListCreateAPIView): permission_classes = (IsStaff,) # Only Staff can see player info, i.e. authorized servers queryset = Player.objects.all() serializer_class = PlayerSerializer +@method_decorator(csrf_exempt, name='dispatch') class PlayerView(generics.RetrieveUpdateDestroyAPIView): permission_classes = (IsStaff) queryset = Player.objects.all() serializer_class = PlayerSerializer +@method_decorator(csrf_exempt, name='dispatch') class ServersView(generics.ListCreateAPIView): permission_classes = (IsSuperUserOrReadOnly,) queryset = Server.objects.all() serializer_class = ServerSerializer +@method_decorator(csrf_exempt, name='dispatch') class ServerView(generics.RetrieveUpdateDestroyAPIView): permission_classes = (IsSuperUserOrReadOnly,) queryset = Server.objects.all() serializer_class = ServerSerializer + + +@method_decorator(csrf_exempt, name='dispatch') +class UserDatumView(generics.RetrieveUpdateDestroyAPIView): + permission_classes = (IsSuperUser,) + queryset = UserData.objects.all() + serializer_class = UserDataSerializer + # filter_backends = [UserDataFilterBackend] + +@method_decorator(csrf_exempt, name='dispatch') +class UserDataView(generics.ListCreateAPIView): + permission_classes = (IsSuperUserOrAuthReadOnly,) + queryset = UserData.objects.all() + serializer_class = UserDataSerializer + filter_backends = [UserDataFilterBackend] \ No newline at end of file diff --git a/db.sqlite3 b/db.sqlite3 index 02c78a6..51fa769 100644 Binary files a/db.sqlite3 and b/db.sqlite3 differ diff --git a/users/admin.py b/users/admin.py index b5afd5a..42421a0 100644 --- a/users/admin.py +++ b/users/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin -from .models import Profile +from .models import * -# Register your models here. +admin.site.register(UserData) diff --git a/users/forms.py b/users/forms.py index 17b30be..0d0a388 100644 --- a/users/forms.py +++ b/users/forms.py @@ -1,7 +1,7 @@ from django import forms from django.contrib.auth.models import User from django.contrib.auth.forms import UserCreationForm -from .models import Profile +from .models import * class UserRegisterForm(UserCreationForm): diff --git a/users/migrations/0003_userdata_delete_profile.py b/users/migrations/0003_userdata_delete_profile.py new file mode 100644 index 0000000..88ae888 --- /dev/null +++ b/users/migrations/0003_userdata_delete_profile.py @@ -0,0 +1,31 @@ +# Generated by Django 5.2.9 on 2026-02-28 03:45 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0002_alter_profile_id'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='UserData', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=40)), + ('xp', models.IntegerField()), + ('money', models.IntegerField()), + ('equipment', models.CharField(default='0;', max_length=1024)), + ('inventory', models.CharField(default='0;', max_length=1024)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.DeleteModel( + name='Profile', + ), + ] diff --git a/users/models.py b/users/models.py index 3802880..8a3ec8e 100644 --- a/users/models.py +++ b/users/models.py @@ -3,14 +3,21 @@ from django.contrib.auth.models import User # Create your models here. -class Profile(models.Model): +class UserData(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) - name = models.CharField(max_length=100) - about = models.TextField(default='Hi, I am new to TechBlog') - gender = models.TextField(default='None') - dob = models.DateField(default='1999-01-01') - # image = models.ImageField(default='default.png', name='profile_pic', upload_to='profile_pics') + name = models.CharField(max_length=40) + xp = models.IntegerField() + money = models.IntegerField() + equipment = models.CharField(max_length=1024, default='0;') + inventory = models.CharField(max_length=1024, default='0;') def __str__(self): - return f"{self.user.username}'s Profile" + return f"{self.user.username}'s data" + + +# So this is my beutiful brainchild to keep user data in about 1KB per user, I'm not too sure but still +# it's worth the try, so the main payload is the inventory along the soliers an their weapons and vehicles +# along with the mods for everything which I have separated by `;`, `.` and `,` for soldier, equipment +# class and each equipment. I'll try a bit of bit-hacking to pack as much info of 20 bytes in 2 of the mods. +# ammo|--|sights|---|internals|---|, trigger|--|barrel|--|skins|----|, number|--------| \ No newline at end of file diff --git a/users/serializers.py b/users/serializers.py new file mode 100644 index 0000000..f8a8a47 --- /dev/null +++ b/users/serializers.py @@ -0,0 +1,7 @@ +from rest_framework import serializers +from .models import * + +class UserDataSerializer(serializers.ModelSerializer): + class Meta: + model = UserData + fields = ['user', 'name', 'xp', 'money', 'equipment', 'inventory'] diff --git a/users/urls.py b/users/urls.py index d90dc45..1e87528 100644 --- a/users/urls.py +++ b/users/urls.py @@ -3,8 +3,8 @@ from django.contrib.auth import views as login_view from . import views urlpatterns = [ - path('profile/', views.profile, name='Profile'), - path('profile/', views.profile, name='NamedProfile'), + # path('profile/', views.profile, name='Profile'), + # path('profile/', views.profile, name='NamedProfile'), path('login/', login_view.LoginView.as_view(template_name='users/login.html'), name='Login'), path('logout/', login_view.LogoutView.as_view(template_name='users/logout.html'), name='Logout'), path('register/', views.register, name='Register') diff --git a/users/views.py b/users/views.py index 6bac6ff..70326ac 100644 --- a/users/views.py +++ b/users/views.py @@ -11,52 +11,36 @@ from django.views.generic import * # def users(request): # return render(request, 'users/users.html', {'title': 'Users'}) -def getFromArr(arr, indices, *args, **kwargs): - x = [] - for i in indices: - x.append(arr[i]) - return x +# def getFromArr(arr, indices, *args, **kwargs): +# x = [] +# for i in indices: +# x.append(arr[i]) +# return x -@login_required -def profile(request, *args, **kwargs): - try: - user = User._default_manager.all()[kwargs['pk'] - 1] - except: - user = request.user - print(user.id) +# @login_required +# def profile(request, *args, **kwargs): +# try: +# user = User._default_manager.all()[kwargs['pk'] - 1] +# except: +# user = request.user +# print(user.id) - allow_empty = True - queryset = None - model = Post - paginate_by = None - paginate_orphans = 0 - context_object_name = 'posts' - ordering = ['-date_posted'] +# allow_empty = True +# queryset = Post._default_manager.all() +# context_object_name = 'posts' +# ordering = ['-date_posted'] - if queryset is not None: - queryset = queryset - if isinstance(queryset, QuerySet): - queryset = queryset.all() - elif model is not None: - queryset = model._default_manager.all() - else: - raise ImproperlyConfigured( - "%(cls)s is missing a QuerySet. Define " - "%(cls)s.model, %(cls)s.queryset, or override " - "%(cls)s.get_queryset()." % {"cls": self.__class__.__name__} - ) +# if ordering: +# if isinstance(ordering, str): +# ordering = (ordering,) +# queryset = queryset.order_by(*ordering) - if ordering: - if isinstance(ordering, str): - ordering = (ordering,) - queryset = queryset.order_by(*ordering) - - return render(request, 'users/profile.html', {'title': 'Profile', 'profileUser': user, context_object_name: queryset}) +# return render(request, 'users/profile.html', {'title': 'Profile', 'profileUser': user, context_object_name: queryset}) -def people(request): - return render(request, 'users/people.html', {'title': 'People', 'users': User._default_manager.all()}) +# def people(request): +# return render(request, 'users/people.html', {'title': 'People', 'users': User._default_manager.all()}) users = {