Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
16 changes: 15 additions & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,18 @@ DATABASE_URL=postgresql://postgres:postgres@localhost/news_db
UPLOAD_DIR=uploads
PROJECT_NAME=News API
VERSION=1.0.0
API_V1_STR=/api/v1

API_V1_STR=/api/v1
JWT_SECRET_KEY=your-secret-key-change-in-production-min-32-chars
JWT_ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30
REFRESH_TOKEN_EXPIRE_DAYS=30

# Redis (для кэша новостей, пользователей и сессий)
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_DB=0

GITHUB_CLIENT_ID=Ov23lir6ZAxVCtgOT059
GITHUB_CLIENT_SECRET=60853199
GITHUB_REDIRECT_URI=http://localhost:8000/api/v1/auth/github/callback
36 changes: 25 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# News API

RESTful API для управления новостями, пользователями и комментариями, построенное на FastAPI.
RESTful API для управления новостями, пользователями и комментариями, построенное на FastAPI с системой авторизации через JWT и GitHub OAuth.

## Стек технологий

Expand All @@ -10,18 +10,32 @@ RESTful API для управления новостями, пользовате
- PostgreSQL
- Alembic
- Pydantic
- JWT (python-jose)
- Argon2 (хеширование паролей)
- httpx (GitHub OAuth)
- Redis (кэш новостей, пользователей, сессии, брокер Celery)
- Celery (фоновые задачи: уведомления о новых новостях, еженедельный дайджест)

## Установка и запуск

### Предварительные требования

- Python 3.10 или выше
- PostgreSQL
- pip
- **Prometheus:** http://localhost:9090 (target — приложение на хосте:8000).
- **Grafana:** http://localhost:3000 (логин/пароль: admin/admin).
- **Kibana:** http://localhost:5601 (создайте index pattern `logs-app-*` для логов).
- **Logstash** читает `logs/app.json.log` и отправляет события в Elasticsearch.

### Переменные окружения (.env)

```env
# Метрики и логи
LOG_LEVEL=INFO
LOG_JSON_FILE=logs/app.json.log
METRICS_JSON_FILE=logs/metrics.json
METRICS_JSON_INTERVAL_SEC=30

# Hawk
HAWK_TOKEN=your_integration_token_from_hawk_so
HAWK_ENABLED=true
```


### Шаги по установке

1. Клонируйте репозиторий:
```bash
git clone <repository-url>
cd news_api
Binary file added alembic/__pycache__/env.cpython-314.pyc
Binary file not shown.
2 changes: 1 addition & 1 deletion alembic/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
sys.path.append(str(Path(__file__).parent.parent))

from app.core.database import Base
from app.models import user, news, comment
from app.models import user, news, comment, refresh_session
from app.core.config import settings

config = context.config
Expand Down
49 changes: 49 additions & 0 deletions alembic/versions/003_add_auth_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""add auth fields

Revision ID: 003
Revises: 002
Create Date: 2024-01-15 12:00:00.000000

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = '003'
down_revision = '002'
branch_labels = None
depends_on = None

def upgrade() -> None:
# Add auth fields to users table
op.add_column('users', sa.Column('password_hash', sa.String(), nullable=True))
op.add_column('users', sa.Column('is_admin', sa.Boolean(), nullable=True, server_default='false'))
op.add_column('users', sa.Column('github_id', sa.String(), nullable=True))
op.create_index(op.f('ix_users_github_id'), 'users', ['github_id'], unique=True)

# Create refresh_sessions table
op.create_table(
'refresh_sessions',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('refresh_token', sa.String(), nullable=False),
sa.Column('user_agent', sa.Text(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('expires_at', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_refresh_sessions_id'), 'refresh_sessions', ['id'], unique=False)
op.create_index(op.f('ix_refresh_sessions_user_id'), 'refresh_sessions', ['user_id'], unique=False)
op.create_index(op.f('ix_refresh_sessions_refresh_token'), 'refresh_sessions', ['refresh_token'], unique=True)

def downgrade() -> None:
op.drop_table('refresh_sessions')
op.drop_index(op.f('ix_users_github_id'), table_name='users')
op.drop_column('users', 'github_id')
op.drop_column('users', 'is_admin')
op.drop_column('users', 'password_hash')




Binary file modified app/__pycache__/__init__.cpython-311.pyc
Binary file not shown.
Binary file added app/__pycache__/__init__.cpython-314.pyc
Binary file not shown.
Binary file modified app/__pycache__/main.cpython-311.pyc
Binary file not shown.
Binary file modified app/api/v1/__pycache__/api.cpython-311.pyc
Binary file not shown.
8 changes: 7 additions & 1 deletion app/api/v1/api.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
from fastapi import APIRouter
from app.api.v1.endpoints import users, news, comments
from app.api.v1.endpoints import users, news, comments, auth

api_router = APIRouter()

api_router.include_router(
auth.router,
prefix="/auth",
tags=["authentication"]
)

api_router.include_router(
users.router,
prefix="/users",
Expand Down
Binary file modified app/api/v1/endpoints/__pycache__/__init__.cpython-311.pyc
Binary file not shown.
Binary file not shown.
Binary file modified app/api/v1/endpoints/__pycache__/comments.cpython-311.pyc
Binary file not shown.
Binary file modified app/api/v1/endpoints/__pycache__/news.cpython-311.pyc
Binary file not shown.
Binary file modified app/api/v1/endpoints/__pycache__/users.cpython-311.pyc
Binary file not shown.
Loading