diff --git a/.woodpecker.yml b/.woodpecker.yml deleted file mode 100644 index 8836806..0000000 --- a/.woodpecker.yml +++ /dev/null @@ -1,33 +0,0 @@ -# .woodpecker.yml -steps: - - name: build - image: docker - when: - - branch: master - event: push - commands: - - docker build --platform linux/arm64 --no-cache -t "$IMAGE" . - - echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY" --password-stdin -u "$REGISTRY_USERNAME" - - docker push "$IMAGE" - volumes: - - /var/run/docker.sock:/var/run/docker.sock - secrets: [REGISTRY, REGISTRY_USERNAME, REGISTRY_PASSWORD, IMAGE] - - name: deploy - image: docker - when: - - branch: master - event: push - commands: - - mkdir -p /root/.ssh/ - - echo "$SSH_KEY" | tr -d '\r' > /root/.ssh/id_rsa - - chmod 600 /root/.ssh/id_rsa - - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > /root/.ssh/config - - ssh "$REMOTE_HOST" " - cd $PROJECT_DIRECTORY; - docker-compose -f docker-compose.demo.yml down; - docker image rm "$IMAGE" || true; - docker volume rm "$VOLUME" || true; - docker pull "$IMAGE"; - docker compose -f docker-compose.demo.yml up -d; - docker image prune -af;" - secrets: [SSH_KEY, REMOTE_HOST, PROJECT_DIRECTORY, IMAGE, VOLUME] diff --git a/.woodpecker/.build.yml b/.woodpecker/.build.yml new file mode 100644 index 0000000..67c27c7 --- /dev/null +++ b/.woodpecker/.build.yml @@ -0,0 +1,22 @@ +labels: + platform: linux/amd64 + +steps: + - name: build + image: docker + when: + - branch: master + event: push + commands: + - docker build -t "$REGISTRY_IMAGE_TAG" . + - echo "$FORGEJO_REGISTRY_PASSWORD" | docker login "$FORGEJO_REGISTRY_URL" --password-stdin -u "$FORGEJO_REGISTRY_USERNAME" + - docker push "$REGISTRY_IMAGE_TAG" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + secrets: + [ + FORGEJO_REGISTRY_URL, + FORGEJO_REGISTRY_USERNAME, + FORGEJO_REGISTRY_PASSWORD, + REGISTRY_IMAGE_TAG, + ] diff --git a/.woodpecker/.deploy.yml b/.woodpecker/.deploy.yml new file mode 100644 index 0000000..1e9d6de --- /dev/null +++ b/.woodpecker/.deploy.yml @@ -0,0 +1,31 @@ +steps: + - name: deploy + image: alpine:3.20 + when: + - branch: master + event: push + commands: + - apk add openssh + - mkdir -p /root/.ssh/ + - echo "$WOODPECKER_SSH_KEY" | tr -d '\r' > /root/.ssh/id_rsa + - chmod 600 /root/.ssh/id_rsa + - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > /root/.ssh/config + - ssh "$SSH_HOST" ' + cd "$PROJECT_DIRECTORY"; + docker-compose down; + docker image rm "$REGISTRY_IMAGE_TAG" || true; + docker volume rm "$DOCKER_DB_VOLUME" || true; + docker pull "$REGISTRY_IMAGE_TAG"; + docker-compose up -d; + docker image prune -af;' + secrets: + [ + SSH_HOST, + PROJECT_DIRECTORY, + WOODPECKER_SSH_KEY, + REGISTRY_IMAGE_TAG, + DOCKER_DB_VOLUME, + ] + +depends_on: + - build diff --git a/Dockerfile b/Dockerfile index fef478e..70158f1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,18 +14,10 @@ RUN chown root:root /tmp RUN chmod 1777 /tmp # Install packages -RUN apt clean -RUN apt update -RUN apt install -y graphviz libgraphviz-dev graphviz-dev wget zip -RUN pip3 install --upgrade pip -RUN pip3 install --no-cache-dir -r requirements.txt +RUN apt update && apt install -y graphviz libgraphviz-dev graphviz-dev wget zip chromium chromium-driver firefox-esr +RUN pip3 install --upgrade pip && pip3 install --no-cache-dir -r requirements.txt -# Install Chrome & Chromedriver -RUN apt install -y chromium chromium-driver - -# Install Firefox and Geckodriver -RUN apt install -y firefox-esr -# Download the latest Geckodriver and install it +# (Firefox) Download the latest Geckodriver and install it ENV GECKODRIVER_VERSION=latest RUN wget -O geckodriver.tar.gz https://github.com/mozilla/geckodriver/releases/download/v0.35.0/geckodriver-v0.35.0-linux64.tar.gz RUN tar -zxf geckodriver.tar.gz -C /usr/bin diff --git a/README.md b/README.md index 093c61b..9cff4a1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## DRF-Template -![Build Status](https://woodpecker.06222001.xyz/api/badges/1/status.svg) +![Build Status](https://woodpecker.06222001.xyz/api/badges/2/status.svg) ![Demo Page Status](https://stats.06222001.xyz/api/badge/119/status) This is a Django template that I personally use for my projects. This covers the following @@ -27,7 +27,7 @@ When using `docker-compose.dev.yml`, the entire project directory is mounted ont ### Deployment -A sample `docker-compose.demo.yml` is provided which I use in hosting the demo. DEBUG should be set to False when deploying as to not expose the URLs fro Celery Flower and the Django Silk Profiler. The local Inbucket container is not present so make sure to specify an external SMTP server to process emails properly. +A sample `docker-compose.yml` is provided which I use in hosting the demo. DEBUG should be set to False when deploying as to not expose the URLs fro Celery Flower and the Django Silk Profiler. The local Inbucket container is not present so make sure to specify an external SMTP server to process emails properly. ### URLs diff --git a/backend/schema.yml b/backend/schema.yml index 743c2ff..7162675 100644 --- a/backend/schema.yml +++ b/backend/schema.yml @@ -6,12 +6,12 @@ info: paths: /api/v1/accounts/jwt/create/: post: - operationId: api_v1_accounts_jwt_create_create + operationId: accounts_jwt_create_create description: |- Takes a set of user credentials and returns an access and refresh JSON web token pair to prove the authentication of those credentials. tags: - - api + - accounts requestBody: content: application/json: @@ -33,12 +33,12 @@ paths: description: '' /api/v1/accounts/jwt/refresh/: post: - operationId: api_v1_accounts_jwt_refresh_create + operationId: accounts_jwt_refresh_create description: |- Takes a refresh type JSON web token and returns an access type JSON web token if the refresh token is valid. tags: - - api + - accounts requestBody: content: application/json: @@ -60,12 +60,12 @@ paths: description: '' /api/v1/accounts/jwt/verify/: post: - operationId: api_v1_accounts_jwt_verify_create + operationId: accounts_jwt_verify_create description: |- Takes a token and indicates if it is valid. This view provides no information about a token's fitness for a particular use. tags: - - api + - accounts requestBody: content: application/json: @@ -87,9 +87,9 @@ paths: description: '' /api/v1/accounts/users/: get: - operationId: api_v1_accounts_users_list + operationId: accounts_users_list tags: - - api + - accounts security: - jwtAuth: [] responses: @@ -102,9 +102,9 @@ paths: $ref: '#/components/schemas/CustomUser' description: '' post: - operationId: api_v1_accounts_users_create + operationId: accounts_users_create tags: - - api + - accounts requestBody: content: application/json: @@ -129,7 +129,7 @@ paths: description: '' /api/v1/accounts/users/{id}/: get: - operationId: api_v1_accounts_users_retrieve + operationId: accounts_users_retrieve parameters: - in: path name: id @@ -138,7 +138,7 @@ paths: description: A unique integer value identifying this user. required: true tags: - - api + - accounts security: - jwtAuth: [] - {} @@ -150,7 +150,7 @@ paths: $ref: '#/components/schemas/CustomUser' description: '' put: - operationId: api_v1_accounts_users_update + operationId: accounts_users_update parameters: - in: path name: id @@ -159,7 +159,7 @@ paths: description: A unique integer value identifying this user. required: true tags: - - api + - accounts requestBody: content: application/json: @@ -183,7 +183,7 @@ paths: $ref: '#/components/schemas/CustomUser' description: '' patch: - operationId: api_v1_accounts_users_partial_update + operationId: accounts_users_partial_update parameters: - in: path name: id @@ -192,7 +192,7 @@ paths: description: A unique integer value identifying this user. required: true tags: - - api + - accounts requestBody: content: application/json: @@ -215,7 +215,7 @@ paths: $ref: '#/components/schemas/CustomUser' description: '' delete: - operationId: api_v1_accounts_users_destroy + operationId: accounts_users_destroy parameters: - in: path name: id @@ -224,7 +224,7 @@ paths: description: A unique integer value identifying this user. required: true tags: - - api + - accounts security: - jwtAuth: [] responses: @@ -232,9 +232,9 @@ paths: description: No response body /api/v1/accounts/users/activation/: post: - operationId: api_v1_accounts_users_activation_create + operationId: accounts_users_activation_create tags: - - api + - accounts requestBody: content: application/json: @@ -259,9 +259,9 @@ paths: description: '' /api/v1/accounts/users/me/: get: - operationId: api_v1_accounts_users_me_retrieve + operationId: accounts_users_me_retrieve tags: - - api + - accounts security: - jwtAuth: [] - {} @@ -273,9 +273,9 @@ paths: $ref: '#/components/schemas/CustomUser' description: '' put: - operationId: api_v1_accounts_users_me_update + operationId: accounts_users_me_update tags: - - api + - accounts requestBody: content: application/json: @@ -299,9 +299,9 @@ paths: $ref: '#/components/schemas/CustomUser' description: '' patch: - operationId: api_v1_accounts_users_me_partial_update + operationId: accounts_users_me_partial_update tags: - - api + - accounts requestBody: content: application/json: @@ -324,9 +324,9 @@ paths: $ref: '#/components/schemas/CustomUser' description: '' delete: - operationId: api_v1_accounts_users_me_destroy + operationId: accounts_users_me_destroy tags: - - api + - accounts security: - jwtAuth: [] responses: @@ -334,9 +334,9 @@ paths: description: No response body /api/v1/accounts/users/resend_activation/: post: - operationId: api_v1_accounts_users_resend_activation_create + operationId: accounts_users_resend_activation_create tags: - - api + - accounts requestBody: content: application/json: @@ -361,9 +361,9 @@ paths: description: '' /api/v1/accounts/users/reset_password/: post: - operationId: api_v1_accounts_users_reset_password_create + operationId: accounts_users_reset_password_create tags: - - api + - accounts requestBody: content: application/json: @@ -388,9 +388,9 @@ paths: description: '' /api/v1/accounts/users/reset_password_confirm/: post: - operationId: api_v1_accounts_users_reset_password_confirm_create + operationId: accounts_users_reset_password_confirm_create tags: - - api + - accounts requestBody: content: application/json: @@ -415,9 +415,9 @@ paths: description: '' /api/v1/accounts/users/reset_username/: post: - operationId: api_v1_accounts_users_reset_username_create + operationId: accounts_users_reset_username_create tags: - - api + - accounts requestBody: content: application/json: @@ -441,9 +441,9 @@ paths: description: '' /api/v1/accounts/users/reset_username_confirm/: post: - operationId: api_v1_accounts_users_reset_username_confirm_create + operationId: accounts_users_reset_username_confirm_create tags: - - api + - accounts requestBody: content: application/json: @@ -467,9 +467,9 @@ paths: description: '' /api/v1/accounts/users/set_password/: post: - operationId: api_v1_accounts_users_set_password_create + operationId: accounts_users_set_password_create tags: - - api + - accounts requestBody: content: application/json: @@ -493,9 +493,9 @@ paths: description: '' /api/v1/accounts/users/set_username/: post: - operationId: api_v1_accounts_users_set_username_create + operationId: accounts_users_set_username_create tags: - - api + - accounts requestBody: content: application/json: @@ -519,9 +519,9 @@ paths: description: '' /api/v1/billing/: get: - operationId: api_v1_billing_retrieve + operationId: billing_retrieve tags: - - api + - billing security: - jwtAuth: [] responses: @@ -529,9 +529,9 @@ paths: description: No response body /api/v1/notifications/: get: - operationId: api_v1_notifications_list + operationId: notifications_list tags: - - api + - notifications security: - jwtAuth: [] - {} @@ -546,7 +546,7 @@ paths: description: '' /api/v1/notifications/{id}/: get: - operationId: api_v1_notifications_retrieve + operationId: notifications_retrieve parameters: - in: path name: id @@ -555,7 +555,7 @@ paths: description: A unique integer value identifying this notification. required: true tags: - - api + - notifications security: - jwtAuth: [] - {} @@ -567,7 +567,7 @@ paths: $ref: '#/components/schemas/Notification' description: '' patch: - operationId: api_v1_notifications_partial_update + operationId: notifications_partial_update parameters: - in: path name: id @@ -576,7 +576,7 @@ paths: description: A unique integer value identifying this notification. required: true tags: - - api + - notifications requestBody: content: application/json: @@ -599,7 +599,7 @@ paths: $ref: '#/components/schemas/Notification' description: '' delete: - operationId: api_v1_notifications_destroy + operationId: notifications_destroy parameters: - in: path name: id @@ -608,7 +608,7 @@ paths: description: A unique integer value identifying this notification. required: true tags: - - api + - notifications security: - jwtAuth: [] - {} @@ -617,9 +617,9 @@ paths: description: No response body /api/v1/stripe/checkout_session/: post: - operationId: api_v1_stripe_checkout_session_create + operationId: stripe_checkout_session_create tags: - - api + - stripe requestBody: content: application/json: @@ -639,9 +639,9 @@ paths: description: No response body /api/v1/stripe/webhook/: post: - operationId: api_v1_stripe_webhook_create + operationId: stripe_webhook_create tags: - - api + - stripe security: - jwtAuth: [] - {} @@ -650,9 +650,9 @@ paths: description: No response body /api/v1/subscriptions/plans/: get: - operationId: api_v1_subscriptions_plans_list + operationId: subscriptions_plans_list tags: - - api + - subscriptions security: - jwtAuth: [] - {} @@ -667,7 +667,7 @@ paths: description: '' /api/v1/subscriptions/plans/{id}/: get: - operationId: api_v1_subscriptions_plans_retrieve + operationId: subscriptions_plans_retrieve parameters: - in: path name: id @@ -676,7 +676,7 @@ paths: description: A unique integer value identifying this subscription plan. required: true tags: - - api + - subscriptions security: - jwtAuth: [] - {} @@ -689,9 +689,9 @@ paths: description: '' /api/v1/subscriptions/self/: get: - operationId: api_v1_subscriptions_self_list + operationId: subscriptions_self_list tags: - - api + - subscriptions security: - jwtAuth: [] responses: @@ -705,7 +705,7 @@ paths: description: '' /api/v1/subscriptions/self/{id}/: get: - operationId: api_v1_subscriptions_self_retrieve + operationId: subscriptions_self_retrieve parameters: - in: path name: id @@ -714,7 +714,7 @@ paths: description: A unique integer value identifying this user subscription. required: true tags: - - api + - subscriptions security: - jwtAuth: [] responses: @@ -726,9 +726,9 @@ paths: description: '' /api/v1/subscriptions/user_group/: get: - operationId: api_v1_subscriptions_user_group_list + operationId: subscriptions_user_group_list tags: - - api + - subscriptions security: - jwtAuth: [] responses: @@ -742,7 +742,7 @@ paths: description: '' /api/v1/subscriptions/user_group/{id}/: get: - operationId: api_v1_subscriptions_user_group_retrieve + operationId: subscriptions_user_group_retrieve parameters: - in: path name: id @@ -751,7 +751,7 @@ paths: description: A unique integer value identifying this user subscription. required: true tags: - - api + - subscriptions security: - jwtAuth: [] responses: diff --git a/backend/webdriver/tasks.py b/backend/webdriver/tasks.py index 50c355b..33b390a 100644 --- a/backend/webdriver/tasks.py +++ b/backend/webdriver/tasks.py @@ -23,7 +23,8 @@ def sample_selenium_task(): @shared_task(autoretry_for=(Exception,), retry_kwargs={'max_retries': 3, 'countdown': 5}) def simple_google_search(): - driver = setup_webdriver(use_proxy=False, use_saved_session=False) + driver = setup_webdriver(driver_type="firefox", + use_proxy=False, use_saved_session=False) driver.get(f"https://google.com/") google_search(driver, search_term="cat blog posts") diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 37f8422..03ea04d 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,5 +1,3 @@ -version: "3.9" - services: # Django Backend django: diff --git a/docker-compose.demo.yml b/docker-compose.yml similarity index 84% rename from docker-compose.demo.yml rename to docker-compose.yml index 803b6f2..e935f1c 100644 --- a/docker-compose.demo.yml +++ b/docker-compose.yml @@ -1,10 +1,8 @@ -version: "3.9" - services: # Django Backend django: env_file: .env - image: keannu125/drf-template:latest + image: git.06222001.xyz/keannu125/drf_template:latest ports: - "${BACKEND_PORT}:8000" environment: @@ -12,16 +10,18 @@ services: - RUN_TYPE=web depends_on: - postgres + - pgbouncer # Django Celery Worker celery: env_file: .env environment: - RUN_TYPE=worker - image: keannu125/drf-template:latest + image: git.06222001.xyz/keannu125/drf_template:latest depends_on: - django - postgres + - pgbouncer - redis # Run multiple worker instances scale: 4 @@ -31,11 +31,12 @@ services: env_file: .env environment: - RUN_TYPE=beat - image: keannu125/drf-template:latest + image: git.06222001.xyz/keannu125/drf_template:latest depends_on: - celery - django - postgres + - pgbouncer - redis # SQL Database @@ -47,7 +48,7 @@ services: - POSTGRES_USER=${DB_USERNAME} - POSTGRES_PASSWORD=${DB_PASSWORD} volumes: - - db-data:/var/lib/postgresql/data + - db_data:/var/lib/postgresql/data command: postgres -c max_connections=200 # DB Bouncer @@ -76,4 +77,4 @@ services: command: listen --forward-to django:8000/api/v1/stripe/webhook/ volumes: - db-data: + db_data: