Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop #1

Merged
merged 12 commits into from
Nov 16, 2023
47 changes: 47 additions & 0 deletions .github/workflows/linting.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: referral-api

on:
push:
branches:
- develop
- main
pull_request:
branches:
- develop
- main

jobs:
isort:
name: Sorting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Install Python
uses: actions/setup-python@v2
with:
python-version: "3.9"

- name: Install isort
run: pip install isort

- name: Run isort
run: isort --check src


flake8:
name: Linter
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Install Python
uses: actions/setup-python@v2
with:
python-version: "3.9"

- name: Install flake8
run: pip install flake8

- name: Run flake8
run: flake8 src --count --statistics --show-source
32 changes: 32 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: check-added-large-files
- id: trailing-whitespace
args: [--markdown-linebreak-ext=md]
- id: check-merge-conflict
- id: mixed-line-ending
args: [--fix=lf]
- id: no-commit-to-branch
args: [--branch, master, --branch, main]
- id: name-tests-test

- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
args: [--settings, setup.cfg]

- repo: https://github.com/pycqa/flake8
rev: 5.0.4
hooks:
- id: flake8
additional_dependencies:
- flake8-docstrings
- pep8-naming
- flake8-broken-line
- flake8-return
args: [--config, setup.cfg]
13 changes: 13 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM python:3.9.17-slim

WORKDIR /app

COPY /src /app/

COPY pyproject.toml poetry.lock ./

RUN pip3 install poetry

RUN poetry config virtualenvs.create false

RUN poetry install
78 changes: 77 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,77 @@
# referral-api
# Referral API

API service with phone number authentication and a simple referral system.

## Project Structure and Description

### Phone Number Authentication

Authentication in the service is based on the phone number format "+79608543017".

To start, obtain a 4-digit code by sending a POST request with the phone number to the `POST /api/v1/auth/send_code/` endpoint.

Once the code is received, submit it along with the phone number to the `POST /api/v1/auth/jwt/get_by_phone/` endpoint. Optionally, you can include an existing referral code from another user along with the phone number and 4-digit code.

If a user with the specified phone number does not exist, they are added to the database. After addition, the user is assigned a unique referral invite code.

Upon successful authentication, the response includes JWT access/refresh tokens (bearer auth). These tokens will be needed for accessing user endpoints and profile editing. Standard endpoints for token verification and refresh are also available: `POST /api/v1/auth/jwt/verify/`, `POST /api/v1/auth/jwt/refresh/`.

### Users

- `GET /api/v1/users/`: View the list of users. The `invite_code` field is the user's personal referral code, unique and assigned during user creation. The `invited_by_code` field is the referral code of another user who invited them to the service.

- `GET /api/v1/users/{id}/`: Retrieve information about a specific user.

- `GET /api/v1/users/current_user/`: Retrieve information about the current user.

On endpoints providing information about a specific/current user, there is an `invited` field with a list of user IDs and phone numbers who accepted the invitation from the viewed user.

- `PATCH /api/v1/users/current_user/`: Edit information about the current user. You can set the user's name, surname, email address, and the invite code through which they received the service invitation.

### **How to run the project:**

Clone the repository and navigate to the ```/infra ``` directory:

```bash
git clone https://github.com/temirovazat/referral-api.git
```
```
cd referral-api/infra/
```

Create a .env file and add project settings:

```bash
vi .env
```

```
# PostgreSQL
DB_ENGINE=django.db.backends.postgresql
DB_NAME=referral_db
DB_USER=postgres
DB_PASSWORD=postgres
DB_HOST=db
DB_PORT=5432

# Django
SECRET_KEY=django-insecure-szpgqvuswh#lxmzs1#l@t_meqr#l-qceo#f+zm#u5a2@w@3v9#
DEBUG=False

# Authentication
AUTH_CODE_EXPIRES_MINUTES=30
REFRESH_TOKEN_LIFETIME_DAYS=14
ACCESS_TOKEN_LIFETIME_MINUTES=600
```

Deploy and run the project in containers:

```bash
docker compose up -d
```

Creating a superuser:

```bash
docker compose exec ref-web python manage.py createsuperuser
```
16 changes: 16 additions & 0 deletions infra/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# PostgreSQL
DB_ENGINE=django.db.backends.postgresql
DB_NAME=referral_db
DB_USER=postgres
DB_PASSWORD=postgres
DB_HOST=db
DB_PORT=5432

# Django
SECRET_KEY=django-insecure-szpgqvuswh#lxmzs1#l@t_meqr#l-qceo#f+zm#u5a2@w@3v9#
DEBUG=False

# Authentication
AUTH_CODE_EXPIRES_MINUTES=30
REFRESH_TOKEN_LIFETIME_DAYS=14
ACCESS_TOKEN_LIFETIME_MINUTES=600
45 changes: 45 additions & 0 deletions infra/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
version: '3.8'

services:
db:
image: postgres:alpine
container_name: ref-postgres15
environment:
POSTGRES_PASSWORD: $DB_PASSWORD
POSTGRES_USER: $DB_USER
POSTGRES_DB: $DB_NAME
volumes:
- postgres:/var/lib/postgresql/data/
ports:
- "5432:5432"
restart: always

web:
container_name: ref-web
build: ../
restart: always
command: >
/bin/sh -c "poetry run python manage.py migrate --noinput
&& poetry run python manage.py collectstatic --noinput
&& poetry run gunicorn config.wsgi:application --bind 0.0.0.0:8000"
volumes:
- static:/app/static/
depends_on:
- db
env_file:
- ./.env

nginx:
container_name: ref-nginx
image: nginx:1.21.3-alpine
ports:
- 80:80
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
- static:/var/html/static/
depends_on:
- web

volumes:
static:
postgres:
26 changes: 26 additions & 0 deletions infra/nginx/default.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
server {
listen 80;
client_max_body_size 4M;

server_name 127.0.0.1;
server_tokens off;

location /static/ {
root /var/html/;
}

location / {
proxy_pass http://web:8000;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Referrer $http_referer;
proxy_set_header Referer $http_referer;

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Loading
Loading