Compare commits

..

13 commits

9 changed files with 136 additions and 124 deletions

View file

@ -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]

22
.woodpecker/.build.yml Normal file
View file

@ -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,
]

31
.woodpecker/.deploy.yml Normal file
View file

@ -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

View file

@ -14,18 +14,10 @@ RUN chown root:root /tmp
RUN chmod 1777 /tmp RUN chmod 1777 /tmp
# Install packages # Install packages
RUN apt clean RUN apt update && apt install -y graphviz libgraphviz-dev graphviz-dev wget zip chromium chromium-driver firefox-esr
RUN apt update RUN pip3 install --upgrade pip && pip3 install --no-cache-dir -r requirements.txt
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
# Install Chrome & Chromedriver # (Firefox) Download the latest Geckodriver and install it
RUN apt install -y chromium chromium-driver
# Install Firefox and Geckodriver
RUN apt install -y firefox-esr
# Download the latest Geckodriver and install it
ENV GECKODRIVER_VERSION=latest 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 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 RUN tar -zxf geckodriver.tar.gz -C /usr/bin

View file

@ -1,6 +1,6 @@
## DRF-Template ## 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) ![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 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 ### 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 ### URLs

View file

@ -6,12 +6,12 @@ info:
paths: paths:
/api/v1/accounts/jwt/create/: /api/v1/accounts/jwt/create/:
post: post:
operationId: api_v1_accounts_jwt_create_create operationId: accounts_jwt_create_create
description: |- description: |-
Takes a set of user credentials and returns an access and refresh JSON web Takes a set of user credentials and returns an access and refresh JSON web
token pair to prove the authentication of those credentials. token pair to prove the authentication of those credentials.
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -33,12 +33,12 @@ paths:
description: '' description: ''
/api/v1/accounts/jwt/refresh/: /api/v1/accounts/jwt/refresh/:
post: post:
operationId: api_v1_accounts_jwt_refresh_create operationId: accounts_jwt_refresh_create
description: |- description: |-
Takes a refresh type JSON web token and returns an access type JSON web Takes a refresh type JSON web token and returns an access type JSON web
token if the refresh token is valid. token if the refresh token is valid.
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -60,12 +60,12 @@ paths:
description: '' description: ''
/api/v1/accounts/jwt/verify/: /api/v1/accounts/jwt/verify/:
post: post:
operationId: api_v1_accounts_jwt_verify_create operationId: accounts_jwt_verify_create
description: |- description: |-
Takes a token and indicates if it is valid. This view provides no Takes a token and indicates if it is valid. This view provides no
information about a token's fitness for a particular use. information about a token's fitness for a particular use.
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -87,9 +87,9 @@ paths:
description: '' description: ''
/api/v1/accounts/users/: /api/v1/accounts/users/:
get: get:
operationId: api_v1_accounts_users_list operationId: accounts_users_list
tags: tags:
- api - accounts
security: security:
- jwtAuth: [] - jwtAuth: []
responses: responses:
@ -102,9 +102,9 @@ paths:
$ref: '#/components/schemas/CustomUser' $ref: '#/components/schemas/CustomUser'
description: '' description: ''
post: post:
operationId: api_v1_accounts_users_create operationId: accounts_users_create
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -129,7 +129,7 @@ paths:
description: '' description: ''
/api/v1/accounts/users/{id}/: /api/v1/accounts/users/{id}/:
get: get:
operationId: api_v1_accounts_users_retrieve operationId: accounts_users_retrieve
parameters: parameters:
- in: path - in: path
name: id name: id
@ -138,7 +138,7 @@ paths:
description: A unique integer value identifying this user. description: A unique integer value identifying this user.
required: true required: true
tags: tags:
- api - accounts
security: security:
- jwtAuth: [] - jwtAuth: []
- {} - {}
@ -150,7 +150,7 @@ paths:
$ref: '#/components/schemas/CustomUser' $ref: '#/components/schemas/CustomUser'
description: '' description: ''
put: put:
operationId: api_v1_accounts_users_update operationId: accounts_users_update
parameters: parameters:
- in: path - in: path
name: id name: id
@ -159,7 +159,7 @@ paths:
description: A unique integer value identifying this user. description: A unique integer value identifying this user.
required: true required: true
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -183,7 +183,7 @@ paths:
$ref: '#/components/schemas/CustomUser' $ref: '#/components/schemas/CustomUser'
description: '' description: ''
patch: patch:
operationId: api_v1_accounts_users_partial_update operationId: accounts_users_partial_update
parameters: parameters:
- in: path - in: path
name: id name: id
@ -192,7 +192,7 @@ paths:
description: A unique integer value identifying this user. description: A unique integer value identifying this user.
required: true required: true
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -215,7 +215,7 @@ paths:
$ref: '#/components/schemas/CustomUser' $ref: '#/components/schemas/CustomUser'
description: '' description: ''
delete: delete:
operationId: api_v1_accounts_users_destroy operationId: accounts_users_destroy
parameters: parameters:
- in: path - in: path
name: id name: id
@ -224,7 +224,7 @@ paths:
description: A unique integer value identifying this user. description: A unique integer value identifying this user.
required: true required: true
tags: tags:
- api - accounts
security: security:
- jwtAuth: [] - jwtAuth: []
responses: responses:
@ -232,9 +232,9 @@ paths:
description: No response body description: No response body
/api/v1/accounts/users/activation/: /api/v1/accounts/users/activation/:
post: post:
operationId: api_v1_accounts_users_activation_create operationId: accounts_users_activation_create
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -259,9 +259,9 @@ paths:
description: '' description: ''
/api/v1/accounts/users/me/: /api/v1/accounts/users/me/:
get: get:
operationId: api_v1_accounts_users_me_retrieve operationId: accounts_users_me_retrieve
tags: tags:
- api - accounts
security: security:
- jwtAuth: [] - jwtAuth: []
- {} - {}
@ -273,9 +273,9 @@ paths:
$ref: '#/components/schemas/CustomUser' $ref: '#/components/schemas/CustomUser'
description: '' description: ''
put: put:
operationId: api_v1_accounts_users_me_update operationId: accounts_users_me_update
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -299,9 +299,9 @@ paths:
$ref: '#/components/schemas/CustomUser' $ref: '#/components/schemas/CustomUser'
description: '' description: ''
patch: patch:
operationId: api_v1_accounts_users_me_partial_update operationId: accounts_users_me_partial_update
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -324,9 +324,9 @@ paths:
$ref: '#/components/schemas/CustomUser' $ref: '#/components/schemas/CustomUser'
description: '' description: ''
delete: delete:
operationId: api_v1_accounts_users_me_destroy operationId: accounts_users_me_destroy
tags: tags:
- api - accounts
security: security:
- jwtAuth: [] - jwtAuth: []
responses: responses:
@ -334,9 +334,9 @@ paths:
description: No response body description: No response body
/api/v1/accounts/users/resend_activation/: /api/v1/accounts/users/resend_activation/:
post: post:
operationId: api_v1_accounts_users_resend_activation_create operationId: accounts_users_resend_activation_create
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -361,9 +361,9 @@ paths:
description: '' description: ''
/api/v1/accounts/users/reset_password/: /api/v1/accounts/users/reset_password/:
post: post:
operationId: api_v1_accounts_users_reset_password_create operationId: accounts_users_reset_password_create
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -388,9 +388,9 @@ paths:
description: '' description: ''
/api/v1/accounts/users/reset_password_confirm/: /api/v1/accounts/users/reset_password_confirm/:
post: post:
operationId: api_v1_accounts_users_reset_password_confirm_create operationId: accounts_users_reset_password_confirm_create
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -415,9 +415,9 @@ paths:
description: '' description: ''
/api/v1/accounts/users/reset_username/: /api/v1/accounts/users/reset_username/:
post: post:
operationId: api_v1_accounts_users_reset_username_create operationId: accounts_users_reset_username_create
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -441,9 +441,9 @@ paths:
description: '' description: ''
/api/v1/accounts/users/reset_username_confirm/: /api/v1/accounts/users/reset_username_confirm/:
post: post:
operationId: api_v1_accounts_users_reset_username_confirm_create operationId: accounts_users_reset_username_confirm_create
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -467,9 +467,9 @@ paths:
description: '' description: ''
/api/v1/accounts/users/set_password/: /api/v1/accounts/users/set_password/:
post: post:
operationId: api_v1_accounts_users_set_password_create operationId: accounts_users_set_password_create
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -493,9 +493,9 @@ paths:
description: '' description: ''
/api/v1/accounts/users/set_username/: /api/v1/accounts/users/set_username/:
post: post:
operationId: api_v1_accounts_users_set_username_create operationId: accounts_users_set_username_create
tags: tags:
- api - accounts
requestBody: requestBody:
content: content:
application/json: application/json:
@ -519,9 +519,9 @@ paths:
description: '' description: ''
/api/v1/billing/: /api/v1/billing/:
get: get:
operationId: api_v1_billing_retrieve operationId: billing_retrieve
tags: tags:
- api - billing
security: security:
- jwtAuth: [] - jwtAuth: []
responses: responses:
@ -529,9 +529,9 @@ paths:
description: No response body description: No response body
/api/v1/notifications/: /api/v1/notifications/:
get: get:
operationId: api_v1_notifications_list operationId: notifications_list
tags: tags:
- api - notifications
security: security:
- jwtAuth: [] - jwtAuth: []
- {} - {}
@ -546,7 +546,7 @@ paths:
description: '' description: ''
/api/v1/notifications/{id}/: /api/v1/notifications/{id}/:
get: get:
operationId: api_v1_notifications_retrieve operationId: notifications_retrieve
parameters: parameters:
- in: path - in: path
name: id name: id
@ -555,7 +555,7 @@ paths:
description: A unique integer value identifying this notification. description: A unique integer value identifying this notification.
required: true required: true
tags: tags:
- api - notifications
security: security:
- jwtAuth: [] - jwtAuth: []
- {} - {}
@ -567,7 +567,7 @@ paths:
$ref: '#/components/schemas/Notification' $ref: '#/components/schemas/Notification'
description: '' description: ''
patch: patch:
operationId: api_v1_notifications_partial_update operationId: notifications_partial_update
parameters: parameters:
- in: path - in: path
name: id name: id
@ -576,7 +576,7 @@ paths:
description: A unique integer value identifying this notification. description: A unique integer value identifying this notification.
required: true required: true
tags: tags:
- api - notifications
requestBody: requestBody:
content: content:
application/json: application/json:
@ -599,7 +599,7 @@ paths:
$ref: '#/components/schemas/Notification' $ref: '#/components/schemas/Notification'
description: '' description: ''
delete: delete:
operationId: api_v1_notifications_destroy operationId: notifications_destroy
parameters: parameters:
- in: path - in: path
name: id name: id
@ -608,7 +608,7 @@ paths:
description: A unique integer value identifying this notification. description: A unique integer value identifying this notification.
required: true required: true
tags: tags:
- api - notifications
security: security:
- jwtAuth: [] - jwtAuth: []
- {} - {}
@ -617,9 +617,9 @@ paths:
description: No response body description: No response body
/api/v1/stripe/checkout_session/: /api/v1/stripe/checkout_session/:
post: post:
operationId: api_v1_stripe_checkout_session_create operationId: stripe_checkout_session_create
tags: tags:
- api - stripe
requestBody: requestBody:
content: content:
application/json: application/json:
@ -639,9 +639,9 @@ paths:
description: No response body description: No response body
/api/v1/stripe/webhook/: /api/v1/stripe/webhook/:
post: post:
operationId: api_v1_stripe_webhook_create operationId: stripe_webhook_create
tags: tags:
- api - stripe
security: security:
- jwtAuth: [] - jwtAuth: []
- {} - {}
@ -650,9 +650,9 @@ paths:
description: No response body description: No response body
/api/v1/subscriptions/plans/: /api/v1/subscriptions/plans/:
get: get:
operationId: api_v1_subscriptions_plans_list operationId: subscriptions_plans_list
tags: tags:
- api - subscriptions
security: security:
- jwtAuth: [] - jwtAuth: []
- {} - {}
@ -667,7 +667,7 @@ paths:
description: '' description: ''
/api/v1/subscriptions/plans/{id}/: /api/v1/subscriptions/plans/{id}/:
get: get:
operationId: api_v1_subscriptions_plans_retrieve operationId: subscriptions_plans_retrieve
parameters: parameters:
- in: path - in: path
name: id name: id
@ -676,7 +676,7 @@ paths:
description: A unique integer value identifying this subscription plan. description: A unique integer value identifying this subscription plan.
required: true required: true
tags: tags:
- api - subscriptions
security: security:
- jwtAuth: [] - jwtAuth: []
- {} - {}
@ -689,9 +689,9 @@ paths:
description: '' description: ''
/api/v1/subscriptions/self/: /api/v1/subscriptions/self/:
get: get:
operationId: api_v1_subscriptions_self_list operationId: subscriptions_self_list
tags: tags:
- api - subscriptions
security: security:
- jwtAuth: [] - jwtAuth: []
responses: responses:
@ -705,7 +705,7 @@ paths:
description: '' description: ''
/api/v1/subscriptions/self/{id}/: /api/v1/subscriptions/self/{id}/:
get: get:
operationId: api_v1_subscriptions_self_retrieve operationId: subscriptions_self_retrieve
parameters: parameters:
- in: path - in: path
name: id name: id
@ -714,7 +714,7 @@ paths:
description: A unique integer value identifying this user subscription. description: A unique integer value identifying this user subscription.
required: true required: true
tags: tags:
- api - subscriptions
security: security:
- jwtAuth: [] - jwtAuth: []
responses: responses:
@ -726,9 +726,9 @@ paths:
description: '' description: ''
/api/v1/subscriptions/user_group/: /api/v1/subscriptions/user_group/:
get: get:
operationId: api_v1_subscriptions_user_group_list operationId: subscriptions_user_group_list
tags: tags:
- api - subscriptions
security: security:
- jwtAuth: [] - jwtAuth: []
responses: responses:
@ -742,7 +742,7 @@ paths:
description: '' description: ''
/api/v1/subscriptions/user_group/{id}/: /api/v1/subscriptions/user_group/{id}/:
get: get:
operationId: api_v1_subscriptions_user_group_retrieve operationId: subscriptions_user_group_retrieve
parameters: parameters:
- in: path - in: path
name: id name: id
@ -751,7 +751,7 @@ paths:
description: A unique integer value identifying this user subscription. description: A unique integer value identifying this user subscription.
required: true required: true
tags: tags:
- api - subscriptions
security: security:
- jwtAuth: [] - jwtAuth: []
responses: responses:

View file

@ -23,7 +23,8 @@ def sample_selenium_task():
@shared_task(autoretry_for=(Exception,), retry_kwargs={'max_retries': 3, 'countdown': 5}) @shared_task(autoretry_for=(Exception,), retry_kwargs={'max_retries': 3, 'countdown': 5})
def simple_google_search(): 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/") driver.get(f"https://google.com/")
google_search(driver, search_term="cat blog posts") google_search(driver, search_term="cat blog posts")

View file

@ -1,5 +1,3 @@
version: "3.9"
services: services:
# Django Backend # Django Backend
django: django:

View file

@ -1,10 +1,8 @@
version: "3.9"
services: services:
# Django Backend # Django Backend
django: django:
env_file: .env env_file: .env
image: keannu125/drf-template:latest image: git.06222001.xyz/keannu125/drf_template:latest
ports: ports:
- "${BACKEND_PORT}:8000" - "${BACKEND_PORT}:8000"
environment: environment:
@ -12,16 +10,18 @@ services:
- RUN_TYPE=web - RUN_TYPE=web
depends_on: depends_on:
- postgres - postgres
- pgbouncer
# Django Celery Worker # Django Celery Worker
celery: celery:
env_file: .env env_file: .env
environment: environment:
- RUN_TYPE=worker - RUN_TYPE=worker
image: keannu125/drf-template:latest image: git.06222001.xyz/keannu125/drf_template:latest
depends_on: depends_on:
- django - django
- postgres - postgres
- pgbouncer
- redis - redis
# Run multiple worker instances # Run multiple worker instances
scale: 4 scale: 4
@ -31,11 +31,12 @@ services:
env_file: .env env_file: .env
environment: environment:
- RUN_TYPE=beat - RUN_TYPE=beat
image: keannu125/drf-template:latest image: git.06222001.xyz/keannu125/drf_template:latest
depends_on: depends_on:
- celery - celery
- django - django
- postgres - postgres
- pgbouncer
- redis - redis
# SQL Database # SQL Database
@ -47,7 +48,7 @@ services:
- POSTGRES_USER=${DB_USERNAME} - POSTGRES_USER=${DB_USERNAME}
- POSTGRES_PASSWORD=${DB_PASSWORD} - POSTGRES_PASSWORD=${DB_PASSWORD}
volumes: volumes:
- db-data:/var/lib/postgresql/data - db_data:/var/lib/postgresql/data
command: postgres -c max_connections=200 command: postgres -c max_connections=200
# DB Bouncer # DB Bouncer
@ -76,4 +77,4 @@ services:
command: listen --forward-to django:8000/api/v1/stripe/webhook/ command: listen --forward-to django:8000/api/v1/stripe/webhook/
volumes: volumes:
db-data: db_data: