Skip to content

Commit

Permalink
Доработка до релиза (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
Wudext authored Jul 27, 2023
1 parent 146bce7 commit 06d8a7d
Show file tree
Hide file tree
Showing 84 changed files with 1,150 additions and 1,152 deletions.
42 changes: 36 additions & 6 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Tests
name: Python package

on:
pull_request:
Expand All @@ -8,17 +8,18 @@ jobs:
test:
name: Unit tests
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@master
- name: Set up docker
uses: docker-practice/actions-setup-docker@master
- name: Run postgres
run: |
docker run -d -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust --name db-test postgres:15-alpine
- uses: actions/setup-python@v4
with:
python-version: '3.10'
python-version: '3.11'
- name: Install dependencies
run: |
python -m ensurepip
Expand All @@ -29,10 +30,39 @@ jobs:
DB_DSN=postgresql://postgres@localhost:5432/postgres alembic upgrade head
- name: Build coverage file
run: |
DB_DSN=postgresql://postgres@localhost:5432/postgres pytest --cache-clear --cov=aciniformes_backend tests > pytest-coverage.txt
DB_DSN=postgresql://postgres@localhost:5432/postgres pytest --junitxml=pytest.xml --cov-report=term-missing:skip-covered tests/ | tee pytest-coverage.txt
- name: Print report
if: always()
run: |
cat pytest-coverage.txt
- name: Comment coverage
uses: coroo/[email protected]
- name: Pytest coverage comment
uses: MishaKav/pytest-coverage-comment@main
with:
pytest-coverage-path: ./pytest-coverage.txt
title: Coverage Report
badge-title: Code Coverage
hide-badge: false
hide-report: false
create-new-comment: false
hide-comment: false
report-only-changed-files: false
remove-link-from-badge: false
junitxml-path: ./pytest.xml
junitxml-title: Summary
linting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: 3.11
- uses: isort/isort-action@master
with:
requirementsFiles: "requirements.txt requirements.dev.txt"
- uses: psf/black@stable
- name: Comment if linting failed
if: ${{ failure() }}
uses: thollander/actions-comment-pull-request@v2
with:
message: |
:poop: Code linting failed, use `black` and `isort` to fix it.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,3 @@ dmypy.json

# Pyre type checker
.pyre/
client_secret.json
static/**
16 changes: 16 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.11
ARG APP_VERSION=dev
ENV APP_VERSION=${APP_VERSION}
ENV APP_NAME=aciniformes_backend
ENV APP_MODULE=${APP_NAME}.routes.base:app

COPY ./requirements.txt /app/
COPY ./logging_prod.conf /app/
COPY ./logging_test.conf /app/
COPY ./.env /app/
RUN pip install -U -r /app/requirements.txt

COPY ./alembic.ini /alembic.ini
COPY ./migrations /migrations/

COPY . /app
29 changes: 29 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
BSD 3-Clause License

Copyright (c) 2022, Профком студентов физфака МГУ
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 changes: 24 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
run:
source ./venv/bin/activate && uvicorn --reload --log-config logging_dev.conf aciniformes_backend.routes.base:app

configure: venv
source ./venv/bin/activate && pip install -r requirements.dev.txt -r requirements.txt

venv:
python3.11 -m venv venv

atomic-format:
autoflake -r --in-place --remove-all-unused-imports ./$(module)
isort ./$(module)
black ./$(module)

format:
make atomic-format module=pinger_backend
make atomic-format module=aciniformes_backend
make atomic-format module=settings.py

db:
docker run -d -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust --name db-pinger_backend postgres:15

migrate:
alembic upgrade head
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Aciniformes-project

Проект пингера сервисов профкома ФФ МГУ. Позволяет пользователю просто и быстро проверять работоспособность любого сайта и сервиса и получать отчет через telegram бота.


# Функционал

1. Опрос любого сервиса или сайта на работоспособность
2. Создание расписания проверок указанных сайтов/сервисов
3. Получение удобного отчета о проверке через telegram бота

# Разработка
Backend разработка – https://github.com/profcomff/.github/wiki/%5Bdev%5D-Backend-разработка


# Quick Start
1. Перейдите в папку проекта

2. Создайте виртуальное окружение командой:
`foo@bar:~$ python3 -m venv ./venv/`
3. Установите библиотеки командой:
`foo@bar:~$ pip install -m requirements.txt`
4. Установите все переменные окружения (см. CONTRIBUTING.md)
5. Запускайте приложение!
`foo@bar:~$ python -m services-backend`


# Использование
1. Создание получателя сообщений
1. Получить или узнать токен telegram бота, через которого будет посылаться сообщение
2. Узнать id чата-получателя в telegram
3. Создать получателя сообщений, выполнив запрос POST /receiver с телом: `{"url": "https://api.telegram.org/bot{токен_бота}/sendMessage", "method": "post", "receiver_body": {"chat_id": id_получателя, "text": текст_сообщения}`

2. Создание опрашиваемого сервиса
1. Выполнить запрос POST /fetcher с телом: `"{
"type_": "get/post/ping",
"address": "ссылка на опрашиваемый сайт",
"fetch_data": "{}" (Имеет смысла заполнять только если в type_ указан post запрос),
"delay_ok": частота опроса при успешном запросе,
"delay_fail": частота опроса при неудавшемся запросе
}"`

# Параметризация и плагины
BOT_TOKEN - токен бота-отправителя отчетов

# Ссылки
Документация проекта - https://api.test.profcomff.com/?urls.primaryName=pinger#

Backend разработка – https://github.com/profcomff/.github/wiki/%5Bdev%5D-Backend-разработка
Binary file removed aciniformes_backend/__init__.pyc
Binary file not shown.
1 change: 1 addition & 0 deletions aciniformes_backend/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

from .routes import app


if __name__ == "__main__":
uvicorn.run(app)
Binary file not shown.
8 changes: 4 additions & 4 deletions aciniformes_backend/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from .metric import Metric
from .fetcher import Fetcher
from .alerts import Alert, Receiver
from .base import BaseModel
from .auth import Auth
from .fetcher import Fetcher, FetcherType
from .metric import Metric


__all__ = ["Metric", "Fetcher", "Alert", "Receiver", "BaseModel", "Auth"]
__all__ = ["Metric", "Fetcher", "Alert", "Receiver", "BaseModel", "FetcherType"]
28 changes: 15 additions & 13 deletions aciniformes_backend/models/alerts.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
"""Классы хранения настроек нотификаций
"""
from datetime import datetime
from .base import BaseModel
from sqlalchemy import JSON, DateTime, ForeignKey, Integer, String
from enum import Enum

from sqlalchemy import JSON, DateTime
from sqlalchemy import Enum as DbEnum
from sqlalchemy import Integer, String
from sqlalchemy.orm import Mapped, mapped_column

from .base import BaseModel


class Method(str, Enum):
POST: str = "post"
GET: str = "get"


class Receiver(BaseModel):
id_: Mapped[int] = mapped_column("id", Integer, primary_key=True)
name: Mapped[str] = mapped_column(String, nullable=False)
chat_id: Mapped[int] = mapped_column(Integer, nullable=False)
url: Mapped[str] = mapped_column(String, nullable=False)
method: Mapped[Method] = mapped_column(DbEnum(Method, native_enum=False), nullable=False)
receiver_body: Mapped[dict] = mapped_column(JSON, nullable=False)
create_ts: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
modify_ts: Mapped[datetime] = mapped_column(
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
)


class Alert(BaseModel):
id_: Mapped[int] = mapped_column("id", Integer, primary_key=True)
data = mapped_column(JSON, nullable=False)
receiver: Mapped[int] = mapped_column(
Integer, ForeignKey("receiver.id", ondelete="CASCADE"), nullable=False
)
filter = mapped_column(String, nullable=False)
create_ts = mapped_column(DateTime, default=datetime.utcnow)
modify_ts = mapped_column(
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
)
15 changes: 0 additions & 15 deletions aciniformes_backend/models/auth.py

This file was deleted.

3 changes: 2 additions & 1 deletion aciniformes_backend/models/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import re
from sqlalchemy.orm import declared_attr, as_declarative

from sqlalchemy.orm import as_declarative, declared_attr


@as_declarative()
Expand Down
30 changes: 9 additions & 21 deletions aciniformes_backend/models/fetcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,29 @@
"""
from datetime import datetime
from enum import Enum
from .base import BaseModel

import sqlalchemy
from sqlalchemy import JSON, DateTime, Integer, String
from sqlalchemy import DateTime, Integer, String
from sqlalchemy.orm import Mapped, mapped_column

from .base import BaseModel


class FetcherType(str, Enum):
GET = "get_ok" # Пишет True, если GET запрос вернул статус 200..299
POST = "post_ok" # Пишет True, если POST запрос вернул статус 200..299
PING = "ping_ok" # Пишет True, если PING успешный
GET = "get" # Пишет положительную метрику, если GET запрос вернул статус 200..299
POST = "post" # Пишет положительную метрику, если POST запрос вернул статус 200..299
PING = "ping" # Пишет положительную метрику, если PING успешный


class Fetcher(BaseModel):
id_: Mapped[int] = mapped_column("id", Integer, primary_key=True)
name: Mapped[str] = mapped_column(String, nullable=False)
type_: Mapped[FetcherType] = mapped_column(
"type", sqlalchemy.Enum(FetcherType, native_enum=False), nullable=False
)
type_: Mapped[FetcherType] = mapped_column("type", sqlalchemy.Enum(FetcherType, native_enum=False), nullable=False)
address: Mapped[str] = mapped_column(String, nullable=False)
fetch_data: Mapped[str] = mapped_column(
String
) # Данные, которые передаются в теле POST запроса
metrics: Mapped[dict] = mapped_column(
JSON, default={}, nullable=False
) # Статическая часть метрик
metric_name: Mapped[str] = mapped_column(
String, nullable=False
) # Название динамической части метрик
fetch_data: Mapped[str] = mapped_column(String, nullable=True) # Данные, которые передаются в теле POST запроса
delay_ok: Mapped[int] = mapped_column(
Integer, default=300, nullable=False
) # Через сколько секунд повторить запрос, если предыдущий успешный
delay_fail: Mapped[int] = mapped_column(
Integer, default=30, nullable=False
) # Через сколько секунд повторить запрос, если предыдущий неуспешный
create_ts: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
modify_ts: Mapped[datetime] = mapped_column(
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
)
11 changes: 7 additions & 4 deletions aciniformes_backend/models/metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
"""

from datetime import datetime
from .base import BaseModel
from sqlalchemy import Integer, JSON, DateTime

from sqlalchemy import Boolean, Float, Integer, String
from sqlalchemy.orm import Mapped, mapped_column

from .base import BaseModel


class Metric(BaseModel):
id_: Mapped[int] = mapped_column("id", Integer, primary_key=True)
metrics: Mapped[dict] = mapped_column(JSON, nullable=False)
create_ts: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
name: Mapped[str] = mapped_column("name", String, nullable=False)
ok: Mapped[bool] = mapped_column("ok", Boolean, nullable=False, default=True)
time_delta: Mapped[float] = mapped_column(Float, default=datetime.utcnow)
3 changes: 3 additions & 0 deletions aciniformes_backend/routes/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
from .base import app


__all__ = ["app"]
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit 06d8a7d

Please sign in to comment.