From 5b85fabcbd7ddc380491dc18c0d23c7837f8936d Mon Sep 17 00:00:00 2001 From: Surya_AI <> Date: Sun, 8 Mar 2026 17:00:20 +0530 Subject: [PATCH] Added UserAction to API and Chat --- .gitignore | 3 + api/actions.py | 15 ++++ api/data.py | 19 ++++ api/tests.py | 69 +++++++++++++++ api/urls.py | 1 + api/views.py | 18 +++- blog/forms.py | 9 ++ blog/models.py | 7 +- blog/urls.py | 12 +-- blog/views.py | 40 ++++++++- db.sqlite3 | Bin 307200 -> 315392 bytes templates/base.html | 4 +- templates/blog/partials/post.html | 5 ++ templates/blog/partials/postList.html | 3 + templates/blog/postList.html | 121 ++++++++++++++++++++++++++ users/migrations/0004_useraction.py | 24 +++++ users/models.py | 19 ++-- users/serializers.py | 6 ++ 18 files changed, 355 insertions(+), 20 deletions(-) create mode 100644 api/actions.py create mode 100644 api/data.py create mode 100644 blog/forms.py create mode 100644 templates/blog/partials/post.html create mode 100644 templates/blog/partials/postList.html create mode 100644 templates/blog/postList.html create mode 100644 users/migrations/0004_useraction.py diff --git a/.gitignore b/.gitignore index 0e1ea32..208433f 100644 --- a/.gitignore +++ b/.gitignore @@ -166,3 +166,6 @@ staticfiles/ # database db.sqlite3 + +# todo +todo* diff --git a/api/actions.py b/api/actions.py new file mode 100644 index 0000000..41a5c44 --- /dev/null +++ b/api/actions.py @@ -0,0 +1,15 @@ +from .views import * +from users.models import * + +def is_action_processable(request): + user = Users.objects.get(request.body["user"]) + if user: + # TODO implement + return True + + +def process_action(request): + if not is_action_processable(request): + return + print(request.body) + diff --git a/api/data.py b/api/data.py new file mode 100644 index 0000000..45a480f --- /dev/null +++ b/api/data.py @@ -0,0 +1,19 @@ +# Defines Data ffs + + +VIEW_ACTION = 0 +PURCHASE_ACTION = 1 +MODIFY_ACTION = 2 +EQUIP_ACTION = 3 + +# Need to define costs for purchase actions and requirements for modify and equip actions + +# Saving space and reducing response times of the server is a priority so keeping in mind that this +# data will probably live on the RAM (as file-io is costly) so it needs to be small and easy to parse + +# # sights,trg,brl +# # cost,ammo^inter^ >^skin,number +# # |----|^^|-||-|>^>^|--||------| +# WEAPON_DATA = """000000000000000000000000000000""" # Use Ints goddamit +# oh yeah, ints +WEAPON_DATA = [] # wtf diff --git a/api/tests.py b/api/tests.py index 7ce503c..942132f 100644 --- a/api/tests.py +++ b/api/tests.py @@ -1,3 +1,72 @@ from django.test import TestCase +from django.contrib.auth.models import User +from rest_framework.test import APITestCase, APIClient +from rest_framework import status # Create your tests here. +class UnAuthAccessTests(APITestCase): + def test_province_get(self): + response = self.client.get("/api/v1/provinces/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_assault_troops_get(self): + response = self.client.get("/api/v1/assault_troops/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_servers_get(self): + response = self.client.get("/api/v1/servers/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_players_get(self): + response = self.client.get("/api/v1/players/") + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + def test_user_action_get(self): + response = self.client.get("/api/v1/user_action/") + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + def test_user_action_post(self): + response = self.client.post("/api/v1/user_action/", {"user": 1, "action": "142"}, format="json") + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + +class AuthAccessTests(APITestCase): + def setUp(self): + self.user = User.objects.create_user(username="test", password="pass123") + self.user2 = User.objects.create_user(username="test2", password="pass123", is_staff=True) + + def test_province_get(self): + self.client.login(username="test", password="pass123") + response = self.client.get("/api/v1/provinces/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_assault_troops_get(self): + self.client.login(username="test", password="pass123") + response = self.client.get("/api/v1/assault_troops/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_servers_get(self): + self.client.login(username="test", password="pass123") + response = self.client.get("/api/v1/servers/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_players_get(self): + self.client.login(username="test", password="pass123") + response = self.client.get("/api/v1/players/") + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + def test_players_staff_get(self): + self.client.login(username="test2", password="pass123") + response = self.client.get("/api/v1/players/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_user_action_post(self): + self.client.login(username="test", password="pass123") + response = self.client.post("/api/v1/user_action/", {"user": 1, "action": "142"}, format="json") + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + def test_user_data_get(self): + self.client.login(username="test", password="pass123") + response = self.client.get("/api/v1/user_data/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + diff --git a/api/urls.py b/api/urls.py index 8a07d97..8b5c32b 100644 --- a/api/urls.py +++ b/api/urls.py @@ -12,4 +12,5 @@ urlpatterns = [ path('servers//', ServerView.as_view()), path('user_data/', UserDataView.as_view()), path('user_data//', UserDatumView.as_view()), + path('user_action/', UserActionView.as_view()), ] diff --git a/api/views.py b/api/views.py index a4adcd0..cba676b 100644 --- a/api/views.py +++ b/api/views.py @@ -1,8 +1,9 @@ -from rest_framework import generics, permissions +from rest_framework import generics, permissions, mixins from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator from .models import * from .filters import * +from .actions import * from .serializers import * from .permissions import * from users.models import * @@ -42,7 +43,7 @@ class PlayersView(generics.ListCreateAPIView): @method_decorator(csrf_exempt, name='dispatch') class PlayerView(generics.RetrieveUpdateDestroyAPIView): - permission_classes = (IsStaff) + permission_classes = (IsStaff,) queryset = Player.objects.all() serializer_class = PlayerSerializer @@ -72,4 +73,15 @@ class UserDataView(generics.ListCreateAPIView): permission_classes = (IsSuperUserOrAuthReadOnly,) queryset = UserData.objects.all() serializer_class = UserDataSerializer - filter_backends = [UserDataFilterBackend] \ No newline at end of file + filter_backends = [UserDataFilterBackend] + + +@method_decorator(csrf_exempt, name='dispatch') +class UserActionView(mixins.CreateModelMixin, generics.GenericAPIView): + permission_classes = (permissions.IsAuthenticated,) + queryset = UserAction.objects.all() + serializer_class = UserActionSerializer + + def post(self, request, *args, **kwargs): + process_action(request) + return self.create(request, *args, **kwargs) \ No newline at end of file diff --git a/blog/forms.py b/blog/forms.py new file mode 100644 index 0000000..cc1ce0a --- /dev/null +++ b/blog/forms.py @@ -0,0 +1,9 @@ +from django import forms +from .models import Post + + +class PostForm(forms.ModelForm): + class Meta: + model = Post + fields = ['content'] + diff --git a/blog/models.py b/blog/models.py index 5ada5ee..611be03 100644 --- a/blog/models.py +++ b/blog/models.py @@ -1,6 +1,6 @@ from django.contrib.auth.models import User from django.db import models -from django.utils import timezone +# from django.utils import timezone # Create your models here. @@ -8,7 +8,8 @@ class Blog(models.Model): content = models.TextField() title = models.CharField(max_length=150) author = models.ForeignKey(User, on_delete=models.CASCADE) - date_posted = models.DateTimeField(default=timezone.now) + # date_posted = models.DateTimeField(default=timezone.now) + date_posted = models.DateTimeField(auto_now_add=True) def get_absolute_url(self): return '/' @@ -18,4 +19,4 @@ class Blog(models.Model): class Post(models.Model): content = models.TextField() author = models.ForeignKey(User, on_delete=models.CASCADE) - date_posted = models.DateTimeField(default=timezone.now) + date_posted = models.DateTimeField(auto_now_add=True) diff --git a/blog/urls.py b/blog/urls.py index 3bde192..3b0c0e5 100644 --- a/blog/urls.py +++ b/blog/urls.py @@ -4,10 +4,12 @@ from . import views urlpatterns = [ path('', views.home, name='Home'), path('news/', views.news, name='News'), - path('blog/', views.BlogDetailView.as_view(), name='Blog'), - path('blog/create/', views.BlogCreateView.as_view(), name='Blog Create'), - path('post/', views.PostDetailView.as_view(), name='Post'), - path('post/create/', views.PostCreateView.as_view(), name='Post Create'), - path('dev/', views.dev, name='Dev'), + # path('blog/', views.BlogDetailView.as_view(), name='Blog'), + # path('blog/create/', views.BlogCreateView.as_view(), name='Blog Create'), + # path('post/', views.PostDetailView.as_view(), name='Post'), + # path('post/create/', views.PostCreateView.as_view(), name='Post Create'), + # path('dev/', views.dev, name='Dev'), + path('chat/', views.chat, name='Chat'), + path("chat/p/", views.posts_partial, name="ChatPartial"), path('dev/support/', views.support, name='Support'), ] diff --git a/blog/views.py b/blog/views.py index 4f7138e..5adb5d3 100644 --- a/blog/views.py +++ b/blog/views.py @@ -2,7 +2,10 @@ from django.shortcuts import render from django.contrib.auth.mixins import * from django.views.generic import * from .models import * +from .forms import * +MAX_POSTS = 150 +MARGIN = 20 # Create your views here. def news(request): @@ -49,7 +52,7 @@ class BlogCreateView(LoginRequiredMixin, CreateView): def form_valid(self, form): form.instance.author = self.request.user - return super().form_valid(form) + return super().form_valid(form) and self.request.user.is_staff @@ -68,6 +71,39 @@ class PostCreateView(LoginRequiredMixin, CreateView): return super().form_valid(form) +def chat(request): + if request.method == "POST": + form = PostForm(request.POST) + + if form.is_valid(): + post = form.save(commit=False) + post.author = request.user + post.save() + print(Post.objects.count()) + if Post.objects.count() > MAX_POSTS + MARGIN: + qs = Post.objects.order_by("-date_posted") + old_ids = qs.values_list("id", flat=True)[MAX_POSTS:] + + if old_ids: + Post.objects.filter(id__in=old_ids).delete() + + return render(request, "blog/partials/post.html", {"post": post}) + + posts = Post.objects.select_related("author").order_by("-date_posted") + form = PostForm() + + return render(request, "blog/postList.html", { + "posts": posts, + "form": form + }) + +def posts_partial(request): + posts = Post.objects.select_related("author").order_by("-date_posted")[:40] + + return render(request, "blog/partials/postList.html", { + "posts": posts + }) + def dev(request): return render(request, 'dev.html', {'title': 'Development'}) @@ -75,4 +111,4 @@ def support(request): return render(request, 'support.html', {'title': 'Support Us'}) def home(request): - return render(request, 'index.html', {'title': 'Home'}) \ No newline at end of file + return render(request, 'index.html', {'title': 'Home'}) diff --git a/db.sqlite3 b/db.sqlite3 index 51fa76967409cb4accdf39825b83cfc920d1edde..423a93890791d7b617954a8d94560020c02d2385 100644 GIT binary patch delta 3295 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 diff --git a/templates/base.html b/templates/base.html index b67ce7c..495cfd1 100644 --- a/templates/base.html +++ b/templates/base.html @@ -512,10 +512,11 @@