diff --git a/rog/middleware/__init__.py b/rog/middleware/__init__.py new file mode 100644 index 0000000..d13102d --- /dev/null +++ b/rog/middleware/__init__.py @@ -0,0 +1,3 @@ +from .ip_blocking import IPBlockingMiddleware + +__all__ = ['IPBlockingMiddleware'] diff --git a/rog/middleware/ip_blocking.py b/rog/middleware/ip_blocking.py new file mode 100644 index 0000000..0c83c8e --- /dev/null +++ b/rog/middleware/ip_blocking.py @@ -0,0 +1,42 @@ +from django.core.exceptions import PermissionDenied +from django.core.cache import cache +from django.conf import settings + +class IPBlockingMiddleware: + def __init__(self, get_response): + self.get_response = get_response + # 事前にブロックする IP アドレスのリスト + self.blacklisted_ips = getattr(settings, 'BLACKLISTED_IPS', []) + + def __call__(self, request): + ip = self.get_client_ip(request) + + # キャッシュからブロックリストを取得 + blocked_ips = cache.get('blocked_ips', set()) + + # 事前にブロックされた IP またはキャッシュ内のブロックされた IP をチェック + if ip in self.blacklisted_ips or ip in blocked_ips: + raise PermissionDenied + + # 不正アクセスの検出ロジックをここに実装 + if self.is_suspicious(ip): + blocked_ips.add(ip) + cache.set('blocked_ips', blocked_ips, timeout=3600) # 1時間ブロック + raise PermissionDenied + + response = self.get_response(request) + return response + + def is_suspicious(self, ip): + request_count = cache.get(f'request_count_{ip}', 0) + cache.set(f'request_count_{ip}', request_count + 1, timeout=60) + return request_count > 100 # 1分間に100回以上のリクエストがあれば不審と判断 + + def get_client_ip(self, request): + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + if x_forwarded_for: + ip = x_forwarded_for.split(',')[0] + else: + ip = request.META.get('REMOTE_ADDR') + return ip + diff --git a/rog/models.py b/rog/models.py index 27a64c3..980f308 100644 --- a/rog/models.py +++ b/rog/models.py @@ -287,10 +287,16 @@ class NewEvent2(models.Model): event_name = models.CharField(max_length=255, unique=True) start_datetime = models.DateTimeField(default=timezone.now) end_datetime = models.DateTimeField() + deadlineDateTime = models.DateTimeField(null=True, blank=True) + def __str__(self): return f"{self.event_name} - From:{self.start_datetime} To:{self.end_datetime}" + def save(self, *args, **kwargs): + if not self.deadlineDateTime: + self.deadlineDateTime = self.end_datetime - timedelta(days=7) + super().save(*args, **kwargs) class NewEvent(models.Model): event_name = models.CharField(max_length=255, primary_key=True) diff --git a/rog/permissions.py b/rog/permissions.py index 0fb526c..e9174d8 100644 --- a/rog/permissions.py +++ b/rog/permissions.py @@ -14,3 +14,12 @@ class IsTeamOwner(permissions.BasePermission): elif isinstance(obj, Member): return obj.team.owner == request.user return False + +class IsTeamOwnerOrMember(permissions.BasePermission): + def has_permission(self, request, view): + team_id = view.kwargs.get('team_id') + if not team_id: + return False + team = Team.objects.get(id=team_id) + return team.owner == request.user or team.members.filter(user=request.user).exists() + diff --git a/rog/urls.py b/rog/urls.py index 8f09c0b..ee5c2c6 100644 --- a/rog/urls.py +++ b/rog/urls.py @@ -1,7 +1,7 @@ from sys import prefix from rest_framework import urlpatterns from rest_framework.routers import DefaultRouter -from .views import LocationViewSet, Location_lineViewSet, Location_polygonViewSet, Jpn_Main_PerfViewSet, LocationsInPerf, ExtentForSubPerf, SubPerfInMainPerf, ExtentForMainPerf, LocationsInSubPerf, CatView, RegistrationAPI, LoginAPI, UserAPI, UserActionViewset, UserMakeActionViewset, UserDestinations, UpdateOrder, LocationInBound, DeleteDestination, CustomAreaLocations, GetAllGifuAreas, CustomAreaNames, userDetials, UserTracksViewSet, CatByCity, ChangePasswordView, GoalImageViewSet, CheckinImageViewSet, ExtentForLocations, DeleteAccount, PrivacyView, RegistrationView, TeamViewSet,MemberViewSet,EntryViewSet,RegisterView, VerifyEmailView, NewEventListView,NewEvent2ListView,NewCategoryListView,CategoryListView, MemberUserDetailView, TeamMembersWithUserView,MemberAddView,UserActivationView,RegistrationView,TempUserRegistrationView,ResendInvitationEmailView,update_user_info,update_user_detail,ActivateMemberView, ActivateNewMemberView, PasswordResetRequestView, PasswordResetConfirmView, NewCategoryViewSet,LocationInBound2,UserLastGoalTimeView +from .views import LocationViewSet, Location_lineViewSet, Location_polygonViewSet, Jpn_Main_PerfViewSet, LocationsInPerf, ExtentForSubPerf, SubPerfInMainPerf, ExtentForMainPerf, LocationsInSubPerf, CatView, RegistrationAPI, LoginAPI, UserAPI, UserActionViewset, UserMakeActionViewset, UserDestinations, UpdateOrder, LocationInBound, DeleteDestination, CustomAreaLocations, GetAllGifuAreas, CustomAreaNames, userDetials, UserTracksViewSet, CatByCity, ChangePasswordView, GoalImageViewSet, CheckinImageViewSet, ExtentForLocations, DeleteAccount, PrivacyView, RegistrationView, TeamViewSet,MemberViewSet,EntryViewSet,RegisterView, VerifyEmailView, NewEventListView,NewEvent2ListView,NewCategoryListView,CategoryListView, MemberUserDetailView, TeamMembersWithUserView,MemberAddView,UserActivationView,RegistrationView,TempUserRegistrationView,ResendInvitationEmailView,update_user_info,update_user_detail,ActivateMemberView, ActivateNewMemberView, PasswordResetRequestView, PasswordResetConfirmView, NewCategoryViewSet,LocationInBound2,UserLastGoalTimeView,TeamEntriesView from django.urls import path, include from knox import views as knox_views @@ -94,6 +94,7 @@ urlpatterns += [ path('activate-new-member///', ActivateNewMemberView.as_view(), name='activate-new-member'), path('password-reset/', PasswordResetRequestView.as_view(), name='password_reset_request'), path('reset-password///', PasswordResetConfirmView.as_view(), name='password_reset_confirm'), - path('users//last-goal/', UserLastGoalTimeView.as_view(), name='user-last-goal-time'), + path('users//last-goal/', UserLastGoalTimeView.as_view(), name='user-last-goal-time'), + path('teams//entries/', TeamEntriesView.as_view(), name='team-entries'), ] diff --git a/rog/views.py b/rog/views.py index a14f7e1..f0cf73e 100644 --- a/rog/views.py +++ b/rog/views.py @@ -26,7 +26,7 @@ from rest_framework.response import Response from django.shortcuts import get_object_or_404 from .models import Team, Member, CustomUser, NewCategory from .serializers import TeamSerializer, MemberSerializer, CustomUserSerializer, TeamDetailSerializer,UserUpdateSerializer,UserRegistrationSerializer -from .permissions import IsTeamOwner +from .permissions import IsTeamOwner,IsTeamOwnerOrMember from curses.ascii import NUL from django.core.serializers import serialize @@ -1334,34 +1334,38 @@ class EntryViewSet(viewsets.ModelViewSet): @transaction.atomic def perform_create(self, serializer): - category = serializer.validated_data['category'] - category = NewCategory.objects.select_for_update().get(id=category.id) - zekken_number = category.category_number - category.category_number = F('category_number') + 1 - category.save() - category.refresh_from_db() + try: + category = serializer.validated_data['category'] + category = NewCategory.objects.select_for_update().get(id=category.id) + zekken_number = category.category_number + category.category_number = F('category_number') + 1 + category.save() + category.refresh_from_db() + + team = serializer.validated_data['team'] + event = serializer.validated_data['event'] + event_name = event.event_name # イベント名を取得 + + entry = serializer.save(owner=self.request.user, zekken_number=zekken_number) + + logger.info(f"team.owner = {team.owner}, event_name = {event_name}") + logger.info(f"team = {team}") - team = serializer.validated_data['team'] - event = serializer.validated_data['event'] - event_name = event.event_name # イベント名を取得 + # 外部システムの更新 + success = self.register_team( + entry.zekken_number, + event_name, + team.team_name, + category.category_name, + team.owner.password + ) + if not success: + logger.error("Failed to register external system") + raise serializers.ValidationError("外部システムの更新に失敗しました。") + logger.info("External system registered successfully") + except Exception as e: + logger.exception(f"Error creating Entry: {str(e)}") - entry = serializer.save(owner=self.request.user, zekken_number=zekken_number) - - logger.info(f"team.owner = {team.owner}, event_name = {event_name}") - logger.info(f"team = {team}") - - # 外部システムの更新 - success = self.register_team( - entry.zekken_number, - event_name, - team.team_name, - category.category_name, - team.owner.password - ) - if not success: - logger.error("Failed to register external system") - raise serializers.ValidationError("外部システムの更新に失敗しました。") - logger.info("External system registered successfully") def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) @@ -1489,6 +1493,20 @@ class EntryViewSet(viewsets.ModelViewSet): # else: # return str(errors) +class TeamEntriesView(generics.ListAPIView): + serializer_class = EntrySerializer + permission_classes = [IsAuthenticated, IsTeamOwnerOrMember] + + def get_queryset(self): + team_id = self.kwargs['team_id'] + team = Team.objects.get(id=team_id) + return Entry.objects.filter(team=team) + + def get_serializer_context(self): + context = super().get_serializer_context() + context['team_id'] = self.kwargs['team_id'] + return context + class MemberViewSet(viewsets.ModelViewSet): serializer_class = MemberSerializer