Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1c7a6a1f5c | |||
| f0114ef33c |
@ -1,5 +1,8 @@
|
|||||||
# FROM python:3.9.9-slim-buster
|
# FROM python:3.9.9-slim-buster
|
||||||
FROM osgeo/gdal:ubuntu-small-3.4.0
|
FROM osgeo/gdal:ubuntu-small-3.4.0
|
||||||
|
# Akira
|
||||||
|
FROM python:3.10
|
||||||
|
FROM ubuntu:latest
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
@ -14,6 +17,13 @@ ARG TZ Asia/Tokyo \
|
|||||||
|
|
||||||
RUN apt-get update -y
|
RUN apt-get update -y
|
||||||
|
|
||||||
|
# 必要なライブラリのインストール by akira
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y software-properties-common && \
|
||||||
|
add-apt-repository ppa:ubuntugis/ppa && \
|
||||||
|
apt-get update && \
|
||||||
|
apt-get install -y gdal-bin libgdal-dev python3-gdal
|
||||||
|
|
||||||
# Install GDAL dependencies
|
# Install GDAL dependencies
|
||||||
RUN apt-get install -y libgdal-dev g++ --no-install-recommends && \
|
RUN apt-get install -y libgdal-dev g++ --no-install-recommends && \
|
||||||
apt-get clean -y
|
apt-get clean -y
|
||||||
@ -23,7 +33,7 @@ ENV CPLUS_INCLUDE_PATH=/usr/include/gdal
|
|||||||
ENV C_INCLUDE_PATH=/usr/include/gdal
|
ENV C_INCLUDE_PATH=/usr/include/gdal
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get -y install netcat gcc postgresql \
|
&& apt-get -y install netcat-openbsd gcc postgresql \
|
||||||
&& apt-get clean
|
&& apt-get clean
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
@ -56,7 +66,9 @@ RUN pip install -r requirements.txt
|
|||||||
COPY . /app
|
COPY . /app
|
||||||
|
|
||||||
# Collect static files
|
# Collect static files
|
||||||
RUN python manage.py collectstatic --noinput
|
RUN python3 manage.py collectstatic --noinput
|
||||||
|
|
||||||
# Use Gunicorn as the entrypoint
|
# Use Gunicorn as the entrypoint
|
||||||
CMD ["gunicorn", "config.wsgi:application", "--bind", "0.0.0.0:8000"]
|
CMD ["gunicorn", "config.wsgi:application", "--bind", "0.0.0.0:8000"]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
6
README.jpn
Normal file
6
README.jpn
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
デプロイ:
|
||||||
|
you can just run
|
||||||
|
docker-compose up -d
|
||||||
|
will deploy it
|
||||||
|
|
||||||
|
|
||||||
@ -173,4 +173,17 @@ LEAFLET_CONFIG = {
|
|||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
|
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
|
||||||
'DEFAULT_AUTHENTICATION_CLASSES': ('knox.auth.TokenAuthentication', ),
|
'DEFAULT_AUTHENTICATION_CLASSES': ('knox.auth.TokenAuthentication', ),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Email settings
|
||||||
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||||
|
EMAIL_HOST = 'smtp-mail.outlook.com'
|
||||||
|
EMAIL_PORT = 587
|
||||||
|
EMAIL_USE_TLS = True
|
||||||
|
EMAIL_HOST_USER = 'akira.miyata@gifuai.net'
|
||||||
|
EMAIL_HOST_PASSWORD = 'SachikoMiyata@123'
|
||||||
|
|
||||||
|
# Optional: Set a default "from" address
|
||||||
|
DEFAULT_FROM_EMAIL = 'info@gifuai.net'
|
||||||
|
|
||||||
|
|||||||
@ -31,7 +31,7 @@ matplotlib==3.5.0
|
|||||||
mccabe==0.6.1
|
mccabe==0.6.1
|
||||||
munch==2.5.0
|
munch==2.5.0
|
||||||
mypy-extensions==0.4.3
|
mypy-extensions==0.4.3
|
||||||
numpy==1.21.4
|
numpy==1.26.2
|
||||||
packaging==21.3
|
packaging==21.3
|
||||||
pandas==1.3.4
|
pandas==1.3.4
|
||||||
pathspec==0.9.0
|
pathspec==0.9.0
|
||||||
@ -46,11 +46,13 @@ pyparsing==3.0.6
|
|||||||
pyproj==3.3.0
|
pyproj==3.3.0
|
||||||
python-dateutil==2.8.2
|
python-dateutil==2.8.2
|
||||||
pytz==2021.3
|
pytz==2021.3
|
||||||
rasterio==1.2.10
|
#rasterio==1.2.10 Akira
|
||||||
|
rasterio==1.3.10
|
||||||
regex==2021.11.10
|
regex==2021.11.10
|
||||||
requests==2.26.0
|
requests==2.26.0
|
||||||
Rtree==0.9.7
|
Rtree==0.9.7
|
||||||
scipy==1.7.3
|
#scipy==1.7.3
|
||||||
|
scipy==1.10.1
|
||||||
seaborn==0.11.2
|
seaborn==0.11.2
|
||||||
setuptools-scm==6.3.2
|
setuptools-scm==6.3.2
|
||||||
Shapely==1.8.0
|
Shapely==1.8.0
|
||||||
|
|||||||
BIN
rog/.DS_Store
vendored
BIN
rog/.DS_Store
vendored
Binary file not shown.
16
rog/management/commands/cleanup_temp_users.py
Normal file
16
rog/management/commands/cleanup_temp_users.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.utils import timezone
|
||||||
|
from rog.models import TempUser # アプリ名 'rog' を適切に変更してください
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Deletes expired temporary user records'
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
expired_users = TempUser.objects.filter(expires_at__lt=timezone.now())
|
||||||
|
count = expired_users.count()
|
||||||
|
expired_users.delete()
|
||||||
|
self.stdout.write(self.style.SUCCESS(f'Successfully deleted {count} expired temporary user records'))
|
||||||
|
|
||||||
|
|
||||||
|
# cron job の設定
|
||||||
|
# 0 3 * * * /path/to/your/python /path/to/your/manage.py cleanup_temp_users
|
||||||
141
rog/models.py
141
rog/models.py
@ -23,6 +23,11 @@ from django.apps import apps
|
|||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
|
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
|
||||||
from django.contrib.postgres.indexes import GistIndex
|
from django.contrib.postgres.indexes import GistIndex
|
||||||
|
from django.db import models
|
||||||
|
from django.contrib.auth.hashers import make_password
|
||||||
|
|
||||||
|
from django.utils import timezone
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
import csv
|
import csv
|
||||||
import codecs
|
import codecs
|
||||||
@ -61,35 +66,123 @@ def remove_bom_inplace(path):
|
|||||||
fp.seek(-bom_length, os.SEEK_CUR)
|
fp.seek(-bom_length, os.SEEK_CUR)
|
||||||
fp.truncate()
|
fp.truncate()
|
||||||
|
|
||||||
|
#========== Akira ここから
|
||||||
|
|
||||||
|
class TempUser(models.Model):
|
||||||
|
email = models.EmailField(unique=True)
|
||||||
|
password = models.CharField(max_length=128)
|
||||||
|
is_rogaining = models.BooleanField(default=False)
|
||||||
|
zekken_number = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
event_code = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
team_name = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
group = models.CharField(max_length=255)
|
||||||
|
verification_code = models.UUIDField(default=uuid.uuid4, editable=False)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
expires_at = models.DateTimeField()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.email
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
if not self.expires_at:
|
||||||
|
self.expires_at = timezone.now() + timedelta(hours=24) # 24時間の有効期限
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
def is_valid(self):
|
||||||
|
return timezone.now() <= self.expires_at
|
||||||
|
|
||||||
|
class Team(models.Model):
|
||||||
|
zekken_number = models.CharField(max_length=255, primary_key=True)
|
||||||
|
team_name = models.CharField(max_length=255)
|
||||||
|
password = models.CharField(max_length=128)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.zekken_number} - {self.team_name}"
|
||||||
|
|
||||||
|
|
||||||
|
class Member(models.Model):
|
||||||
|
zekken_number = models.ForeignKey(Team, on_delete=models.CASCADE)
|
||||||
|
userid = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ('zekken_number', 'userid')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.zekken_number} - {self.userid}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Entry(models.Model):
|
||||||
|
zekken_number = models.ForeignKey(Team, on_delete=models.CASCADE)
|
||||||
|
event_code = models.CharField(max_length=255)
|
||||||
|
date = models.DateField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ('zekken_number', 'event_code', 'date')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.zekken_number} - {self.event_code} - {self.date}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#============= Akira ここまで
|
||||||
|
|
||||||
class CustomUserManager(BaseUserManager):
|
class CustomUserManager(BaseUserManager):
|
||||||
|
|
||||||
def create_user(self, email, password, group, event_code, team_name, **other_fields):
|
def create_user(self, email, firstname, lastname, date_of_birth, password=None):
|
||||||
|
|
||||||
if not email:
|
if not email:
|
||||||
raise ValueError(_("You must provide an email address"))
|
raise ValueError(_("You must provide an email address"))
|
||||||
|
|
||||||
# email = self.normalize_email(email)
|
# ユニークなuseridを生成
|
||||||
user=self.model(email=email, group=group, event_code=event_code, team_name=team_name, zekken_number=email, is_rogaining=True, **other_fields)
|
userid = str(uuid.uuid4())
|
||||||
user.set_password(password)
|
|
||||||
user.save()
|
|
||||||
|
|
||||||
|
user = self.model(
|
||||||
|
email=self.normalize_email(email),
|
||||||
|
firstname=firstname,
|
||||||
|
lastname=lastname,
|
||||||
|
userid=userid,
|
||||||
|
date_of_birth=date_of_birth,
|
||||||
|
)
|
||||||
|
user.set_password(password)
|
||||||
|
user.save(using=self._db)
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
def create_superuser(self, email, password, group, **other_fields):
|
def create_superuser(self, email, firstname, lastname, date_of_birth, password):
|
||||||
other_fields.setdefault('is_staff', True)
|
user = self.create_user(
|
||||||
other_fields.setdefault('is_superuser', True)
|
email,
|
||||||
other_fields.setdefault('is_active', True)
|
firstname=firstname,
|
||||||
|
lastname=lastname,
|
||||||
|
date_of_birth=date_of_birth,
|
||||||
|
password=password,
|
||||||
|
)
|
||||||
|
user.is_staff = True
|
||||||
|
user.is_superuser = True
|
||||||
|
user.is_active = True
|
||||||
|
user.save(using=self._db)
|
||||||
|
return user
|
||||||
|
|
||||||
if other_fields.get('is_staff') is not True:
|
class CustomUser(AbstractBaseUser, PermissionsMixin):
|
||||||
raise ValueError(_('Supperuser must assigned to staff'))
|
email = models.EmailField(unique=True)
|
||||||
if other_fields.get('is_superuser') is not True:
|
firstname = models.CharField(max_length=255)
|
||||||
raise ValueError(_('Supperuser must assigned to superuser=True'))
|
lastname = models.CharField(max_length=255)
|
||||||
|
userid = models.CharField(max_length=255, unique=True)
|
||||||
|
date_of_birth = models.DateField()
|
||||||
|
is_active = models.BooleanField(default=True)
|
||||||
|
is_staff = models.BooleanField(default=False)
|
||||||
|
event_code = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
team_name = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
zekken_number = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
|
||||||
return self.create_user(email, password, group, **other_fields)
|
objects = CustomUserManager()
|
||||||
|
|
||||||
|
USERNAME_FIELD = 'email'
|
||||||
|
REQUIRED_FIELDS = ['firstname', 'lastname', 'userid', 'date_of_birth']
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.email
|
||||||
|
|
||||||
class JpnAdminMainPerf(models.Model):
|
class JpnAdminMainPerf(models.Model):
|
||||||
geom = models.MultiPolygonField(blank=True, null=True)
|
geom = models.MultiPolygonField(blank=True, null=True)
|
||||||
@ -195,6 +288,26 @@ class UserUploadUser(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
class CustomUser(AbstractBaseUser, PermissionsMixin):
|
class CustomUser(AbstractBaseUser, PermissionsMixin):
|
||||||
|
email = models.EmailField(unique=True)
|
||||||
|
firstname = models.CharField(max_length=255)
|
||||||
|
lastname = models.CharField(max_length=255)
|
||||||
|
userid = models.CharField(max_length=255, unique=True, editable=False)
|
||||||
|
date_of_birth = models.DateField()
|
||||||
|
is_active = models.BooleanField(default=True)
|
||||||
|
is_staff = models.BooleanField(default=False)
|
||||||
|
event_code = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
team_name = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
zekken_number = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
|
||||||
|
objects = CustomUserManager()
|
||||||
|
|
||||||
|
USERNAME_FIELD = 'email'
|
||||||
|
REQUIRED_FIELDS = ['firstname', 'lastname', 'date_of_birth']
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.email
|
||||||
|
|
||||||
|
class CustomUser_old(AbstractBaseUser, PermissionsMixin):
|
||||||
class Groups(models.TextChoices):
|
class Groups(models.TextChoices):
|
||||||
GB1 = '大垣-初心者', '大垣-初心者'
|
GB1 = '大垣-初心者', '大垣-初心者'
|
||||||
GB2 = '大垣-3時間', '大垣-3時間'
|
GB2 = '大垣-3時間', '大垣-3時間'
|
||||||
|
|||||||
@ -1,14 +1,35 @@
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework_gis.serializers import GeoFeatureModelSerializer
|
from rest_framework_gis.serializers import GeoFeatureModelSerializer
|
||||||
from sqlalchemy.sql.functions import mode
|
from sqlalchemy.sql.functions import mode
|
||||||
from .models import Location, Location_line, Location_polygon, JpnAdminMainPerf, Useractions, GifuAreas, RogUser, UserTracks, GoalImages, CheckinImages,CustomUser
|
from .models import Location, Location_line, Location_polygon, JpnAdminMainPerf, Useractions, GifuAreas, RogUser, UserTracks, GoalImages, CheckinImages,CustomUser,Team, Member, Entry
|
||||||
from drf_extra_fields.fields import Base64ImageField
|
from drf_extra_fields.fields import Base64ImageField
|
||||||
|
from django.contrib.auth.hashers import make_password
|
||||||
|
|
||||||
#from django.contrib.auth.models import User
|
#from django.contrib.auth.models import User
|
||||||
from .models import CustomUser
|
from .models import CustomUser
|
||||||
from django.contrib.auth import authenticate
|
from django.contrib.auth import authenticate
|
||||||
|
|
||||||
from .models import TestModel
|
from .models import TestModel
|
||||||
|
from .models import TempUser
|
||||||
|
|
||||||
|
class RegistrationSerializer(serializers.ModelSerializer):
|
||||||
|
password2 = serializers.CharField(style={"input_type": "password"}, write_only=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = TempUser
|
||||||
|
fields = ['email', 'is_rogaining', 'zekken_number', 'event_code', 'team_name', 'group', 'password', 'password2']
|
||||||
|
extra_kwargs = {
|
||||||
|
'password': {'write_only': True}
|
||||||
|
}
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
if attrs['password'] != attrs['password2']:
|
||||||
|
raise serializers.ValidationError({"password": "Password fields didn't match."})
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
validated_data.pop('password2')
|
||||||
|
return TempUser.objects.create(**validated_data)
|
||||||
|
|
||||||
|
|
||||||
class LocationCatSerializer(serializers.ModelSerializer):
|
class LocationCatSerializer(serializers.ModelSerializer):
|
||||||
@ -53,6 +74,38 @@ class JPN_main_perfSerializer(serializers.ModelSerializer):
|
|||||||
# model=JpnAdminPerf
|
# model=JpnAdminPerf
|
||||||
# fields=['id','et_id', 'et_right', 'et_left', 'adm2_l', 'adm1_l', 'adm0_l', 'adm0_r', 'adm1_r', 'adm2_r', 'admlevel']
|
# fields=['id','et_id', 'et_right', 'et_left', 'adm2_l', 'adm1_l', 'adm0_l', 'adm0_r', 'adm1_r', 'adm2_r', 'admlevel']
|
||||||
|
|
||||||
|
#============= Akira ここから
|
||||||
|
class TeamSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Team
|
||||||
|
fields = ['zekken_number', 'team_name', 'password']
|
||||||
|
extra_kwargs = {'password': {'write_only': True}}
|
||||||
|
|
||||||
|
class MemberSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Member
|
||||||
|
fields = ['zekken_number', 'userid']
|
||||||
|
|
||||||
|
class EntrySerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Entry
|
||||||
|
fields = ['zekken_number', 'event_code', 'date']
|
||||||
|
|
||||||
|
class CustomUserSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = CustomUser
|
||||||
|
fields = ['email', 'firstname', 'lastname', 'userid', 'date_of_birth', 'password']
|
||||||
|
extra_kwargs = {
|
||||||
|
'password': {'write_only': True},
|
||||||
|
'userid': {'read_only': True}
|
||||||
|
}
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
validated_data['password'] = make_password(validated_data.get('password'))
|
||||||
|
return super(CustomUserSerializer, self).create(validated_data)
|
||||||
|
|
||||||
|
|
||||||
|
#============= Akira ここまで
|
||||||
|
|
||||||
class GifuAreaSerializer(serializers.ModelSerializer):
|
class GifuAreaSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -192,4 +245,4 @@ class RegistrationSerializer(serializers.ModelSerializer):
|
|||||||
raise serializers.ValidationError({'password': 'Passwords must match.'})
|
raise serializers.ValidationError({'password': 'Passwords must match.'})
|
||||||
user.set_password(password)
|
user.set_password(password)
|
||||||
user.save()
|
user.save()
|
||||||
return user
|
return user
|
||||||
|
|||||||
17
rog/urls.py
17
rog/urls.py
@ -1,7 +1,7 @@
|
|||||||
from sys import prefix
|
from sys import prefix
|
||||||
from rest_framework import urlpatterns
|
from rest_framework import urlpatterns
|
||||||
from rest_framework.routers import DefaultRouter
|
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
|
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, VerifyEmailView, TeamViewSet, MemberViewSet, EntryViewSet
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from knox import views as knox_views
|
from knox import views as knox_views
|
||||||
|
|
||||||
@ -18,6 +18,17 @@ router.register(prefix='track', viewset=UserTracksViewSet, basename='track')
|
|||||||
router.register(prefix='goalimage', viewset=GoalImageViewSet, basename='goalimage')
|
router.register(prefix='goalimage', viewset=GoalImageViewSet, basename='goalimage')
|
||||||
router.register(prefix='checkinimage', viewset=CheckinImageViewSet, basename='checkinimage')
|
router.register(prefix='checkinimage', viewset=CheckinImageViewSet, basename='checkinimage')
|
||||||
|
|
||||||
|
#Akira 追加
|
||||||
|
# /api/teams/ - チームの一覧取得と作成
|
||||||
|
# /api/teams/<pk>/ - 特定のチームの取得、更新、削除
|
||||||
|
# /api/members/ - メンバーの一覧取得と作成
|
||||||
|
# /api/members/<pk>/ - 特定のメンバーの取得、更新、削除
|
||||||
|
# /api/entries/ - エントリーの一覧取得と作成
|
||||||
|
# /api/entries/<pk>/ - 特定のエントリーの取得、更新、削除
|
||||||
|
#
|
||||||
|
router.register(r'teams', TeamViewSet)
|
||||||
|
router.register(r'members', MemberViewSet)
|
||||||
|
router.register(r'entries', EntryViewSet)
|
||||||
|
|
||||||
urlpatterns = router.urls
|
urlpatterns = router.urls
|
||||||
|
|
||||||
@ -48,5 +59,7 @@ urlpatterns += [
|
|||||||
path('delete-account/', DeleteAccount, name="delete-account"),
|
path('delete-account/', DeleteAccount, name="delete-account"),
|
||||||
path('privacy/', PrivacyView, name='privacy-view'),
|
path('privacy/', PrivacyView, name='privacy-view'),
|
||||||
path('register', RegistrationView.as_view(), name='register'),
|
path('register', RegistrationView.as_view(), name='register'),
|
||||||
|
path('verify-email/<uuid:verification_code>/', VerifyEmailView.as_view(), name='verify_email'),
|
||||||
|
|
||||||
# path('goal-image/', GoalImageViewSet.as_view(), name='goal-image')
|
# path('goal-image/', GoalImageViewSet.as_view(), name='goal-image')
|
||||||
]
|
]
|
||||||
|
|||||||
179
rog/views.py
179
rog/views.py
@ -1,15 +1,15 @@
|
|||||||
from curses.ascii import NUL
|
from curses.ascii import NUL
|
||||||
from django.core.serializers import serialize
|
from django.core.serializers import serialize
|
||||||
from .models import GoalImages, Location, Location_line, Location_polygon, JpnAdminMainPerf, Useractions, GifuAreas, RogUser, CustomUser, UserTracks, GoalImages, CheckinImages
|
from .models import GoalImages, Location, Location_line, Location_polygon, JpnAdminMainPerf, Useractions, GifuAreas, RogUser, CustomUser, UserTracks, GoalImages, CheckinImages, TempUser
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets,status
|
||||||
from .serializers import LocationSerializer, Location_lineSerializer, Location_polygonSerializer, JPN_main_perfSerializer, LocationCatSerializer, CreateUserSerializer, UserSerializer, LoginUserSerializer, UseractionsSerializer, UserDestinationSerializer, GifuAreaSerializer, LocationEventNameSerializer, RogUserSerializer, UserTracksSerializer, ChangePasswordSerializer, GolaImageSerializer, CheckinImageSerializer, RegistrationSerializer
|
from .serializers import LocationSerializer, Location_lineSerializer, Location_polygonSerializer, JPN_main_perfSerializer, LocationCatSerializer, CreateUserSerializer, UserSerializer, LoginUserSerializer, UseractionsSerializer, UserDestinationSerializer, GifuAreaSerializer, LocationEventNameSerializer, RogUserSerializer, UserTracksSerializer, ChangePasswordSerializer, GolaImageSerializer, CheckinImageSerializer, RegistrationSerializer, Team, Member, Entry, CustomUserSerializer
|
||||||
from knox.models import AuthToken
|
from knox.models import AuthToken
|
||||||
|
|
||||||
from rest_framework import viewsets, generics, status
|
from rest_framework import viewsets, generics, status
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.parsers import JSONParser, MultiPartParser
|
from rest_framework.parsers import JSONParser, MultiPartParser
|
||||||
from .serializers import LocationSerializer
|
from .serializers import LocationSerializer, TeamSerializer, MemberSerializer, EntrySerializer
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from django.contrib.gis.db.models import Extent, Union
|
from django.contrib.gis.db.models import Extent, Union
|
||||||
@ -29,8 +29,9 @@ from rest_framework.parsers import JSONParser, MultiPartParser
|
|||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
import uuid
|
import uuid
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
class LocationViewSet(viewsets.ModelViewSet):
|
class LocationViewSet(viewsets.ModelViewSet):
|
||||||
queryset=Location.objects.all()
|
queryset=Location.objects.all()
|
||||||
@ -55,6 +56,114 @@ class Jpn_Main_PerfViewSet(viewsets.ModelViewSet):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#===== AKira ここから
|
||||||
|
|
||||||
|
class CustomUserViewSet(viewsets.ModelViewSet):
|
||||||
|
queryset = CustomUser.objects.all()
|
||||||
|
serializer_class = CustomUserSerializer
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return CustomUser.objects.filter(id=self.request.user.id)
|
||||||
|
|
||||||
|
class TeamViewSet(viewsets.ModelViewSet):
|
||||||
|
queryset = Team.objects.all()
|
||||||
|
serializer_class = TeamSerializer
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
self.perform_create(serializer)
|
||||||
|
headers = self.get_success_headers(serializer.data)
|
||||||
|
|
||||||
|
# チーム登録後にエントリー登録と外部APIコールを行う
|
||||||
|
self.register_entry_and_call_external_api(serializer.data)
|
||||||
|
|
||||||
|
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
|
||||||
|
|
||||||
|
def register_entry_and_call_external_api(self, team_data):
|
||||||
|
# エントリーの登録
|
||||||
|
entry_data = {
|
||||||
|
'zekken_number': team_data['zekken_number'],
|
||||||
|
'event_code': request.data.get('event_code'), # エントリー用のevent_codeを取得
|
||||||
|
'date': request.data.get('date') # エントリー用の日付を取得
|
||||||
|
}
|
||||||
|
entry_serializer = EntrySerializer(data=entry_data)
|
||||||
|
if entry_serializer.is_valid():
|
||||||
|
entry_serializer.save()
|
||||||
|
|
||||||
|
# 外部APIへのコール
|
||||||
|
self.call_external_api(team_data, entry_data)
|
||||||
|
else:
|
||||||
|
# エントリー登録に失敗した場合のエラーハンドリング
|
||||||
|
raise serializers.ValidationError(entry_serializer.errors)
|
||||||
|
|
||||||
|
def call_external_api(self, team_data, entry_data):
|
||||||
|
external_api_url = "https://rogaining.sumasen.net/gifuroge/register_team"
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
'zekken_number': team_data['zekken_number'],
|
||||||
|
'event_code': entry_data['event_code'],
|
||||||
|
'team_name': team_data['team_name'],
|
||||||
|
'class_name': team_data.get('class_name', 'Default'), # class_nameがない場合はデフォルト値を設定
|
||||||
|
'password': team_data['password']
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.post(external_api_url, data=payload)
|
||||||
|
response.raise_for_status() # エラーレスポンスの場合は例外を発生させる
|
||||||
|
|
||||||
|
# レスポンスの処理(必要に応じて)
|
||||||
|
print(f"External API response: {response.json()}")
|
||||||
|
except requests.RequestException as e:
|
||||||
|
# 外部APIコールに失敗した場合のエラーハンドリング
|
||||||
|
print(f"Failed to call external API: {str(e)}")
|
||||||
|
# ここでエラーをログに記録したり、管理者に通知したりすることができます
|
||||||
|
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
user = self.request.user
|
||||||
|
return Team.objects.filter(member__userid=user)
|
||||||
|
|
||||||
|
class MemberViewSet(viewsets.ModelViewSet):
|
||||||
|
queryset = Member.objects.all()
|
||||||
|
serializer_class = MemberSerializer
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def create(self, request):
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
self.perform_create(serializer)
|
||||||
|
headers = self.get_success_headers(serializer.data)
|
||||||
|
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
user = self.request.user
|
||||||
|
return Member.objects.filter(userid=user)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class EntryViewSet(viewsets.ModelViewSet):
|
||||||
|
queryset = Entry.objects.all()
|
||||||
|
serializer_class = EntrySerializer
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def create(self, request):
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
self.perform_create(serializer)
|
||||||
|
headers = self.get_success_headers(serializer.data)
|
||||||
|
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
user = self.request.user
|
||||||
|
return Entry.objects.filter(zekken_number__member__userid=user)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#===== AKira ここまで
|
||||||
|
|
||||||
class UserTracksViewSet(viewsets.ModelViewSet):
|
class UserTracksViewSet(viewsets.ModelViewSet):
|
||||||
queryset = UserTracks.objects.all()
|
queryset = UserTracks.objects.all()
|
||||||
serializer_class = UserTracksSerializer
|
serializer_class = UserTracksSerializer
|
||||||
@ -143,9 +252,10 @@ def LocationInBound(request):
|
|||||||
if(cat):
|
if(cat):
|
||||||
if is_rog:
|
if is_rog:
|
||||||
if grp:
|
if grp:
|
||||||
locs = Location.objects.filter(~Q(cp=0), geom__within=pl, category=cat, event_name__isnull=True, group__contains=grp)
|
#locs = Location.objects.filter(~Q(cp=0), geom__within=pl, category=cat, event_name__isnull=True, group__contains=grp)
|
||||||
|
locs = Location.objects.filter(geom__within=pl, category=cat, event_name__isnull=True, group__contains=grp)
|
||||||
else:
|
else:
|
||||||
locs = Location.objects.filter(~Q(cp=0), geom__within=pl, category=cat, event_name__isnull=True)
|
locs = Location.objects.filter(geom__within=pl, category=cat, event_name__isnull=True)
|
||||||
else:
|
else:
|
||||||
if grp:
|
if grp:
|
||||||
locs = Location.objects.filter(geom__within=pl, category=cat, event_name__isnull=True, group__contains=grp, location_name__contains='観光')
|
locs = Location.objects.filter(geom__within=pl, category=cat, event_name__isnull=True, group__contains=grp, location_name__contains='観光')
|
||||||
@ -154,9 +264,9 @@ def LocationInBound(request):
|
|||||||
else:
|
else:
|
||||||
if is_rog:
|
if is_rog:
|
||||||
if grp:
|
if grp:
|
||||||
locs = Location.objects.filter(~Q(cp=0), geom__within=pl, event_name__isnull=True, group__contains=grp)
|
locs = Location.objects.filter(geom__within=pl, event_name__isnull=True, group__contains=grp)
|
||||||
else:
|
else:
|
||||||
locs = Location.objects.filter(~Q(cp=0), geom__within=pl, event_name__isnull=True)
|
locs = Location.objects.filter(geom__within=pl, event_name__isnull=True)
|
||||||
else:
|
else:
|
||||||
if grp:
|
if grp:
|
||||||
locs = Location.objects.filter(geom__within=pl, event_name__isnull=True, group__contains=grp, location_name__contains='観光')
|
locs = Location.objects.filter(geom__within=pl, event_name__isnull=True, group__contains=grp, location_name__contains='観光')
|
||||||
@ -540,10 +650,57 @@ class TestActionViewSet(viewsets.ModelViewSet):
|
|||||||
def PrivacyView(request):
|
def PrivacyView(request):
|
||||||
return render(request, "rog/privacy.html")
|
return render(request, "rog/privacy.html")
|
||||||
|
|
||||||
class RegistrationView(APIView):
|
class RegistrationView_old(APIView):
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
serializer = RegistrationSerializer(data=request.data)
|
serializer = RegistrationSerializer(data=request.data)
|
||||||
if serializer.is_valid():
|
if serializer.is_valid():
|
||||||
serializer.save()
|
serializer.save()
|
||||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
class RegistrationView(APIView):
|
||||||
|
def post(self, request):
|
||||||
|
serializer = RegistrationSerializer(data=request.data)
|
||||||
|
if serializer.is_valid():
|
||||||
|
temp_user = serializer.save()
|
||||||
|
verification_url = request.build_absolute_uri(
|
||||||
|
reverse('verify_email', kwargs={'verification_code': temp_user.verification_code})
|
||||||
|
)
|
||||||
|
send_mail(
|
||||||
|
'Verify your email',
|
||||||
|
f'Please click the link to verify your email: {verification_url}',
|
||||||
|
settings.DEFAULT_FROM_EMAIL,
|
||||||
|
[temp_user.email],
|
||||||
|
fail_silently=False,
|
||||||
|
)
|
||||||
|
return Response({"message": "Please check your email to complete registration."}, status=status.HTTP_201_CREATED)
|
||||||
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
|
class VerifyEmailView(APIView):
|
||||||
|
def get(self, request, verification_code):
|
||||||
|
try:
|
||||||
|
temp_user = TempUser.objects.get(verification_code=verification_code)
|
||||||
|
if not temp_user.is_valid():
|
||||||
|
temp_user.delete()
|
||||||
|
return Response({"error": "Verification link has expired. Please register again."}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
user = CustomUser.objects.create_user(
|
||||||
|
email=temp_user.email,
|
||||||
|
password=temp_user.password,
|
||||||
|
is_rogaining=temp_user.is_rogaining,
|
||||||
|
zekken_number=temp_user.zekken_number,
|
||||||
|
event_code=temp_user.event_code,
|
||||||
|
team_name=temp_user.team_name,
|
||||||
|
group=temp_user.group
|
||||||
|
)
|
||||||
|
temp_user.delete()
|
||||||
|
return Response({"message": "Email verified. Registration complete."}, status=status.HTTP_200_OK)
|
||||||
|
except TempUser.DoesNotExist:
|
||||||
|
return Response({"error": "Invalid verification code."}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user