Giter Site home page Giter Site logo

voting-test-task's Introduction

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

Сервис для голосования на Flask. Позволяет создавать и изменять голосования, регистрировать пользователей, голосовать и изменять голос.

Задание

Необходимо написать http-сервис с помощью Flask и развернуть его на сервере (heroku или любой другой).

Приложение должно предоставлять API, позволяющее проходить регистрацию, авторизовываться по Basic Auth, позволяющее добавлять, редактировать, удалять голосования и ответы пользователей со следующими условиями:

  • В голосовании содержится только один вопрос;
  • Вопрос имеет два или более вариантов ответов;
  • Каждый пользователь может ответить и переголосовать;
  • Если пользователь уже проголосовал:
    • по GET выводить статистику по голосованию о суммарном количестве ответов в голосовании, а также по каждому из вопросов, процентном соотношении популярности ответов. Также необходимо отметить, какой из ответов принадлежит данному пользователю;
    • по POST/PATCH/PUT (в зависимости от реализации) предоставить возможность переголосовать. Соответственно, новый голос должен перезаписать старый, чтобы не позволить пользователю иметь несколько действующих ответов на одно голосование одновременно.

Модели объектов и связи между ними, а также выбор хранилища для данных на свое усмотрение. Для представления данных предлагаю использовать JSON формат.

Авторизация

Авторизация: Basic (предоставить логин и пароль закодированные в Base64). Если для эндпойнта необходима авторизация, соответствующий заголовок необходимо включить в запрос в виде Authorization: Basic {логин:пароль в base64}.

Спецификация эндпойнтов API:

/create-voting

  • Создание нового голосования.
  • Методы: POST
  • Авторизация: требуется
  • Формат запроса:
    • body: {"question": строка, "options": [строки]}
  • Возвращает: 201 при успехе, 400 при отсутствии строки в JSON

/delete-voting/<voting_id>

Удаление голосования с id <voting_id>.

  • Методы: GET
  • Авторизация: требуется
  • Возвращает: 200 при успехе, 400 при неправильном формате id, 404 при неудаче (отсутствие голосования с таким id)

/update-voting/<voting_id>

Редактирование голосования.

  • Методы: POST
  • Авторизация: требуется
  • Формат запроса:
    • body: {"question": строка, "options": [строки]}
  • Возвращает: 200 при успехе, 400 при отсутствии строки в JSON, неверном формате id или неудаче при обновлении голосования

/create-user

Регистрация нового пользователя.

  • Методы: POST
  • Авторизация: не требуется
  • Формат запроса:
    • body: {"username": строка, "password": строка}
  • Возвращает: 200 при успехе, 400 при отсутствии строки в JSON

/vote/<voting_id>

Голосование и просмотр результатов голосования.

  • Методы: POST - для голосования, GET - для просмотра результатов.
  • Авторизация: требуется для голосования
  • Формат запроса POST:
    • body: {"option": строка}
  • Возвращает: 200 при успехе, 400 при отсутствии строки в JSON.
  • GET-запрос возвращает JSON (200) при наличии голосования с указанным id в БД, 400 при неверном id, 404 при отстутствии голосвания в БД. Если в запрос включена авторизация, в возвращаемый JSON включается выбранный пользователем вариант.

/list-votings

Просмотр всех голосований.

  • Метод: GET
  • Авторизация: не требуется
  • Возвращает: JSON со всеми голосованиями и статистикой.

NB: все эндпойнты возвращают текст, если не указано иное

Технические подробности

Проект выполнен на Flask (задеплоен на Heroku и работает через gunicorn) с использованием MongoDB (mLab). MongoDB выбрана из-за простоты работы и формата выдачи запросов (словари, которые можно отдавать напрямую в JSON); возможно, реляционная БД была бы лучшим выбором с точки зрения эффективности (позволяет устанавливать связи между таблицами - можно быстрее обновлять информацию о голосах пользователей при изменении голосований), но интереснее было поразбираться в Mongo. Также использовались библиотеки Flask-HTTPAuth для работы с авторизацией и pymongo для работы с MongoDB, библиотека requests для генерации тестовых запросов. Пароли хранятся в БД в виде строки "логин:пароль", закодированной в Base64.

Коллекция votings хранит данные о голосованиях (вопрос, варианты ответов и имя создавшего пользователя для каждого голосования). Коллекция users хранит данные о пользователях: имя, закодированный в base64 пароль и словарь с голосами в формате {voting_id: option}. При составлении статистики по голосованию объекты пользователей в БД опрашиваются по id голосования и формируется суммарная статистика. При изменении вариантов ответа в голосовании у пользователей, выбравших удалённый или изменённый вариант ответа, голос удаляется; при удалении голосования соответствующая запись удаляется у всех пользователей.

Возможные улучшения и нюансы реализации

  • Использование SQL вместо NoSQL со связью полей
  • Валидация URL - в API изменяемые эндпойнты содержат только id голосований, которые потом валидируются на сервере в db_client. Это должны быть шестнадцатеричные строки определённой длины.
  • Для защиты от SQL инъекций необходимо проверять тип и, возможно, длину передаваемых пользователем данных. Я сделал валидацию только в функции create_voting и решил не раздувать код дальше. Но нужно учитывать, что в текущем состоянии приложение может быть уязвимо для SQL-инъекций (см. например https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/NoSQL%20Injection). Кроме того, в идеале в приложение нужно ввести определённые ограничения на количество создаваемых голосований (например, несколько голосований на пользователя в час), чтобы контролировать размер БД.
  • Безопасность паролей - очевидно, полноценная реализация должна использовать нереверсивный алгоритм шифрования паролей. Кроме того, данные для доступа к БД нужно хранить в отдельном скрытом конфиге, в коде они исключительно для наглядности и удобства разработки и деплоя.
  • ООП отсутствует - приложение довольно простое, не хранит никаких состояний и я не увидел необходимости в создании классов. Возможно, стоит создать класс для клиента БД, чтобы в интерфейсе IDE получать список доступных методов, и инициализировать его при запуске сервера, делая коннект к БД, но других применений для ООП здесь я придумать не смог.

Инструкции по развёртыванию

  1. Записать данные для коннекта к БД в setup.py, запустить файл для создания коллекций votings и users, а также пользователя admin. Это необходимо сделать только один раз для подготовки БД к работе. Пользователь admin может удалять и редактировать любые голосования (пароль: admin).
  2. Записать данные для коннекта к БД в db_client.py.
  3. flask run server.py для запуска сервера. При деплое на Heroku этот шаг можно пропустить - сервер стартует автоматически. Опциональные файлы: db_tests.py для заполнения базы голосованиями, случайно сгенерированными пользователями и случайными голосами; http_tests.py для исследования запросов и ответов.

Важно! Проект должен работать на Python 3.6+ из-за использования f-strings.

Рабочий URL с задеплоенным проектом

https://flask-vote-test.herokuapp.com/

voting-test-task's People

Contributors

nagellack5c avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.