Skip to content

Antida Python School. Итоговое задание по курсу. Учебный проект "Сервис для учета личных финансов".

Notifications You must be signed in to change notification settings

jasper7466/Study-APS-Task3

Repository files navigation

Study-APS-Task3

Antida Python School. Итоговое задание по курсу. Учебный проект "Сервис для учета личных финансов".

Краткое описание

Проект представляет собой приложение, написанное на языке Python с применением web-фреймворка Flask. Реализован REST API, обеспечивающий требуемые методы (см. раздел "Формулировка задания")

Формулировка задания

Предметная область: «Сервис для учета личных финансов»

Словесное описание требований
  1. Сайт представляет собой сервис для учета личных финансов. Пользователи сервиса фиксируют свои доходы и расходы, чтобы видеть отчеты по своим личным финансам.
  2. Для работы на сайте необходима регистрация, обязательные поля профиля — имя, фамилия, email, пароль. Для авторизации используется пара email и пароль.
  3. Зарегистрированный пользователь может:
  • Добавлять операции доходов и расходов, а также редактировать и удалять добавленные операции
  • Добавлять категории для операций, а также редактировать и удалять существующие категории
  • Строить отчеты с разрезами по временному периоду и категории
  1. При добавлении операции пользователь передает следующие поля:
  • Тип операции (доход/расход)
  • Сумма
  • Описание операции (не обязательно)
  • Категория (не обязательно, у операции может быть 1 или 0 категорий)
  • Дата и время (не обязательно, по умолчанию используется текущее время)
  1. При добавлении категории пользователь передает следующие поля:
  • Название
  • Родительская категория (не обязательно, если не указана, то создается категория верхнего уровня)
  1. Категории могут вкладываться друг в друга, образуя древовидную структуру. Например: категория «Еда» может содержать подкатегории «Продукты», «Рестораны», «Обеды».
  2. При построении отчета об операциях, пользователь может указать категорию и временной период, по которым строится отчет:
  • Если указана категория, то учитываются операции из категории и всех ее подкатегорий, подкатегорий ее подкатегорий и так далее. Если категория не указано, то в отчет включаются все операции за период независимо от категории
  • Варианты временных периодов: текущая неделя (с понедельника по воскресенье), предыдущая неделя, текущий месяц, предыдущий месяц, текущий квартал, предыдущий квартал, текущий год, предыдущий год, произвольный диапазон (указываются даты начала и конца диапазона), всё время
  1. Отчет об операциях содержит:
  • Список операций, соответствующий указанным категории и временному периоду. Для каждой операции отдается дата, сумма, описание и категория (вместе со всеми родительскими категориями). Список отсортирован по дате и отдается с пагинацией
  • Общую сумма для всех операций из списка

Техническое задание

Сформированное на основе формального описания задачи техническое задание: ТЗ Rev.1.1.pdf

Проектирование базы данных

Изображения моделей, получившихся в ходе проектирования базы данных:

Концептуальная

Концептуальная

Логическая

Логическая

Физическая

Физическая

Описание API

Авторизация пользователя. Вход и выход
POST /auth/login
Request:
{
  "email": str,
  "password": str
}
POST /auth/logout
Регистрация пользователя
POST /register
Request:
{
  "email": str,
  "password": str,
  "first_name": str,
  "last_name": str
}
Response:
{
  "id": int,
  "email": str,
  "first_name": str,
  "last_name": str
}
Создание категории Метод доступен только авторизованным пользователям.
POST /category
Request:
{
  "name": str,
  "parent_id": int?
}
Response:
{
  "id": int,
  "name": str,
  "parent_id": int?
}
Получение категории Метод доступен только авторизованным пользователям. Поиск производится по уникальному (в рамках дерева данного пользователя) имени категории.
GET /category
Request:
{
  "name": str,
}
Response:
{
  "id": int,
  "name": str,
  "parent_id": int?
}
Редактирование категории Метод доступен только авторизованным пользователям. Пользователь может редактировать только созданные им категории.
PATCH /category/<id>
Request:
{
  "name": str?,
  "parent_id": int?
}
Response:
{
  "id": int,
  "name": str,
  "parent_id": int?
}
Удаление категории Метод доступен только авторизованным пользователям. Пользователь может удалять только созданные им категории.
DELETE /category/<id>
Создание операции Доступно только авторизованным пользователям. Поле type указывает на тип операции - true для операции прихода, false для операци расхода.
POST /transactions
Request:
{
  "type": bool,
  "amount": str,
  "description": str?,
  "category_id": int?,
  "date": int?
}
Responce:
{
  "id": int,
  "type": bool,
  "amount": str,
  "description": str?,
  "category_id": int?,
  "date": int
}
Редактирование операции Доступно только авторизованным пользователям. Метод доступен только для операций, которые созданы пользователем, выполняющим запрос. Редактирование происходит по id операции.
PATCH /transactions/<id>
Request:
{
  "type": bool?,
  "amount": str?,
  "description": str?,
  "category_id": int?,
  "date": int?
}
Responce:
{
  "id": int,
  "type": bool,
  "amount": str,
  "description": str?,
  "category_id": int?,
  "date": int
}
Удаление операции Удаляются лишь те операции, которые созданы авторизованным пользователем. Удаление происходит по id операции.
DELETE /transactions/<id>
Получение списка операций Пользователь может получить только собственные операции. Список можно фильтровать с помощью query string параметров, все параметры необязательные.

Список выводится с использованием пагинации. Параметры page_size и page отвечают за регулировку пагинации: page - отображает текущую страницу, page_size - регулирует количество операций на странице.

Параметры from, to, period отвечают за фильтрацию по времени: from - дата в виде timestamp, отфильтровывает те записи, дата которых превышает заданную, to - дата в виде timestamp, отфильтровывает те записи, дата которых не превышает заданную, period - фильтрация по одному из предустановленных периодов. Если передан параметр period, from и to игнорируются.

Список предустановленных периодов:

  • week – текущая неделя с понедельника по воскресенье

  • last_week – предыдущая неделя с понедельника по воскресенье

  • month – текущий месяц

  • last_month – предыдущий месяц

  • quarter – текущий квартал

  • last_quarter – предыдущий квартал

  • year – текущий год

  • last_year – предыдущий год

    GET /transactions
    Query string:
      category_id: int?
      from: int?
      to: int?
      period: str?
      page_size: int?
      page: int?
    Response:
    {
      "operations": [
        {
          "id": int,
          "date": int,
          "type": bool,
          "description": str?,
          "amount": str,
          "categories": [
            {
              "id": int,
              "name": str
            }
          ]
        }
      ],
      "total": str,
      "total_items": int,
      "total_pages": int,
      "page_size": int,
      "page": int,
      "next_page": str?,
      "prev_page": str?
    }

Актуальная версия

Как развернуть проект

Для запуска приложения, в системе должен быть установлен интерпретатор Python версии 3.8 или новее. Совместимость с более ранними версиями не гарантируется.

1. Виртуальное окружение (опционально)

Разработку рекомендуется вести в изолированном режиме из под виртуального окружения. Для его установки потребуется установить пакет virtualenv:

$ pip install virtualenv

2. Клонирование проекта

Чтобы клонировать проект локально - вызовите интерфейс командной строки (например, Git Bash) в желаемой директории, выполните команду:

$ git clone https://github.com/jasper7466/Study-APS-Task3.git

и перейдите в директорию проекта:

$ cd ./Study-APS-Task3

3. Установка виртуального окружения (опционально)

$ python -m virtualenv venv

4. Активация виртуального окружения (опционально)

$ . venv/Scripts/activate

5. Установка пакетов из зависимостей

Зависимости зафиксированы в файле requirements.txt. Для их автоматической установки достаточно выполнить команду:

$ pip install -r requirements.txt

Примечание: если работа ведётся не из под venv - пакеты установятся в систему

6. Установка переменных окружения

Добавление в PYTHONPATH пути до корня приложения (где лежит модуль app.py):

$ export PYTHONPATH=./src (или set PYTHONPATH=./src)

Установка пути до приложения относительно PYTHONPATH в переменную окружения FLASK_APP:

$ export FLASK_APP=app:create_app (или set FLASK_APP=app:create_app)

Для запуска в режиме отладки следует устанавить переменную окружения FLASK_ENV в значение "development":

$ export FLASK_ENV=development (или set FLASK_ENV=development)

При такой настройке:

  • сервер будет запущен в режиме автоматической "горячей" перезагрузки приложения при детектировании изменений в его исходных кодах
  • при возникновении ошибок в браузере будет выводиться stack trace

Установку переменных окружения и некоторых других переменных параметров при каждом запуске приложения можно избежать, добавив в корневую директорию проекта файлы .env и .flaskenv следующего содержания:

.env:

DB_CONNECTION = example.db
SECRET_KEY = secret_key

.flaskenv:

PYTHONPATH = ./src
FLASK_APP = app:create_app
FLASK_ENV = development

Указанные в этих файлах параметры будут автоматически подтягиваться и применяться с помощью пакета python-dotenv

7. Запуск приложения

Для запуска приложения в настроенном на предыдущем шаге режиме выполните команду:

$ flask run

8. Фиксирование зависимостей

После завершения доработки проекта, в случае добавления новых пакетов - следует зафиксировать зависимости, обновив файл requirements.txt. Это можно сделать автоматически, выполнив команду:

$ pip freeze > requirements.txt

Команду имеет смысл выполнять из под виртуального окружения, если оно используется. В противном случае будут подтянуты все локальные пакеты из системы.

Примечания

  • Файл БД не исключён из индекса и присутствует в репозитории для удобства продолжения тестирования/доработки. При отладке желательно скопировать его вне директории проекта, изменив соответствующим образом переменную DB_CONNECTION в файле .env, либо добавить в .gitignore.
  • В качестве инструмента для тестирования API задействован Postman. Коллекция тестовых запросов приведена в виде экспортированного в формате "Collection v2.1" JSON-файла API test requests.postman_collection.json в корне проекта.

Технологии

  • Python
  • Flask
  • HTTP
  • REST API
  • Sqlite

Известные проблемы и что можно улучшить

  • Валидация структуры запросов выполнена частично
  • Валидация передаваемых данных выполнена частично
  • Код не покрыт автоматическими тестами
  • Присутствуют методы, лежащие не совсем в своём сервисе -> дублирование одинаковых исключений от разных сервисов
  • Реализована защита от замыкания категории "сама на себя", но не реализована защита от закольцовывания дерева "на себя". Реализовать не сложно (на базе метода get_categories сервиса transactions), но весьма проблематично в текущем исполнении по причине, указанной в предыдущем пункте
  • Фиксирование зависимостей лучше выполнить более прогрессивным способом, с помощью специализированных библиотек (pipenv, poetry)

Замечания/пожелания по результатам защиты проекта

  • В Docstrings желательно прописывать ожидаемые типы переменных, это упростит тестирование
  • Возвращаемый ответ должен всегда иметь фиксированную для каждого конкретного эндпоинта структуру, это упростит работу фронтенд-разработчику. В текущей реализации необязательные поля не возвращаются в случае, если они пусты (null, undefined)
  • В случае пустого тела ответа (когда по запросу ничего не найдено) - следует возвращать пустой объект, а не код ошибки 404
  • Желательно унифицировать способ отображения элементов и обращения к ним (или везде по id или везде по имени)
  • Для запроса записей с фильтром по временному периоду можно попробовать воспользоваться встроенными инструментами SQLite
  • Для случая, когда в теле запроса отсутствуют обязательные для его обработки поля - лучше возвращать код ошибки 422

About

Antida Python School. Итоговое задание по курсу. Учебный проект "Сервис для учета личных финансов".

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages