mirror of
https://github.com/i701/sarlink-portal-api.git
synced 2025-02-20 19:32:00 +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
|
||||
FROM python:3.11.4-slim-buster
|
||||
FROM python:3.11.4-slim-buster AS builder
|
||||
|
||||
# set work directory
|
||||
WORKDIR /app
|
||||
@ -9,20 +13,59 @@ ENV PYTHONDONTWRITEBYTECODE 1
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
|
||||
# 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
|
||||
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
|
||||
COPY ./requirements.txt .
|
||||
RUN pip install -r requirements.txt
|
||||
RUN pip install --no-cache /wheels/*
|
||||
|
||||
# copy entrypoint.sh
|
||||
COPY ./entrypoint.sh .
|
||||
RUN sed -i 's/\r$//g' /app/entrypoint.sh
|
||||
RUN chmod +x /app/entrypoint.sh
|
||||
# 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 . .
|
||||
COPY . $APP_HOME
|
||||
|
||||
# run entrypoint.sh
|
||||
ENTRYPOINT ["/app/entrypoint.sh"]
|
||||
# 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"]
|
||||
|
@ -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",
|
||||
"last_name",
|
||||
"first_name",
|
||||
"email",
|
||||
"is_active",
|
||||
"id_card",
|
||||
"mobile",
|
||||
]
|
||||
|
@ -46,9 +46,19 @@ class CustomReadOnlyUserSerializer(serializers.ModelSerializer):
|
||||
"username",
|
||||
"mobile",
|
||||
"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):
|
||||
"""serializer for the user object"""
|
||||
|
||||
@ -93,13 +103,16 @@ class KnoxTokenSerializer(serializers.ModelSerializer):
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class AtollSerializer(serializers.ModelSerializer):
|
||||
class Meta: # type: ignore
|
||||
model = Atoll
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class IslandSerializer(serializers.ModelSerializer):
|
||||
class Meta: # type: ignore
|
||||
model = Island
|
||||
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,
|
||||
healthcheck,
|
||||
test_email,
|
||||
ListCreateAtollView,
|
||||
ListAtollView,
|
||||
CreateAtollView,
|
||||
RetrieveUpdateDestroyAtollView,
|
||||
ListCreateIslandView,
|
||||
RetrieveUpdateDestroyIslandView,
|
||||
ListUserByIDCardView,
|
||||
)
|
||||
|
||||
|
||||
@ -28,9 +30,11 @@ urlpatterns = [
|
||||
# path("auth/", CustomAuthToken.as_view()),
|
||||
path("users/", ListUserView.as_view(), name="users"),
|
||||
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("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(
|
||||
"atolls/<int:pk>/",
|
||||
RetrieveUpdateDestroyAtollView.as_view(),
|
||||
|
20
api/views.py
20
api/views.py
@ -28,6 +28,7 @@ from .serializers import (
|
||||
AuthSerializer,
|
||||
CustomUserSerializer,
|
||||
CustomReadOnlyUserSerializer,
|
||||
CustomReadOnlyUserByIDCardSerializer,
|
||||
)
|
||||
|
||||
|
||||
@ -195,6 +196,16 @@ class ListUserView(StaffEditorPermissionMixin, generics.ListAPIView):
|
||||
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):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = CustomReadOnlyUserSerializer
|
||||
@ -228,7 +239,7 @@ def test_email(request):
|
||||
return Response({"status": "ok"}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class ListCreateAtollView(StaffEditorPermissionMixin, generics.ListCreateAPIView):
|
||||
class CreateAtollView(StaffEditorPermissionMixin, generics.CreateAPIView):
|
||||
serializer_class = AtollSerializer
|
||||
queryset = Atoll.objects.all()
|
||||
|
||||
@ -242,6 +253,13 @@ class ListCreateAtollView(StaffEditorPermissionMixin, generics.ListCreateAPIView
|
||||
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(
|
||||
StaffEditorPermissionMixin, generics.RetrieveUpdateDestroyAPIView
|
||||
):
|
||||
|
@ -219,7 +219,7 @@ def send_sms_with_callback_token(user, mobile_token, **kwargs):
|
||||
"message": base_string % mobile_token.key,
|
||||
"check_delivery": False,
|
||||
}
|
||||
|
||||
print(mobile_token.key)
|
||||
response = requests.post(api_url, headers=headers, data=json.dumps(data))
|
||||
if response.status_code == 200:
|
||||
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:
|
||||
api:
|
||||
build: .
|
||||
command: python manage.py runserver 0.0.0.0:8000
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.prod
|
||||
restart: always
|
||||
command: gunicorn apibase.wsgi:application --bind 0.0.0.0:5000 --workers=2
|
||||
volumes:
|
||||
- ./:/usr/src/app/
|
||||
- /home/<username>/docker/council-api/staticfiles:/home/app/api/staticfiles
|
||||
ports:
|
||||
- 8000:8000
|
||||
- 5000:5000
|
||||
env_file:
|
||||
- ./.env
|
||||
depends_on:
|
||||
@ -14,17 +17,22 @@ services:
|
||||
|
||||
db:
|
||||
image: postgres:15
|
||||
restart: always
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data/
|
||||
- ./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"
|
||||
volumes:
|
||||
postgres_data:
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user