mirror of
https://github.com/i701/sarlink-portal-api.git
synced 2025-02-22 08:32:01 +00:00
Refactor Docker configuration and API endpoints
- Merged production and development Docker configurations - Updated Dockerfile to use multi-stage build - Removed separate Dockerfile.prod - Modified docker-compose.yml for production settings - Added new API endpoints for user filtering by ID card - Updated serializers and views for Atoll and Island management - Enhanced user and atoll-related filters and views
This commit is contained in:
parent
f6f77bb0e5
commit
c1fc07e3e2
65
Dockerfile
65
Dockerfile
@ -1,5 +1,9 @@
|
|||||||
|
###########
|
||||||
|
# BUILDER #
|
||||||
|
###########
|
||||||
|
|
||||||
# pull official base image
|
# pull official base image
|
||||||
FROM python:3.11.4-slim-buster
|
FROM python:3.11.4-slim-buster AS builder
|
||||||
|
|
||||||
# set work directory
|
# set work directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
@ -9,20 +13,59 @@ ENV PYTHONDONTWRITEBYTECODE 1
|
|||||||
ENV PYTHONUNBUFFERED 1
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
|
||||||
# install system dependencies
|
# install system dependencies
|
||||||
RUN apt-get update && apt-get install -y netcat
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends gcc
|
||||||
|
|
||||||
|
# lint
|
||||||
|
RUN pip install --upgrade pip
|
||||||
|
COPY . /app/
|
||||||
|
|
||||||
|
# install python dependencies
|
||||||
|
COPY ./requirements.txt .
|
||||||
|
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt
|
||||||
|
|
||||||
|
|
||||||
|
#########
|
||||||
|
# FINAL #
|
||||||
|
#########
|
||||||
|
|
||||||
|
# pull official base image
|
||||||
|
FROM python:3.11.4-slim-buster
|
||||||
|
|
||||||
|
# create directory for the app user
|
||||||
|
RUN mkdir -p /home/app
|
||||||
|
|
||||||
|
# create the app user
|
||||||
|
RUN addgroup --system app && adduser --system --group app
|
||||||
|
|
||||||
|
# create the appropriate directories
|
||||||
|
ENV HOME=/home/app
|
||||||
|
ENV APP_HOME=/home/app/api
|
||||||
|
RUN mkdir $APP_HOME
|
||||||
|
RUN mkdir $APP_HOME/staticfiles
|
||||||
|
RUN chmod -R 777 $APP_HOME/staticfiles
|
||||||
|
WORKDIR $APP_HOME
|
||||||
|
|
||||||
# install dependencies
|
# install dependencies
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends netcat
|
||||||
|
COPY --from=builder /app/wheels /wheels
|
||||||
|
COPY --from=builder /app/requirements.txt .
|
||||||
RUN pip install --upgrade pip
|
RUN pip install --upgrade pip
|
||||||
COPY ./requirements.txt .
|
RUN pip install --no-cache /wheels/*
|
||||||
RUN pip install -r requirements.txt
|
|
||||||
|
|
||||||
# copy entrypoint.sh
|
# copy entrypoint.prod.sh
|
||||||
COPY ./entrypoint.sh .
|
COPY ./entrypoint.prod.sh .
|
||||||
RUN sed -i 's/\r$//g' /app/entrypoint.sh
|
RUN sed -i 's/\r$//g' $APP_HOME/entrypoint.prod.sh
|
||||||
RUN chmod +x /app/entrypoint.sh
|
RUN chmod +x $APP_HOME/entrypoint.prod.sh
|
||||||
|
|
||||||
# copy project
|
# copy project
|
||||||
COPY . .
|
COPY . $APP_HOME
|
||||||
|
|
||||||
# run entrypoint.sh
|
# chown all the files to the app user
|
||||||
ENTRYPOINT ["/app/entrypoint.sh"]
|
RUN chown -R app:app $APP_HOME
|
||||||
|
|
||||||
|
# change to the app user
|
||||||
|
USER app
|
||||||
|
|
||||||
|
# run entrypoint.prod.sh
|
||||||
|
ENTRYPOINT ["/home/app/api/entrypoint.prod.sh"]
|
||||||
|
@ -1,71 +0,0 @@
|
|||||||
###########
|
|
||||||
# BUILDER #
|
|
||||||
###########
|
|
||||||
|
|
||||||
# pull official base image
|
|
||||||
FROM python:3.11.4-slim-buster AS builder
|
|
||||||
|
|
||||||
# set work directory
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# set environment variables
|
|
||||||
ENV PYTHONDONTWRITEBYTECODE 1
|
|
||||||
ENV PYTHONUNBUFFERED 1
|
|
||||||
|
|
||||||
# install system dependencies
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get install -y --no-install-recommends gcc
|
|
||||||
|
|
||||||
# lint
|
|
||||||
RUN pip install --upgrade pip
|
|
||||||
COPY . /app/
|
|
||||||
|
|
||||||
# install python dependencies
|
|
||||||
COPY ./requirements.txt .
|
|
||||||
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt
|
|
||||||
|
|
||||||
|
|
||||||
#########
|
|
||||||
# FINAL #
|
|
||||||
#########
|
|
||||||
|
|
||||||
# pull official base image
|
|
||||||
FROM python:3.11.4-slim-buster
|
|
||||||
|
|
||||||
# create directory for the app user
|
|
||||||
RUN mkdir -p /home/app
|
|
||||||
|
|
||||||
# create the app user
|
|
||||||
RUN addgroup --system app && adduser --system --group app
|
|
||||||
|
|
||||||
# create the appropriate directories
|
|
||||||
ENV HOME=/home/app
|
|
||||||
ENV APP_HOME=/home/app/api
|
|
||||||
RUN mkdir $APP_HOME
|
|
||||||
RUN mkdir $APP_HOME/staticfiles
|
|
||||||
RUN chmod -R 777 $APP_HOME/staticfiles
|
|
||||||
WORKDIR $APP_HOME
|
|
||||||
|
|
||||||
# install dependencies
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends netcat
|
|
||||||
COPY --from=builder /app/wheels /wheels
|
|
||||||
COPY --from=builder /app/requirements.txt .
|
|
||||||
RUN pip install --upgrade pip
|
|
||||||
RUN pip install --no-cache /wheels/*
|
|
||||||
|
|
||||||
# copy entrypoint.prod.sh
|
|
||||||
COPY ./entrypoint.prod.sh .
|
|
||||||
RUN sed -i 's/\r$//g' $APP_HOME/entrypoint.prod.sh
|
|
||||||
RUN chmod +x $APP_HOME/entrypoint.prod.sh
|
|
||||||
|
|
||||||
# copy project
|
|
||||||
COPY . $APP_HOME
|
|
||||||
|
|
||||||
# chown all the files to the app user
|
|
||||||
RUN chown -R app:app $APP_HOME
|
|
||||||
|
|
||||||
# change to the app user
|
|
||||||
USER app
|
|
||||||
|
|
||||||
# run entrypoint.prod.sh
|
|
||||||
ENTRYPOINT ["/home/app/api/entrypoint.prod.sh"]
|
|
@ -13,4 +13,8 @@ class UserFilter(django_filters.FilterSet):
|
|||||||
"username",
|
"username",
|
||||||
"last_name",
|
"last_name",
|
||||||
"first_name",
|
"first_name",
|
||||||
|
"email",
|
||||||
|
"is_active",
|
||||||
|
"id_card",
|
||||||
|
"mobile",
|
||||||
]
|
]
|
||||||
|
@ -46,9 +46,19 @@ class CustomReadOnlyUserSerializer(serializers.ModelSerializer):
|
|||||||
"username",
|
"username",
|
||||||
"mobile",
|
"mobile",
|
||||||
"address",
|
"address",
|
||||||
|
"id_card",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CustomReadOnlyUserByIDCardSerializer(serializers.ModelSerializer):
|
||||||
|
"""serializer for the user object"""
|
||||||
|
|
||||||
|
class Meta: # type: ignore
|
||||||
|
model = User
|
||||||
|
# fields = "__all__"
|
||||||
|
fields = ("id_card",)
|
||||||
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
class UserSerializer(serializers.ModelSerializer):
|
||||||
"""serializer for the user object"""
|
"""serializer for the user object"""
|
||||||
|
|
||||||
@ -93,13 +103,16 @@ class KnoxTokenSerializer(serializers.ModelSerializer):
|
|||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
class AtollSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta: # type: ignore
|
|
||||||
model = Atoll
|
|
||||||
fields = "__all__"
|
|
||||||
|
|
||||||
|
|
||||||
class IslandSerializer(serializers.ModelSerializer):
|
class IslandSerializer(serializers.ModelSerializer):
|
||||||
class Meta: # type: ignore
|
class Meta: # type: ignore
|
||||||
model = Island
|
model = Island
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class AtollSerializer(serializers.ModelSerializer):
|
||||||
|
islands = IslandSerializer(many=True, read_only=True)
|
||||||
|
|
||||||
|
class Meta: # type: ignore
|
||||||
|
model = Atoll
|
||||||
|
fields = "__all__"
|
||||||
|
depth = 2
|
||||||
|
@ -11,10 +11,12 @@ from .views import (
|
|||||||
UserDetailAPIView,
|
UserDetailAPIView,
|
||||||
healthcheck,
|
healthcheck,
|
||||||
test_email,
|
test_email,
|
||||||
ListCreateAtollView,
|
ListAtollView,
|
||||||
|
CreateAtollView,
|
||||||
RetrieveUpdateDestroyAtollView,
|
RetrieveUpdateDestroyAtollView,
|
||||||
ListCreateIslandView,
|
ListCreateIslandView,
|
||||||
RetrieveUpdateDestroyIslandView,
|
RetrieveUpdateDestroyIslandView,
|
||||||
|
ListUserByIDCardView,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -28,9 +30,11 @@ urlpatterns = [
|
|||||||
# path("auth/", CustomAuthToken.as_view()),
|
# path("auth/", CustomAuthToken.as_view()),
|
||||||
path("users/", ListUserView.as_view(), name="users"),
|
path("users/", ListUserView.as_view(), name="users"),
|
||||||
path("users/<int:pk>/", UserDetailAPIView.as_view(), name="user-detail"),
|
path("users/<int:pk>/", UserDetailAPIView.as_view(), name="user-detail"),
|
||||||
|
path("users/idcard/", ListUserByIDCardView.as_view(), name="users-idcard"),
|
||||||
path("healthcheck/", healthcheck, name="healthcheck"),
|
path("healthcheck/", healthcheck, name="healthcheck"),
|
||||||
path("test/", test_email, name="testemail"),
|
path("test/", test_email, name="testemail"),
|
||||||
path("atolls/", ListCreateAtollView.as_view(), name="atolls"),
|
path("atolls/", ListAtollView.as_view(), name="atolls"),
|
||||||
|
path("atolls/new/", CreateAtollView.as_view(), name="atoll-new"),
|
||||||
path(
|
path(
|
||||||
"atolls/<int:pk>/",
|
"atolls/<int:pk>/",
|
||||||
RetrieveUpdateDestroyAtollView.as_view(),
|
RetrieveUpdateDestroyAtollView.as_view(),
|
||||||
|
20
api/views.py
20
api/views.py
@ -28,6 +28,7 @@ from .serializers import (
|
|||||||
AuthSerializer,
|
AuthSerializer,
|
||||||
CustomUserSerializer,
|
CustomUserSerializer,
|
||||||
CustomReadOnlyUserSerializer,
|
CustomReadOnlyUserSerializer,
|
||||||
|
CustomReadOnlyUserByIDCardSerializer,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -195,6 +196,16 @@ class ListUserView(StaffEditorPermissionMixin, generics.ListAPIView):
|
|||||||
queryset = User.objects.all()
|
queryset = User.objects.all()
|
||||||
|
|
||||||
|
|
||||||
|
class ListUserByIDCardView(generics.ListAPIView):
|
||||||
|
# Create user API view
|
||||||
|
permission_classes = (permissions.AllowAny,)
|
||||||
|
serializer_class = CustomReadOnlyUserByIDCardSerializer
|
||||||
|
filter_backends = [DjangoFilterBackend]
|
||||||
|
filterset_fields = "__all__"
|
||||||
|
filterset_class = UserFilter
|
||||||
|
queryset = User.objects.all()
|
||||||
|
|
||||||
|
|
||||||
class UserDetailAPIView(StaffEditorPermissionMixin, generics.RetrieveAPIView):
|
class UserDetailAPIView(StaffEditorPermissionMixin, generics.RetrieveAPIView):
|
||||||
queryset = User.objects.all()
|
queryset = User.objects.all()
|
||||||
serializer_class = CustomReadOnlyUserSerializer
|
serializer_class = CustomReadOnlyUserSerializer
|
||||||
@ -228,7 +239,7 @@ def test_email(request):
|
|||||||
return Response({"status": "ok"}, status=status.HTTP_200_OK)
|
return Response({"status": "ok"}, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
class ListCreateAtollView(StaffEditorPermissionMixin, generics.ListCreateAPIView):
|
class CreateAtollView(StaffEditorPermissionMixin, generics.CreateAPIView):
|
||||||
serializer_class = AtollSerializer
|
serializer_class = AtollSerializer
|
||||||
queryset = Atoll.objects.all()
|
queryset = Atoll.objects.all()
|
||||||
|
|
||||||
@ -242,6 +253,13 @@ class ListCreateAtollView(StaffEditorPermissionMixin, generics.ListCreateAPIView
|
|||||||
return super().create(request, *args, **kwargs)
|
return super().create(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class ListAtollView(generics.ListAPIView):
|
||||||
|
permission_classes = (permissions.AllowAny,)
|
||||||
|
serializer_class = AtollSerializer
|
||||||
|
queryset = Atoll.objects.all()
|
||||||
|
throttle_classes = () # override throttling
|
||||||
|
|
||||||
|
|
||||||
class RetrieveUpdateDestroyAtollView(
|
class RetrieveUpdateDestroyAtollView(
|
||||||
StaffEditorPermissionMixin, generics.RetrieveUpdateDestroyAPIView
|
StaffEditorPermissionMixin, generics.RetrieveUpdateDestroyAPIView
|
||||||
):
|
):
|
||||||
|
@ -219,7 +219,7 @@ def send_sms_with_callback_token(user, mobile_token, **kwargs):
|
|||||||
"message": base_string % mobile_token.key,
|
"message": base_string % mobile_token.key,
|
||||||
"check_delivery": False,
|
"check_delivery": False,
|
||||||
}
|
}
|
||||||
|
print(mobile_token.key)
|
||||||
response = requests.post(api_url, headers=headers, data=json.dumps(data))
|
response = requests.post(api_url, headers=headers, data=json.dumps(data))
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
return True
|
return True
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
services:
|
|
||||||
api:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: Dockerfile.prod
|
|
||||||
restart: always
|
|
||||||
command: gunicorn apibase.wsgi:application --bind 0.0.0.0:5000 --workers=2
|
|
||||||
volumes:
|
|
||||||
- /home/<username>/docker/council-api/staticfiles:/home/app/api/staticfiles
|
|
||||||
ports:
|
|
||||||
- 5000:5000
|
|
||||||
env_file:
|
|
||||||
- ./.env
|
|
||||||
depends_on:
|
|
||||||
- db
|
|
||||||
- redis
|
|
||||||
|
|
||||||
db:
|
|
||||||
image: postgres:15
|
|
||||||
restart: always
|
|
||||||
volumes:
|
|
||||||
- ./postgres_data:/var/lib/postgresql/data/
|
|
||||||
env_file:
|
|
||||||
- ./.env
|
|
||||||
environment:
|
|
||||||
- POSTGRES_USER=${POSTGRES_USER}
|
|
||||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
|
||||||
- POSTGRES_DB=${POSTGRES_DATABASE}
|
|
||||||
ports:
|
|
||||||
- 5232:5432
|
|
||||||
|
|
||||||
redis:
|
|
||||||
image: "redis:alpine"
|
|
||||||
restart: always
|
|
||||||
expose:
|
|
||||||
- "6379"
|
|
||||||
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
|||||||
services:
|
services:
|
||||||
api:
|
api:
|
||||||
build: .
|
build:
|
||||||
command: python manage.py runserver 0.0.0.0:8000
|
context: .
|
||||||
|
dockerfile: Dockerfile.prod
|
||||||
|
restart: always
|
||||||
|
command: gunicorn apibase.wsgi:application --bind 0.0.0.0:5000 --workers=2
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/usr/src/app/
|
- /home/<username>/docker/council-api/staticfiles:/home/app/api/staticfiles
|
||||||
ports:
|
ports:
|
||||||
- 8000:8000
|
- 5000:5000
|
||||||
env_file:
|
env_file:
|
||||||
- ./.env
|
- ./.env
|
||||||
depends_on:
|
depends_on:
|
||||||
@ -14,17 +17,22 @@ services:
|
|||||||
|
|
||||||
db:
|
db:
|
||||||
image: postgres:15
|
image: postgres:15
|
||||||
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql/data/
|
- ./postgres_data:/var/lib/postgresql/data/
|
||||||
|
env_file:
|
||||||
|
- ./.env
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_USER=${POSTGRES_USER}
|
- POSTGRES_USER=${POSTGRES_USER}
|
||||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||||
- POSTGRES_DB=${POSTGRES_DATABASE}
|
- POSTGRES_DB=${POSTGRES_DATABASE}
|
||||||
|
ports:
|
||||||
|
- 5232:5432
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: "redis:alpine"
|
image: "redis:alpine"
|
||||||
restart: always
|
restart: always
|
||||||
expose:
|
expose:
|
||||||
- "6379"
|
- "6379"
|
||||||
volumes:
|
|
||||||
postgres_data:
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user