Merge pull request #2 from JscorpTech/dev

dev
This commit is contained in:
Samandar Azamov
2025-04-20 16:16:55 +05:00
committed by GitHub
174 changed files with 860 additions and 44 deletions

View File

@@ -1,2 +1,2 @@
AUTH_COMMAND=sh ./resources/scripts/entrypoint.sh USER_COMMAND=sh ./resources/scripts/entrypoint.sh
JWT_KEY=key JWT_KEY=key

View File

@@ -16,9 +16,10 @@ jobs:
- name: 📥 Secret orqali .env fayl yaratish - name: 📥 Secret orqali .env fayl yaratish
run: | run: |
echo "${{ secrets.BASE_ENV_FILE }}" > .env echo "${{ secrets.BASE_ENV_FILE }}" > .env
echo "${{ secrets.AUTH_ENV_FILE }}" > ./auth/.env echo "${{ secrets.USER_ENV_FILE }}" > ./user/.env
- name: 🛠 Docker Compose bilan build & deploy - name: 🛠 Docker Compose bilan build & deploy
run: | run: |
docker compose --profile user --profile payment build
docker compose down docker compose down
docker compose --profile auth --profile payment up -d --build docker compose --profile user --profile payment up -d

View File

@@ -1,14 +1,10 @@
up-auth: up-user:
docker compose --profile auth up -d docker compose --profile user up -d
down-user:
down-auth: docker compose --profile user down
docker compose --profile auth down
up-payment: up-payment:
docker compose --profile payment up -d docker compose --profile payment up -d
down-payment: down-payment:
docker compose --profile payment down docker compose --profile payment down
down-all: down-all:
docker compose --profile payment --profile auth down docker compose --profile payment --profile user --profile notification down

View File

@@ -5,6 +5,7 @@ networks:
volumes: volumes:
pg_data: null pg_data: null
pycache: null pycache: null
rabbitmq-data: null
services: services:
traefik: traefik:
@@ -21,46 +22,46 @@ services:
- "/var/run/docker.sock:/var/run/docker.sock:ro" - "/var/run/docker.sock:/var/run/docker.sock:ro"
networks: networks:
- lamenu - lamenu
auth-nginx: user-nginx:
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.auth.rule=PathPrefix(`/auth`)" - "traefik.http.routers.user.rule=PathPrefix(`/user`)"
- "traefik.http.routers.auth.entrypoints=web" - "traefik.http.routers.user.entrypoints=web"
- "traefik.http.services.auth.loadbalancer.server.port=80" - "traefik.http.services.user.loadbalancer.server.port=80"
- "traefik.http.middlewares.auth-strip-prefix.stripPrefix.prefixes=/auth" - "traefik.http.middlewares.user-strip-prefix.stripPrefix.prefixes=/user"
- "traefik.http.routers.auth.middlewares=auth-strip-prefix" - "traefik.http.routers.user.middlewares=user-strip-prefix"
networks: networks:
- lamenu - lamenu
volumes: volumes:
- ./auth/resources/layout/nginx.conf:/etc/nginx/nginx.conf - ./user/resources/layout/nginx.conf:/etc/nginx/nginx.conf
- ./auth/resources/:/usr/share/nginx/html/resources/ - ./user/resources/:/usr/share/nginx/html/resources/
build: build:
context: ./auth context: ./user
dockerfile: ./docker/Dockerfile.nginx dockerfile: ./docker/Dockerfile.nginx
depends_on: depends_on:
- auth - user
profiles: profiles:
- auth - user
auth: user:
networks: networks:
- lamenu - lamenu
build: build:
context: ./auth context: ./user
dockerfile: ./docker/Dockerfile.web dockerfile: ./docker/Dockerfile.web
restart: always restart: always
command: ${AUTH_COMMAND:-sh ./resources/scripts/entrypoint.sh} command: ${user_COMMAND:-sh ./resources/scripts/entrypoint.sh}
environment: environment:
- PYTHONPYCACHEPREFIX=/var/cache/pycache - PYTHONPYCACHEPREFIX=/var/cache/pycache
- JWT_KEY=${JWT_KEY} - JWT_KEY=${JWT_KEY}
volumes: volumes:
- ./auth:/code - ./user:/code
- pycache:/var/cache/pycache - pycache:/var/cache/pycache
depends_on: depends_on:
- auth-db - user-db
- redis - redis
profiles: profiles:
- auth - user
auth-db: user-db:
networks: networks:
- lamenu - lamenu
image: postgres:16 image: postgres:16
@@ -72,9 +73,14 @@ services:
volumes: volumes:
- pg_data:/var/lib/postgresql/data - pg_data:/var/lib/postgresql/data
profiles: profiles:
- auth - user
payment: payment:
labels:
- "traefik.enable=true"
- "traefik.http.routers.payment.rule=PathPrefix(`/payment`)"
- "traefik.http.routers.payment.entrypoints=web"
- "traefik.http.services.payment.loadbalancer.server.port=8000"
networks: networks:
- lamenu - lamenu
build: build:
@@ -89,8 +95,29 @@ services:
profiles: profiles:
- payment - payment
notification:
build:
context: ./notification
dockerfile: Dockerfile
networks:
- lamenu
profiles:
- notification
redis: redis:
networks: networks:
- lamenu - lamenu
restart: always restart: always
image: redis image: redis
rabbitmq:
image: rabbitmq:management
container_name: rabbitmq
ports:
- "5672:5672" # RabbitMQ porti
- "15672:15672" # Web konsol porti
environment:
- RABBITMQ_DEFAULT_USER=guest # Foydalanuvchi nomi
- RABBITMQ_DEFAULT_PASS=guest # Parol
volumes:
- rabbitmq-data:/var/lib/rabbitmq # Ma'lumotlarni saqlash

19
notification/Dockerfile Normal file
View File

@@ -0,0 +1,19 @@
FROM golang:alpine as build
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o notification ./cmd/main.go
FROM alpine
WORKDIR /app
COPY --from=build /app/notification .
CMD ["./notification"]

112
notification/README.MD Normal file
View File

@@ -0,0 +1,112 @@
# Notification Service
A microservice for handling and delivering notifications through various channels like SMS and email using RabbitMQ as a message broker.
## Overview
This notification service is designed as a standalone microservice that consumes notification requests from a RabbitMQ queue and routes them to the appropriate notification provider based on the notification type. Currently, it supports SMS and email notifications.
## Features
- Message consumption from RabbitMQ
- Support for multiple notification channels (SMS, email)
- Extensible architecture for adding new notification types
- Asynchronous notification handling
## Architecture
The notification service follows a clean architecture approach:
- **Domain Layer**: Contains core business logic and port interfaces
- **Infrastructure Layer**: Implements the ports with concrete adapters
- **RabbitMQ**: Used as a message broker for consuming notification requests
## Installation
### Prerequisites
- Go 1.x+
- RabbitMQ server
### Setup
1. Clone the repository:
```bash
git clone https://github.com/JscorpTech/notification.git
cd notification
```
2. Install dependencies:
```bash
go mod download
```
3. Build the application:
```bash
go build -o notification-service
```
## Configuration
Configure your RabbitMQ connection and other settings in the appropriate configuration files.
## Usage
### Running the service
```bash
./notification-service
```
This will start the notification consumer that listens for incoming notification requests.
### Sending a notification
Notifications should be published to the RabbitMQ exchange with the following JSON format:
```json
{
"type": "email",
"message": "Hello, this is a test notification.",
"to": ["user@example.com"]
}
```
Available notification types:
- `email`: For email notifications
- `sms`: For SMS notifications
## Project Structure
```
notification/
├── cmd/
│ └── main.go # Entry point
├── internal/
│ ├── domain/
│ │ └── ports.go # Interfaces
│ ├── notifier/
│ │ ├── email.go # Email notification implementation
│ │ └── sms.go # SMS notification implementation
│ ├── rabbitmq/
│ │ └── connection.go # RabbitMQ connection handling
│ └── consumer/
│ └── consumer.go # Implementation of the notification consumer
└── README.md
```
## Contributing
1. Fork the repository
2. Create your feature branch: `git checkout -b feature/my-new-feature`
3. Commit your changes: `git commit -am 'Add some feature'`
4. Push to the branch: `git push origin feature/my-new-feature`
5. Submit a pull request
## License
[Add your license here]
## Contact
JscorpTech - [GitHub](https://github.com/JscorpTech)

10
notification/cmd/main.go Normal file
View File

@@ -0,0 +1,10 @@
package main
import (
"github.com/JscorpTech/notification/internal/consumer"
)
func main() {
notification := consumer.NewNotificationConsumer()
notification.Start()
}

12
notification/go.mod Normal file
View File

@@ -0,0 +1,12 @@
module github.com/JscorpTech/notification
go 1.24.0
require (
github.com/k0kubun/pp/v3 v3.4.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/streadway/amqp v1.1.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/text v0.19.0 // indirect
)

13
notification/go.sum Normal file
View File

@@ -0,0 +1,13 @@
github.com/k0kubun/pp/v3 v3.4.1 h1:1WdFZDRRqe8UsR61N/2RoOZ3ziTEqgTPVqKrHeb779Y=
github.com/k0kubun/pp/v3 v3.4.1/go.mod h1:+SiNiqKnBfw1Nkj82Lh5bIeKQOAkPy6Xw9CAZUZ8npI=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM=
github.com/streadway/amqp v1.1.0/go.mod h1:WYSrTEYHOXHd0nwFeUXAe2G2hRnQT+deZJJf88uS9Bg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=

View File

@@ -0,0 +1,13 @@
package config
import (
"os"
)
func GetEnv(key, fallback string) string {
val := os.Getenv(key)
if val == "" {
return fallback
}
return val
}

View File

@@ -0,0 +1,62 @@
package consumer
import (
"encoding/json"
"fmt"
"log"
"github.com/JscorpTech/notification/internal/domain"
"github.com/JscorpTech/notification/internal/notifier"
"github.com/JscorpTech/notification/internal/rabbitmq"
"github.com/streadway/amqp"
)
type notificationConsumer struct{}
func NewNotificationConsumer() domain.NotificationConsumerPort {
return &notificationConsumer{}
}
func (n *notificationConsumer) Start() {
conn, ch, err := rabbitmq.Connect()
if err != nil {
log.Fatal(err)
}
defer conn.Close()
defer ch.Close()
exchangeName := "notification"
queueName := "notification"
routingKey := "notification"
ch.ExchangeDeclare(exchangeName, "direct", true, false, false, false, nil)
q, _ := ch.QueueDeclare(queueName, true, false, false, false, nil)
ch.QueueBind(q.Name, routingKey, exchangeName, false, nil)
msgs, _ := ch.Consume(q.Name, "", true, false, false, false, nil)
go func() {
for msg := range msgs {
go n.Handler(msg)
}
}()
fmt.Println("🚀 Server started. Ctrl+C to quit.")
select {}
}
func (n *notificationConsumer) Handler(msg amqp.Delivery) {
var notification domain.NotificationMsg
err := json.Unmarshal(msg.Body, &notification)
if err != nil {
fmt.Print(err.Error())
}
var ntf domain.NotifierPort
switch notification.Type {
case "sms":
ntf = notifier.NewSmsNotifier()
case "email":
ntf = notifier.NewEmailNotifier()
}
ntf.SendMessage(notification.To, notification.Message)
}

View File

@@ -0,0 +1,18 @@
package domain
import "github.com/streadway/amqp"
type NotificationConsumerPort interface {
Start()
Handler(amqp.Delivery)
}
type NotifierPort interface {
SendMessage([]string, string)
}
type NotificationMsg struct {
Type string `json:"type"`
Message string `json:"message"`
To []string `json:"to"`
}

View File

@@ -0,0 +1,16 @@
package notifier
import (
"github.com/JscorpTech/notification/internal/domain"
"github.com/k0kubun/pp/v3"
)
type emailNotifier struct{}
func NewEmailNotifier() domain.NotifierPort {
return &emailNotifier{}
}
func (n *emailNotifier) SendMessage(to []string, body string) {
pp.Print(to, body)
}

View File

@@ -0,0 +1,16 @@
package notifier
import (
"github.com/JscorpTech/notification/internal/domain"
"github.com/k0kubun/pp/v3"
)
type smsNotifier struct{}
func NewSmsNotifier() domain.NotifierPort {
return &smsNotifier{}
}
func (n *smsNotifier) SendMessage(to []string, body string) {
pp.Print(to, body)
}

View File

@@ -0,0 +1,21 @@
package rabbitmq
import (
"log"
"github.com/streadway/amqp"
)
func Connect() (*amqp.Connection, *amqp.Channel, error) {
conn, err := amqp.Dial("amqp://guest:guest@127.0.0.1:5672/")
if err != nil {
return nil, nil, err
}
ch, err := conn.Channel()
if err != nil {
return nil, nil, err
}
log.Println("🐇 Connected to RabbitMQ")
return conn, ch, nil
}

View File

@@ -1,3 +1,13 @@
FROM alpine:latest FROM python:3.13-alpine
CMD ["sleep", "60"] ENV PYTHONPYCACHEPREFIX=/dev/null
RUN apk update && apk add git gettext
WORKDIR /code
COPY requirements.txt /code/requirements.txt
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt
CMD ["sh", "./entrypoint.sh"]

3
payment/api/admin.py Normal file
View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

6
payment/api/apps.py Normal file
View File

@@ -0,0 +1,6 @@
from django.apps import AppConfig
class ApiConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "api"

3
payment/api/models.py Normal file
View File

@@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

3
payment/api/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

6
payment/api/urls.py Normal file
View File

@@ -0,0 +1,6 @@
from django.urls import path
from .views import HealthView
urlpatterns = [
path("health/", HealthView.as_view())
]

7
payment/api/views.py Normal file
View File

@@ -0,0 +1,7 @@
from rest_framework.views import APIView
from rest_framework.response import Response
class HealthView(APIView):
def get(self, *args, **kwargs):
return Response(data={"detail": "OK"})

16
payment/config/asgi.py Normal file
View File

@@ -0,0 +1,16 @@
"""
ASGI config for config project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
application = get_asgi_application()

126
payment/config/settings.py Normal file
View File

@@ -0,0 +1,126 @@
"""
Django settings for config project.
Generated by 'django-admin startproject' using Django 5.1.3.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.1/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-iv-iwjd(4d%g5&fyo*+xybkjhaik+r@3j0$h91u0^$u4fwuh53"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = [
"*"
]
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"api",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "config.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "config.wsgi.application"
# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Password validation
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/
STATIC_URL = "static/"
# Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

7
payment/config/urls.py Normal file
View File

@@ -0,0 +1,7 @@
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("payment/api/", include("api.urls")),
path("payment/admin/", admin.site.urls),
]

16
payment/config/wsgi.py Normal file
View File

@@ -0,0 +1,16 @@
"""
WSGI config for config project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
application = get_wsgi_application()

BIN
payment/db.sqlite3 Normal file

Binary file not shown.

5
payment/entrypoint.sh Normal file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
python3 manage.py collectstatus --no-input
python3 manage.py migrate --no-input
python3 manage.py runserver 0.0.0.0:8000

22
payment/manage.py Executable file
View File

@@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()

2
payment/requirements.txt Normal file
View File

@@ -0,0 +1,2 @@
django==5.1.3
djangorestframework==3.15.2

13
template/Dockerfile Normal file
View File

@@ -0,0 +1,13 @@
FROM python:3.13-alpine
ENV PYTHONPYCACHEPREFIX=/dev/null
RUN apk update && apk add git gettext
WORKDIR /code
COPY requirements.txt /code/requirements.txt
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt
CMD ["sh", "./entrypoint.sh"]

3
template/api/admin.py Normal file
View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

6
template/api/apps.py Normal file
View File

@@ -0,0 +1,6 @@
from django.apps import AppConfig
class ApiConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "api"

3
template/api/models.py Normal file
View File

@@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

3
template/api/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

6
template/api/urls.py Normal file
View File

@@ -0,0 +1,6 @@
from django.urls import path
from .views import HealthView
urlpatterns = [
path("health/", HealthView.as_view())
]

7
template/api/views.py Normal file
View File

@@ -0,0 +1,7 @@
from rest_framework.views import APIView
from rest_framework.response import Response
class HealthView(APIView):
def get(self, *args, **kwargs):
return Response(data={"detail": "OK"})

16
template/config/asgi.py Normal file
View File

@@ -0,0 +1,16 @@
"""
ASGI config for config project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
application = get_asgi_application()

126
template/config/settings.py Normal file
View File

@@ -0,0 +1,126 @@
"""
Django settings for config project.
Generated by 'django-admin startproject' using Django 5.1.3.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.1/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-iv-iwjd(4d%g5&fyo*+xybkjhaik+r@3j0$h91u0^$u4fwuh53"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = [
"*"
]
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"api",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "config.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "config.wsgi.application"
# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Password validation
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/
STATIC_URL = "static/"
# Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

7
template/config/urls.py Normal file
View File

@@ -0,0 +1,7 @@
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("payment/api/", include("api.urls")),
path("payment/admin/", admin.site.urls),
]

16
template/config/wsgi.py Normal file
View File

@@ -0,0 +1,16 @@
"""
WSGI config for config project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
application = get_wsgi_application()

BIN
template/db.sqlite3 Normal file

Binary file not shown.

5
template/entrypoint.sh Normal file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
python3 manage.py collectstatus --no-input
python3 manage.py migrate --no-input
python3 manage.py runserver 0.0.0.0:8000

22
template/manage.py Executable file
View File

@@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,2 @@
django==5.1.3
djangorestframework==3.15.2

17
test.py Normal file
View File

@@ -0,0 +1,17 @@
from kombu import Connection, Exchange, Producer
# RabbitMQ ulanishi
rabbit_url = 'amqp://guest:guest@127.0.0.1:5672/'
connection = Connection(rabbit_url)
channel = connection.channel()
exchange = Exchange('notification', type='direct')
# Producer yaratish
producer = Producer(channel, exchange=exchange, routing_key="notification")
# Xabar yuborish
message = {'type': 'email', 'message': 'Hello, Workers!', "to": ["+998888112309", "+998943990509"]}
producer.publish(message)
print("Message sent to all workers!")

View File

View File

@@ -1,11 +1,7 @@
from config.env import env from config.env import env
APPS = [ APPS = [
"cacheops", "cacheops",
"drf_spectacular", "drf_spectacular",
"rest_framework", "rest_framework",
"corsheaders", "corsheaders",

View File

Some files were not shown because too many files have changed in this diff Show More