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 48 commits into from
Sep 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
2d02c63
models, some views and serializers
ZebraHr Sep 4, 2023
7e39518
changes in views
ZebraHr Sep 5, 2023
a6f55de
добавлены настройки djoser
ZebraHr Sep 6, 2023
94f83e0
добавлена вспомогательная модель для вывода ингредиентов в рецептах, …
ZebraHr Sep 9, 2023
bc9c9f5
Решена проблема с сериализаторами для избранного и подписки
ZebraHr Sep 10, 2023
ed09e2a
доработано Избранное, Список покупок
ZebraHr Sep 19, 2023
bd4f4e0
проверка деплоя
ZebraHr Sep 19, 2023
a9c56c3
проверка деплоя
ZebraHr Sep 19, 2023
54960a7
проверка деплоя
ZebraHr Sep 19, 2023
c37c6ee
проверка деплоя
ZebraHr Sep 19, 2023
991f47a
проверка деплоя
ZebraHr Sep 19, 2023
298d3d5
проверка деплоя
ZebraHr Sep 19, 2023
9305088
проверка деплоя
ZebraHr Sep 19, 2023
0b7e6ce
проверка деплоя
ZebraHr Sep 19, 2023
76325b4
проверка деплоя
ZebraHr Sep 19, 2023
e711b5f
проверка деплоя
ZebraHr Sep 19, 2023
63dae4c
проверка деплоя
ZebraHr Sep 19, 2023
eb016e4
проверка деплоя
ZebraHr Sep 19, 2023
3c47380
проверка деплоя
ZebraHr Sep 19, 2023
76c5532
проверка деплоя
ZebraHr Sep 19, 2023
dadb4ae
проверка работы БД
ZebraHr Sep 19, 2023
64e1c1d
проверка работы БД
ZebraHr Sep 21, 2023
17384bd
проверка работы статики
ZebraHr Sep 21, 2023
8a09201
проверка работы статики
ZebraHr Sep 21, 2023
3a46bb0
проверка работы бд
ZebraHr Sep 21, 2023
7cb1c1c
проверка работы бд
ZebraHr Sep 21, 2023
a8fdbe1
проверка работы филльтра
ZebraHr Sep 21, 2023
744dec4
проверка работы филльтра
ZebraHr Sep 21, 2023
0bd2064
test
ZebraHr Sep 22, 2023
633c895
test
ZebraHr Sep 22, 2023
d9df7d2
test
ZebraHr Sep 22, 2023
ad1a849
test
ZebraHr Sep 22, 2023
3ef53d9
test
ZebraHr Sep 22, 2023
87e8cbb
test
ZebraHr Sep 22, 2023
7c3957b
test
ZebraHr Sep 22, 2023
00a54e5
test
ZebraHr Sep 22, 2023
b21cdf1
test
ZebraHr Sep 22, 2023
d2c95f6
test
ZebraHr Sep 23, 2023
890f56d
test
ZebraHr Sep 23, 2023
ffd39f5
test
ZebraHr Sep 23, 2023
c80659f
test
ZebraHr Sep 23, 2023
3d0d943
test
ZebraHr Sep 23, 2023
3a97ad2
test
ZebraHr Sep 23, 2023
a8db838
тест доменного имени
ZebraHr Sep 23, 2023
b8b452d
деплой перед ревью
ZebraHr Sep 23, 2023
438614f
деплой перед ревью
ZebraHr Sep 23, 2023
2fb4b7d
финльный тест
ZebraHr Sep 23, 2023
84d84ba
финльный тест
ZebraHr Sep 23, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
name: Main Foodgram workflow

on: push

jobs:
tests:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:13.10
env:
POSTGRES_USER: foodgram_user
POSTGRES_PASSWORD: foodgram_password
POSTGRES_DB: foodgram_db
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- name: Check out code
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.9
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8==6.0.0
pip install -r ./backend/requirements.txt
- name: Test with flake8 and django tests
env:
POSTGRES_USER: foodgram_user
POSTGRES_PASSWORD: foodgram_password
POSTGRES_DB: foodgram_db
DB_HOST: 127.0.0.1
DB_PORT: 5432
run: |
python -m flake8 backend/
cd backend/
python manage.py test


build_backend_and_push_to_docker_hub:
name: Push Backend Docker image to DockerHub
runs-on: ubuntu-latest
needs: tests
steps:
- name: Check out the repo
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Push to DockerHub
uses: docker/build-push-action@v4
with:
context: ./backend/
push: true
tags: ${{ secrets.DOCKER_USERNAME }}/foodgram_backend:latest

build_frontend_and_push_to_docker_hub:
name: Push frontend Docker image to DockerHub
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Push to DockerHub
uses: docker/build-push-action@v4
with:
context: ./frontend/
push: true
tags: ${{ secrets.DOCKER_USERNAME }}/foodgram_frontend:latest


deploy:
runs-on: ubuntu-latest
needs:
- build_backend_and_push_to_docker_hub
- build_frontend_and_push_to_docker_hub

steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Copy docker-compose.yml via ssh
uses: appleboy/scp-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USER }}
key: ${{ secrets.SSH_KEY }}
passphrase: ${{ secrets.SSH_PASSPHRASE }}
source: "docker-compose.production.yml"
target: "foodgram"
- name: Executing remote ssh commands to deploy
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USER }}
key: ${{ secrets.SSH_KEY }}
passphrase: ${{ secrets.SSH_PASSPHRASE }}
script: |
cd foodgram
sudo docker compose -f docker-compose.production.yml pull
sudo docker compose -f docker-compose.production.yml down
sudo docker compose -f docker-compose.production.yml up -d
sudo docker compose -f docker-compose.production.yml exec backend python manage.py migrate
sudo docker compose -f docker-compose.production.yml exec backend python manage.py collectstatic
sudo docker compose -f docker-compose.production.yml exec backend cp -r /app/collected_static/. /backend_static/static/


send_message:
runs-on: ubuntu-latest
needs: deploy
steps:
- name: Send message
uses: appleboy/telegram-action@master
with:
to: ${{ secrets.TELEGRAM_TO }}
token: ${{ secrets.TELEGRAM_TOKEN }}
message: Деплой успешно выполнен! https://github.com/${{ github.repository }}/commit/${{github.sha}}
96 changes: 95 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,95 @@
# praktikum_new_diplom

# Foodgram
Проект "Продуктовый помошник" (Foodgram) — сайт с рецептами.

## Технологии:
Python 3.9
Django 3.2.3
djangorestframework 3.12.4
Nginx
gunicorn
Docker

## Описание работы:
В проекте "Проуктовый помощник" любители вкусно готовить могут публиковать рецепты, добавлять чужие рецепты в избранное и подписываться на публикации других авторов. Пользователям сайта также будет доступен сервис «Список покупок». Он позволит создавать список продуктов, которые нужно купить для приготовления выбранных блюд.

## Установка проекта
- Сделайте fork репозитория, затем клонируйте его:
```
git clone https://github.com/ZebraHr/foodgram-project-reactl
```
- Для адаптации проекта на своем удаленном сервере добавьте секреты в GitHub Actions:
```
DOCKER_USERNAME # имя пользователя в DockerHub
DOCKER_PASSWORD # пароль пользователя в DockerHub
HOST # ip_address сервера
USER # имя пользователя
SSH_KEY # приватный ssh-ключ (cat ~/.ssh/id_rsa)
SSH_PASSPHRASE # кодовая фраза (пароль) для ssh-ключа

TELEGRAM_TO # id телеграм-аккаунта (можно узнать у @userinfobot, команда /start)
TELEGRAM_TOKEN # токен бота (получить токен можно у @BotFather, /token, имя бота)
```
- На удаленном сервере создайте папку foodgram/
- На удаленном сервере в папке проекта cоздайте файл .env:
```
POSTGRES_DB=<Желаемое_имя_базы_данных>
POSTGRES_USER=<Желаемое_имя_пользователя_базы_данных>
POSTGRES_PASSWORD=<Желаемый_пароль_пользователя_базы_данных>
DB_HOST=db
DB_PORT=5432

SECRET_KEY = 'ваш_secret_key'
ALLOWED_HOSTS = ip_удаленного сервера, 127.0.0.1, localhost
DEBUG = False
```
- Установка Nginx. Находясь на удалённом сервере, из любой директории выполните команду, затем запустите Nginx:
```
sudo apt install nginx -y
sudo systemctl start nginx
```
- Перейдите в файл конфигурации nginx и измените его настройки на следующие:
```
nano /etc/nginx/sites-enabled/default
```
```
server {
server_name server_name <публичный-IP-адрес> <доменное-имя>;
server_tokens_off;
client_max_body_size 30M;

location / {
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:8000;
}

}
```
- Перезарузите Nginx:
```
sudo nginx -t
sudo systemctl reload nginx
```
- Откройте порты для фаервола и активируйте его:
```
sudo ufw allow 'Nginx Full'
sudo ufw allow OpenSSH
sudo ufw enable
```
- (Опционально) Получите SSL-сертификат для вашего доменного имени с помощью Certbot:
```
sudo apt install snapd
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo certbot --nginx
```
- Пуш в любую ветку запускает тестирование и деплой Foodgram на ваш удаленный сервер, а после успешного деплоя вам приходит оповещение в телеграм.

### Автор
Анна Победоносцева

Студент Яндекс Практикума ["Python-разаботчик плюс"](https://practicum.yandex.ru/python-developer-plus/?from=catalog)

GitHub:
(https://github.com/ZebraHr)
6 changes: 6 additions & 0 deletions backend/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
venv
.git
db.sqlite3
.idea
.vscode
.env
11 changes: 11 additions & 0 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM python:3.9

WORKDIR /app

COPY requirements.txt ./

RUN pip install -r requirements.txt --no-cache-dir

COPY . .

CMD ["gunicorn", "--bind", "0.0.0.0:8000", "foodgram.wsgi"]
Empty file added backend/api/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions backend/api/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class ApiConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'api'
53 changes: 53 additions & 0 deletions backend/api/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from django_filters.rest_framework import filters, FilterSet
from recipes.models import Recipe, Ingredient
from users.models import User


class IngredientFilter(FilterSet):
name = filters.CharFilter(lookup_expr='istartswith')

class Meta:
model = Ingredient
fields = ('name',)


IN_NOT_IN = (
(0, 'Not_In'),
(1, 'In'),
)


class RecipeFilter(FilterSet):
"""Фильтрация рецептов."""

author = filters.ModelChoiceFilter(
queryset=User.objects.all()
)
is_in_shopping_cart = filters.ChoiceFilter(
choices=IN_NOT_IN, method='get_is_in'
)
is_favorited = filters.ChoiceFilter(
choices=IN_NOT_IN,
method='get_is_in'
)
tags = filters.AllValuesMultipleFilter(
field_name='tags__slug',
label='Ссылка'
)

def get_is_in(self, queryset, name, value):
"""
Фильтрация рецептов по избранному и списку покупок.
"""
user = self.request.user
if user.is_authenticated:
if value == '1':
if name == 'is_favorited':
queryset = queryset.filter(favorites_recipes__user=user)
if name == 'is_in_shopping_cart':
queryset = queryset.filter(shopping_cart__user=user)
return queryset

class Meta:
model = Recipe
fields = ['is_favorited', 'is_in_shopping_cart', 'author', 'tags']
Empty file.
7 changes: 7 additions & 0 deletions backend/api/paginations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from rest_framework.pagination import PageNumberPagination


class RecipePagination(PageNumberPagination):
"""Паджинация рецептов."""
page_size = 6
page_size_query_param = 'limit'
20 changes: 20 additions & 0 deletions backend/api/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from rest_framework.permissions import SAFE_METHODS, BasePermission


class IsOwnerOrReadOnly(BasePermission):
def has_object_permission(self, request, view, obj):
return request.method in SAFE_METHODS or obj.author == request.user


class IsAmdinOrReadOnly(BasePermission):

def has_permission(self, request, view):
return (request.method in SAFE_METHODS
or (
request.user.is_authenticated
and (request.user.is_admin or request.user.is_superuser)))

# class IsAdminOrReadOnly(BasePermission):
# def has_permission(self, request, view):
# return (request.method in SAFE_METHODS
# or request.user and request.user.is_staff)
Loading