From 49b3ee734262e04e353af6bcfe62a2291a8180c7 Mon Sep 17 00:00:00 2001 From: Akira Miyata Date: Wed, 31 Jul 2024 00:56:23 +0000 Subject: [PATCH] debug temp --- rog/models.py | 87 ++++++- .../email/entry_notification_email.txt | 6 - .../invitation_and_verification_email.txt | 23 ++ .../email/invitation_existing_email.txt | 22 +- rog/templates/email/invitation_new_email.txt | 28 +-- rog/templates/email/verification_email.txt | 29 +-- rog/urls.py | 5 +- rog/utils.py | 60 ++--- rog/views.py | 223 +++++++++++++++++- 9 files changed, 383 insertions(+), 100 deletions(-) delete mode 100644 rog/templates/email/entry_notification_email.txt create mode 100644 rog/templates/email/invitation_and_verification_email.txt diff --git a/rog/models.py b/rog/models.py index b04bc5a..da4944f 100644 --- a/rog/models.py +++ b/rog/models.py @@ -26,6 +26,8 @@ from django.contrib.postgres.indexes import GistIndex from django.utils import timezone from datetime import timedelta,date +from django.contrib.gis.geos import Point,MultiPoint + #from django.db import models from django.core.exceptions import ValidationError @@ -886,17 +888,17 @@ def publish_data(sender, instance, created, **kwargs): os.remove(file) try: - logger.debug("Attempting to read shape file") + #logger.debug("Attempting to read shape file") # print("before reading the file") shp = glob.glob(r'{}/**/*.shp'.format(file_path), recursive=True)[0] - logger.info(f"Shape file read: {shp}") + #logger.info(f"Shape file read: {shp}") # print("this is the read file",shp) gdf = gpd.read_file(shp) crs_name = str(gdf.crs.srs) - logger.debug(f"CRS name: {crs_name}") + #logger.debug(f"CRS name: {crs_name}") # print(crs_name, 'crs - name') epsg = int(crs_name.replace('epsg:','')) @@ -904,11 +906,11 @@ def publish_data(sender, instance, created, **kwargs): epsg=4326 lm2 = getTempMappingforModel(instance.layerof, shp) - logger.info("Saving to temporary table") + #logger.info("Saving to temporary table") # print("### shape file is ###") lm2.save(strict=True, verbose=True) - logger.info("Save to temporary table completed") + #logger.info("Save to temporary table completed") os.remove(shp) except Exception as e: @@ -922,9 +924,9 @@ def publish_data(sender, instance, created, **kwargs): remove_bom_inplace(csv_f) mdl = apps.get_model(app_label="rog", model_name=LAYER_CHOICES[instance.layerof -1][1]) - # print(mdl) - # print(f"#### instance.layerof - {instance.layerof}") - logger.debug(f"Model for layer: {mdl}") + print(mdl) + print(f"#### instance.layerof - {instance.layerof}") + #logger.debug(f"Model for layer: {mdl}") with open(csv_f, mode="r", encoding="utf-8") as txt_file: #heading = next(txt_file) @@ -936,7 +938,8 @@ def publish_data(sender, instance, created, **kwargs): print("@@@@@@@@@@@@") if instance.layerof == 1: #insertShapeLayerLocation(instance.name, fields) - updateLocation(mdl, fields) + #updateLocation(mdl, fields) + update_or_create_location(mdl, fields) if instance.layerof == 2: updateLineTable(mdl, fields) if instance.layerof == 3: @@ -975,6 +978,72 @@ def insertUserUploadUser(name, fields): except Exception as e: logger.error(f"Error updating TempLocation: {e}", exc_info=True) +def update_or_create_location(mdl, fields): + try: + with transaction.atomic(): + latitude = float(fields[11]) if fields[11] and len(fields[11]) > 0 else None + longitude = float(fields[12]) if fields[12] and len(fields[12]) > 0 else None + + geom = MultiPoint(Point(longitude, latitude)) if latitude is not None and longitude is not None else None + + + defaults={ + 'sub_loc_id': fields[1] if len(fields[1]) > 0 else '', + 'cp': fields[2] if len(fields[2]) > 0 else 0, + # その他のフィールド... + 'location_name': fields[3] if len(fields[3]) > 0 else '', + 'category': fields[4] if len(fields[4]) > 0 else '', + 'subcategory': fields[5] if len(fields[5]) > 0 else '', + 'zip': fields[6] if len(fields[6]) > 0 else '', + 'address': fields[7] if len(fields[7]) > 0 else '', + 'prefecture': fields[8] if len(fields[8]) > 0 else '', + 'area': fields[9] if len(fields[9]) > 0 else '', + 'city': fields[10] if len(fields[10]) > 0 else '', + 'latitude': latitude, + 'longitude': longitude, + 'photos': fields[13] if len(fields[13]) > 0 else '', + 'videos': fields[14] if len(fields[14]) > 0 else '', + 'webcontents': fields[15] if len(fields[15]) > 0 else '', + 'status': fields[16] if len(fields[16]) > 0 else '', + 'portal': fields[17] if len(fields[17]) > 0 else '', + 'group': fields[18] if len(fields[18]) > 0 else '', + 'phone': fields[19] if len(fields[19]) > 0 else '', + 'fax': fields[20] if len(fields[20]) > 0 else '', + 'email': fields[21] if len(fields[21]) > 0 else '', + 'facility': fields[22] if len(fields[22]) > 0 else '', + 'remark': fields[23] if len(fields[23]) > 0 else '', + 'tags': fields[24] if len(fields[24]) > 0 else '', + 'hidden_location': fields[25] if len(fields[25]) > 0 else False, + 'auto_checkin': fields[26] if len(fields[26]) > 0 else False, + 'checkin_radius': fields[27] if len(fields[27]) > 0 else 15, + 'checkin_point': fields[28] if len(fields[28]) > 0 else 10, + 'buy_point': fields[29] if len(fields[29]) > 0 else 0, + 'evaluation_value': fields[30] if len(fields[30]) > 0 else '', + 'shop_closed': fields[31] if len(fields[31]) > 0 else False, + 'shop_shutdown': fields[32] if len(fields[32]) > 0 else False, + 'opening_hours_mon': fields[33] if len(fields[33]) > 0 else '', + 'opening_hours_tue': fields[34] if len(fields[34]) > 0 else '', + 'opening_hours_wed': fields[35] if len(fields[35]) > 0 else '', + 'opening_hours_thu': fields[36] if len(fields[36]) > 0 else '', + 'opening_hours_fri': fields[37] if len(fields[37]) > 0 else '', + 'opening_hours_sat': fields[38] if len(fields[38]) > 0 else '', + 'opening_hours_sun': fields[39] if len(fields[39]) > 0 else '' + } + if geom: + defaults['geom'] = geom + + obj, created = mdl.objects.update_or_create( + location_id=int(fields[0]), + defaults=defaults + ) + + if created: + logger.info(f"New location created with id: {obj.location_id}") + else: + logger.info(f"Location updated with id: {obj.location_id}") + + except Exception as e: + logger.error(f"Error updating or creating location: {e}", exc_info=True) def updateLocation(mdl, fields): diff --git a/rog/templates/email/entry_notification_email.txt b/rog/templates/email/entry_notification_email.txt deleted file mode 100644 index 346fa0d..0000000 --- a/rog/templates/email/entry_notification_email.txt +++ /dev/null @@ -1,6 +0,0 @@ -こちらは岐阜aiネットワークです。 -あなた様の岐阜ロゲエントリーが決定いたしましたことをお伝えいたします。 -残暑厳しい中でのロゲイニングですが、水分補給をしっかり行ってご参加いただければ幸いです。 -それでは、今後とも岐阜ロゲをよろしくお願いいたします。 - -本メールは送信専用のメールアドレスで送信しております。 本メールに返信いただいてもご回答いたしかねますので、あらかじめご了承ください(ご質問等はinfo@gifuai.netまでお願いいたします)。もしこのメールに心当たりがない場合は破棄願います。 diff --git a/rog/templates/email/invitation_and_verification_email.txt b/rog/templates/email/invitation_and_verification_email.txt new file mode 100644 index 0000000..258d39a --- /dev/null +++ b/rog/templates/email/invitation_and_verification_email.txt @@ -0,0 +1,23 @@ +件名: 岐阜ロゲ「岐阜ナビ」アカウントのユーザー登録完了と{{invitor}}さんからのチーム参加のお願い + +{{name}} 様 + +こちらは岐阜aiネットワークのAI担当です。 + +この度は岐阜ロゲアプリ「岐阜ナビ」のダウンロードおよびユーザー登録、誠にありがとうございました。 +あなた様の登録で間違いがなければ、こちらをタップし、ユーザー登録を完了させてください。 +同時に、{{invitor}}さんからのチーム「{{team_name}}」への参加承認にもなります。 + +{{activation_link}} + +リンクをタップすると、アプリからログインすることができるようになります。 + +ログインした後は、チーム編成やエントリーまたはチームへの参加を行ってください。 +なお、リアルロゲイニングは別途申し込みが必要になりますので、ご連絡をお待ちください。 + +それでは、岐阜ロゲアプリ「岐阜ナビ」をお楽しみください。 + +本メールは送信専用のメールアドレスで送信しております。 本メールに返信いただいてもご回答いたしかねますので、あらかじめご了承ください(ご質問等はinfo@gifuai.netまでお願いいたします)。もしこのメールに心当たりがない場合は破棄願います。 + +NPO 岐阜aiネットワーク 岐阜ロゲ担当AI + diff --git a/rog/templates/email/invitation_existing_email.txt b/rog/templates/email/invitation_existing_email.txt index d1ec4e5..675b067 100644 --- a/rog/templates/email/invitation_existing_email.txt +++ b/rog/templates/email/invitation_existing_email.txt @@ -1,25 +1,17 @@ -件名: アカウントのアクティベーション +件名: {{invitor}}さんからの岐阜ロゲチーム「{{team_name}}」への招待です。 -{name} 様 +{{name}} 様 -この度は、サービスにご登録いただき、ありがとうございます。 +こちらは岐阜aiネットワーク担当AIです。 -以下のリンクをクリックしてアカウントをアクティベートしてください: -{activation_link} +このメールは{{invitor}}さんから、あなたへの、岐阜ロゲチームへの招待メールです。 -また、アプリをダウンロードしてください: -{app_download_link} +以下のリンクをタップしていただければ、{{invitor}}さんのチーム「{team_name}」の正式メンバーとして登録されます。 -このメールに心当たりがない場合は、お手数ですが破棄してください。 -よろしくお願いいたします。 +{{activation_link}} -{service_name} チーム - - -こちらは岐阜aiネットワークです。 -このメールは{{招待者}}さんから、あなたへの、岐阜ロゲチームへの招待メールです。こちらをタップしていただければ{{招待者}}さんのチームの正式メンバーとして登録されます。https://xxx.xxxx.xxxxx それでは、今後とも岐阜ロゲをよろしくお願いいたします。 本メールは送信専用のメールアドレスで送信しております。 本メールに返信いただいてもご回答いたしかねますので、あらかじめご了承ください(ご質問等はinfo@gifuai.netまでお願いいたします)。もしこのメールに心当たりがない場合は破棄願います。 - +NPO岐阜aiネットワーク 担当AI diff --git a/rog/templates/email/invitation_new_email.txt b/rog/templates/email/invitation_new_email.txt index 1fad263..c8a4cd8 100644 --- a/rog/templates/email/invitation_new_email.txt +++ b/rog/templates/email/invitation_new_email.txt @@ -1,25 +1,25 @@ -件名: アカウントのアクティベーション +件名: {{invitor}}様からの岐阜ロゲ(チーム名:{{team_name}})への招待メール -{name} 様 +{{name}} 様 -この度は、サービスにご登録いただき、ありがとうございます。 +こちらは岐阜aiネットワークのAI担当です。 -以下のリンクをクリックしてアカウントをアクティベートしてください: -{activation_link} +このメールは {{invitor}} さんから、あなたへの、岐阜ロゲチーム「{{team_name}}」への招待メールです。 -また、アプリをダウンロードしてください: -{app_download_link} +まずは、アプリをダウンロードして、ユーザー登録をしてください。 -このメールに心当たりがない場合は、お手数ですが破棄してください。 -よろしくお願いいたします。 +iPhoneの方:{{app_download_link}} +Androidの方:{{android_download_link}} -{service_name} チーム +ダウンロードした後にユーザー登録を行ってください。 +アクティベーション後に個人情報を入力していただくことでチームに正式登録されます。 - -こちらは岐阜aiネットワークです。 -このメールは{{招待者}}さんから、あなたへの、岐阜ロゲチームへの招待メールです。現在あなたは仮登録の状態ですので、まずは次のリンクをタップしてメンバーとして登録していただき、その後でこちらから岐阜ロゲアプリのダウンロードとインストール及び招待時のユーザー名でのログインをお願いします。個人情報を入力していただくことでチームに正式登録されます。https://xxx.xxxx.xxxxx それでは、今後とも岐阜ロゲをよろしくお願いいたします。 -本メールは送信専用のメールアドレスで送信しております。 本メールに返信いただいてもご回答いたしかねますので、あらかじめご了承ください(ご質問等はinfo@gifuai.netまでお願いいたします)。もしこのメールに心当たりがない場合は破棄願います。 + +※ 本メールは送信専用のメールアドレスで送信しております。 本メールに返信いただいてもご回答いたしかねますので、あらかじめご了承ください(ご質問等はinfo@gifuai.netまでお願いいたします)。もしこのメールに心当たりがない場合は破棄願います。 + +NPO岐阜aiネットワーク 担当AI + diff --git a/rog/templates/email/verification_email.txt b/rog/templates/email/verification_email.txt index 99fff88..3108689 100644 --- a/rog/templates/email/verification_email.txt +++ b/rog/templates/email/verification_email.txt @@ -1,29 +1,22 @@ -件名: アカウントのアクティベーション -{name} 様 +件名: 岐阜ロゲ「岐阜ナビ」アカウントのユーザー登録完了依頼 -この度は、サービスにご登録いただき、ありがとうございます。 -以下のリンクをクリックしてアカウントをアクティベートしてください: +{{name}} 様 -{activation_link} +こちらは岐阜aiネットワークのAI担当です。 -また、アプリをダウンロードしてください: +この度は岐阜ロゲアプリ「岐阜ナビ」のダウンロードおよびユーザー登録、誠にありがとうございました。 +あなた様の登録で間違いがなければ、こちらをタップし、ユーザー登録を完了させてください。 -{app_download_link} +{{activation_link}} -このメールに心当たりがない場合は、お手数ですが破棄してください。 -よろしくお願いいたします。 +リンクをタップすると、アプリからログインすることができるようになります。 -{service_name} チーム +ログインした後は、チーム編成やエントリーまたはチームへの参加を行ってください。 +なお、リアルロゲイニングは別途申し込みが必要になりますので、ご連絡をお待ちください。 - -件名:岐阜ロゲのアクティベーション -{name} 様 - -こちらは岐阜aiネットワークです。 -この度は岐阜ロゲアプリのダウンロードおよびユーザー登録、誠にありがとうございました。あなた様の登録で間違いがなければ、こちらをタップしログインページにお進みください。https://xxx.xxxx.xxxxx -それでは、今後とも岐阜ロゲをよろしくお願いいたします。 +それでは、岐阜ロゲアプリ「岐阜ナビ」をお楽しみください。 本メールは送信専用のメールアドレスで送信しております。 本メールに返信いただいてもご回答いたしかねますので、あらかじめご了承ください(ご質問等はinfo@gifuai.netまでお願いいたします)。もしこのメールに心当たりがない場合は破棄願います。 +NPO 岐阜aiネットワーク 岐阜ロゲ担当AI -{service_name} チーム diff --git a/rog/urls.py b/rog/urls.py index c082fa0..3859398 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 +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 from django.urls import path, include from knox import views as knox_views @@ -85,5 +85,6 @@ urlpatterns += [ path('register/', TempUserRegistrationView.as_view(), name='temp-register'), # 仮登録 #path('register/temp/', RegisterView.as_view(), name='register'), # 古い仮登録 path('reactivate//',ResendInvitationEmailView.as_view(),name='reactivate'), - + path('userinfo//', update_user_info, name='update_user_info'), + path('userdetail//',update_user_info, name='update_user_detail') ] diff --git a/rog/utils.py b/rog/utils.py index 42a2041..ef6651c 100644 --- a/rog/utils.py +++ b/rog/utils.py @@ -29,62 +29,62 @@ def share_send_email(subject, body, recipient_email): raise # エラーを再度発生させて、呼び出し元で処理できるようにします -# 既にユーザーになっている人にチームへの参加要請メールを出す。 -# -def send_team_join_email(sender,user,team,entry,activation_link): - context = { - 'name': user.firstname or user.email, - 'activation_link': activation_link, - 'app_download_link': settings.APP_DOWNLOAD_LINK, - 'service_name': settings.SERVICE_NAME, - } - - subject, body = load_email_template('team_invitation_email.txt', context) - share_send_email(subject,body,user.email) - - # 自らユーザー登録した際に、メールの確認メールを送る。 # def send_verification_email(user, activation_link): context = { 'name': user.firstname or user.email, 'activation_link': activation_link, - 'app_download_link': settings.APP_DOWNLOAD_LINK, - 'service_name': settings.SERVICE_NAME, } - + logger.info(f"send_verification_email : {context}") subject, body = load_email_template('verification_email.txt', context) share_send_email(subject,body,user.email) + + + +# 既にユーザーになっている人にチームへの参加要請メールを出す。 +# +def send_team_join_email(sender,user,team,activation_link): + context = { + 'name': user.lastname or user.email, + 'invitor': sender.lastname, + 'activation_link': activation_link, + 'team_name': team.team_name, + } + + subject, body = load_email_template('invitation_existing_email.txt', context) + share_send_email(subject,body,user.email) + + + # まだユーザーでない人にチームメンバー招待メールを送る # その人がユーザー登録して、ユーザー登録されるとメンバーになる。 # アプリからユーザー登録するため、アプリのダウンロードリンクも送る。 # -def send_invitation_email(sender,user,team,entry,activation_link): +def send_invitation_email(sender,user,team,activation_link): context = { 'name': user.firstname or user.email, - 'invitaion_link': activation_link, + 'invitor': sender.lastname, 'app_download_link': settings.APP_DOWNLOAD_LINK, - 'service_name': settings.SERVICE_NAME, + 'android_download_link': settings.ANDROID_DOWNLOAD_LINK, } - subject, body = load_email_template('rogaining_invitaion_email.txt', context) + subject, body = load_email_template('invitation_new_email.txt', context) share_send_email(subject,body,user.email) -# エントリーしたら、その内容をメンバーに送信する。 +# 招待された後にユーザー登録された場合、ヴェリフィケーションでチーム参加登録される。 # -def send_entry_email(sender,user,team,entry,activation_link): +def send_invitaion_and_verification_email(sender, user, team, activation_link): context = { 'name': user.firstname or user.email, - 'invitaion_link': activation_link, - 'app_download_link': settings.APP_DOWNLOAD_LINK, - 'service_name': settings.SERVICE_NAME, - } - - subject, body = load_email_template('entry_notification_email.txt', context) + 'activation_link': activation_link, + 'team_name': team.team_name, + } + logger.info(f"send_invitation_and_verification_email : {context}") + subject, body = load_email_template('invitation_and_verification_email.txt', context) share_send_email(subject,body,user.email) - diff --git a/rog/views.py b/rog/views.py index 18fd0c8..e13c217 100644 --- a/rog/views.py +++ b/rog/views.py @@ -1,7 +1,7 @@ from rest_framework import serializers from django.db import IntegrityError from django.urls import reverse -from .utils import send_verification_email,send_invitation_email,send_team_join_email,send_entry_email +from .utils import send_verification_email,send_invitation_email,send_team_join_email from django.conf import settings import uuid from rest_framework.exceptions import ValidationError as DRFValidationError @@ -86,6 +86,95 @@ class UserTracksViewSet(viewsets.ModelViewSet): serializer_class = UserTracksSerializer +@api_view(['PUT']) +@permission_classes([IsAuthenticated]) +def update_user_info(request, user_id): + try: + user = CustomUser.objects.get(id=user_id) + except CustomUser.DoesNotExist: + return Response({"error": "User not found"}, status=status.HTTP_404_NOT_FOUND) + + if request.user.id != user_id: + return Response({"error": "You don't have permission to update this user's information"}, status=status.HTTP_403_FORBIDDEN) + + data = request.data + logger.debug(f"Received data for update: {data}") + + # CustomUserの更新可能なフィールドを指定 + updateable_fields = ['zekken_number', 'event_code', 'team_name', 'group'] + + #for field in updateable_fields: + # if field in data: + # setattr(user, field, data[field]) + + updated_fields = [] + for field in updateable_fields: + if field in data: + old_value = getattr(user, field) + setattr(user, field, data[field]) + new_value = getattr(user, field) + if old_value != new_value: + updated_fields.append(f"{field}: {old_value} -> {new_value}") + + logger.debug(f"Fields to be updated: {updated_fields}") + + try: + user.save() + + logger.info(f"User {user_id} updated. Changed fields: {', '.join(updated_fields)}") + + serializer = CustomUserSerializer(user) + + return Response(serializer.data, status=status.HTTP_200_OK) + except Exception as e: + logger.error(f"Error updating user {user_id}: {str(e)}") + return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) + +@api_view(['PUT']) +@permission_classes([IsAuthenticated]) +def update_user_detail(request, user_id): + try: + user = CustomUser.objects.get(id=user_id) + except CustomUser.DoesNotExist: + return Response({"error": "User not found"}, status=status.HTTP_404_NOT_FOUND) + + if request.user.id != user_id: + return Response({"error": "You don't have permission to update this user's information"}, status=status.HTTP_403_FORBIDDEN) + + data = request.data + logger.debug(f"Received data for update: {data}") + + # CustomUserの更新可能なフィールドを指定 + updateable_fields = ['firstname', 'lastname', 'date_of_birth', 'female'] + + #for field in updateable_fields: + # if field in data: + # setattr(user, field, data[field]) + + updated_fields = [] + for field in updateable_fields: + if field in data: + old_value = getattr(user, field) + setattr(user, field, data[field]) + new_value = getattr(user, field) + if old_value != new_value: + updated_fields.append(f"{field}: {old_value} -> {new_value}") + + logger.debug(f"Fields to be updated: {updated_fields}") + + try: + user.save() + + logger.info(f"User {user_id} updated. Changed fields: {', '.join(updated_fields)}") + + serializer = CustomUserSerializer(user) + + return Response(serializer.data, status=status.HTTP_200_OK) + except Exception as e: + logger.error(f"Error updating user {user_id}: {str(e)}") + return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) + + def LocationsInPerf(request): perfecture = request.GET.get('perf') @@ -149,8 +238,38 @@ def LocationsInSubPerf(request): serializer = LocationSerializer(locs, many=True) return JsonResponse(serializer.data, safe=False) - +# この関数LocationInBoundは、地理的な範囲内にある特定の条件を満たす位置情報を検索し、結果をJSON形式で返すものです。主なロジックは以下の通りです: +# +# 1.リクエストパラメータの取得: +# 4つの緯度経度ペア(lat1/lon1からlat4/lon4) +# カテゴリ(cat) +# グループ(grp) +# ROG(Region of Gaze)フラグ(is_rog) +# +# 2. 境界ポリゴンの作成: +# 4つの緯度経度ペアが全て提供された場合、それらを使用してジオメトリポリゴンを作成します。 +# +# 3.位置情報のフィルタリング: +# 基本的に、ポリゴン内(geom__within=pl)にある位置情報を検索します。 +# イベント名がない(event_name__isnull=True)位置情報のみを対象とします。 +# カテゴリ、グループ、ROGフラグの有無に応じて、さらにフィルタリングを行います: +# カテゴリが指定された場合、そのカテゴリに一致する位置情報のみを検索します。 +# ROGフラグがある場合、cp(おそらくcheck point)が0でない位置情報を検索します。 +# ROGフラグがない場合、location_nameに'観光'を含む位置情報のみを検索します。 +# グループが指定された場合、そのグループを含む位置情報のみを検索します。 +# +# 4.結果の返却: +# 検索結果が120件を超える場合、"too_many_points"フラグを立てたJSONレスポンスを返します。 +# それ以外の場合、LocationSerializerを使用して位置情報をシリアライズし、JSONレスポンスとして返します。 +# +# 5.エラーハンドリング: +# 必要な緯度経度パラメータが不足している場合、空のJSONオブジェクトを返します。 +# +# この関数は、主に観光関連の位置情報を特定の地理的範囲内で検索し、様々な条件でフィルタリングすることができます。ROGフラグの有無によって検索条件が変わるのが特徴的です。 +# def LocationInBound(request): + logger.debug(f"Received request parameters: {request.GET}") + lat1 = float(request.GET.get('la1')) lon1 = float(request.GET.get('ln1')) lat2 = float(request.GET.get('la2')) @@ -164,8 +283,35 @@ def LocationInBound(request): is_rog = request.GET.get('rog') + logger.debug(f"Parsed parameters: lat1={lat1}, lon1={lon1}, lat2={lat2}, lon2={lon2}, " + f"lat3={lat3}, lon3={lon3}, lat4={lat4}, lon4={lon4}, " + f"cat={cat}, grp={grp}, is_rog={is_rog}") + if(lat1 != None and lon1 != None and lat2 != None and lon2 != None and lat3 != None and lon3 != None and lat4 != None and lon4 != None): pl = geos.Polygon(((lon1, lat1), (lon2, lat2), (lon3, lat3), (lon4, lat4), (lon1, lat1)), srid=4326) + logger.debug(f"Created polygon: {pl}") + + base_query = Location.objects.filter(geom__within=pl, event_name__isnull=True) + + if cat: + base_query = base_query.filter(category=cat) + + if is_rog: + base_query = base_query.filter(~Q(cp=0)) + else: + base_query = base_query.filter(location_name__contains='観光') + + if grp: + base_query = base_query.filter(group__contains=grp) + + logger.debug(f"Final query: {base_query.query}") + + locs = base_query + + logger.debug(f"Number of locations found: {len(locs)}") + + + ''' if(cat): if is_rog: if grp: @@ -188,7 +334,9 @@ def LocationInBound(request): locs = Location.objects.filter(geom__within=pl, event_name__isnull=True, group__contains=grp, location_name__contains='観光') else: locs = Location.objects.filter(geom__within=pl, event_name__isnull=True, location_name__contains='観光') - if len(locs) > 120: + ''' + + if len(locs) > 200: return JsonResponse({"too_many_points": True}, safe=False, status=500) else: serializer = LocationSerializer(locs, many=True) @@ -684,6 +832,21 @@ class NewEventListView(generics.ListAPIView): serializer_class = NewEventSerializer permission_classes = [IsAuthenticated] +def update_external_system(zekken_number, event_code, team_name, class_name, password): + api_url = f"{settings.FRONTEND_URL}/gifuroge/update_team_name" + data = { + "zekken_number": zekken_number, + "new_team_name": team_name, + "event_code": event_code + } + try: + response = requests.post(api_url, json=data) + response.raise_for_status() + return True + except requests.RequestException as e: + logger.error(f"Failed to update external system. Error: {str(e)}") + return False + class TeamViewSet(viewsets.ModelViewSet): serializer_class = TeamSerializer permission_classes = [permissions.IsAuthenticated, IsTeamOwner] @@ -693,6 +856,7 @@ class TeamViewSet(viewsets.ModelViewSet): def perform_create(self, serializer): with transaction.atomic(): + category = serializer.validated_data['category'] category = NewCategory.objects.select_for_update().get(id=category.id) zekken_number = category.category_number @@ -702,6 +866,19 @@ class TeamViewSet(viewsets.ModelViewSet): serializer.save(owner=self.request.user, zekken_number=zekken_number) + team = self.get_object() + + # 外部システムの更新 + success = update_external_system( + team.zekken_number, + team.owner.event_code, + team.team_name, + team.category.category_name, + team.owner.password + ) + if not success: + raise serializers.ValidationError("外部システムの更新に失敗しました。") + def destroy(self, request, *args, **kwargs): team = self.get_object() @@ -715,6 +892,22 @@ class TeamViewSet(viewsets.ModelViewSet): except Exception as e: return Response({"error": "更新に失敗しました。競合が発生した可能性があります。"}, status=status.HTTP_409_CONFLICT) + def perform_update(self, serializer): + with transaction.atomic(): + team = serializer.save() + + # 外部システムの更新 + success = update_external_system( + team.zekken_number, + team.owner.event_code, + team.team_name, + team.category.category_name, + team.owner.password + ) + if not success: + raise serializers.ValidationError("外部システムの更新に失敗しました。") + + @action(detail=True, methods=['post']) def copy(self, request, pk=None): original_team = self.get_object() @@ -834,11 +1027,28 @@ class EntryViewSet(viewsets.ModelViewSet): def update(self, request, *args, **kwargs): + logger.info(f"Update method called for Entry with ID: {kwargs.get('pk')}") + logger.debug(f"Request data: {request.data}") + partial = kwargs.pop('partial', False) instance = self.get_object() serializer = self.get_serializer(instance, data=request.data, partial=partial) - serializer.is_valid(raise_exception=True) - self.perform_update(serializer) + + try: + serializer.is_valid(raise_exception=True) + logger.debug(f"Serializer validated data: {serializer.validated_data}") + except serializers.ValidationError as e: + logger.error(f"Validation error: {e.detail}") + return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) + + try: + self.perform_update(serializer) + logger.info(f"Entry updated successfully: {serializer.data}") + except Exception as e: + logger.exception(f"Error updating Entry: {str(e)}") + return Response({"error": "An error occurred while updating the entry."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + return Response(serializer.data) def destroy(self, request, *args, **kwargs): @@ -921,7 +1131,8 @@ class MemberViewSet(viewsets.ModelViewSet): **user_data, verification_code=str(uuid.uuid4()) ) - send_invitation_email(temp_user, team) + send_invitation_email(temp_user, team) #仮登録済みでも確認メールを送る。 + return Response({"message": "Invitation email sent to the user."}, status=status.HTTP_201_CREATED)