Commit 6404754e authored by Volkov Gherman's avatar Volkov Gherman

Merge branch 'develop' into 'master'

Develop

See merge request !8
parents 71407536 836b1c2a
...@@ -4,7 +4,7 @@ DocuSign signature test integration with python DRF service ...@@ -4,7 +4,7 @@ DocuSign signature test integration with python DRF service
Проект подразумевает то, что Вы уже дали согласие на отправку письма на почту. Проект подразумевает то, что Вы уже зарегистрировались на платформе [DocuSign](https://appdemo.docusign.com/home) и дали согласие на отправку письма на почту.
## Технологии ## Технологии
...@@ -12,35 +12,6 @@ DocuSign signature test integration with python DRF service ...@@ -12,35 +12,6 @@ DocuSign signature test integration with python DRF service
- [Django Rest Framework](https://www.django-rest-framework.org/) - [Django Rest Framework](https://www.django-rest-framework.org/)
- [Python](https://www.python.org/) - [Python](https://www.python.org/)
## Использование
Для начала работы приложения нужно:
Вы можете запустить проект двумя разными способами, локально и с помощью контейнера докер
Начнем с запуска приложения локально
Создайте виртуальное окружение с помощью команды:
```sh
$ python3 -m venv venv
```
Активируйте его:
```sh
$ source venv/bin/activate
```
Установите в него все зависимости:
```sh
$ pip install -r requirements/base.txt
```
После этого проведите миграции:
```sh
python3 manage.py migrate
```
Следом запустите сам проект:
```sh
python3 manage.py runserver
```
## Разработка ## Разработка
...@@ -48,6 +19,13 @@ python3 manage.py runserver ...@@ -48,6 +19,13 @@ python3 manage.py runserver
Для установки и запуска проекта, необходим [Python](https://www.python.org/) v3.10+. Для установки и запуска проекта, необходим [Python](https://www.python.org/) v3.10+.
- Также добавьте и заполните **.env** файл со своими данными - Также добавьте и заполните **.env** файл со своими данными
Для начала работы приложения нужно:
Вы можете запустить проект двумя разными способами, локально и с помощью контейнера докер
Начнем с запуска приложения локально
### Установка зависимостей ### Установка зависимостей
Для установки зависимостей, выполните команду: Для установки зависимостей, выполните команду:
```sh ```sh
...@@ -88,8 +66,8 @@ docker-compose up ...@@ -88,8 +66,8 @@ docker-compose up
- [x] Интегрировать приложение DocuSign в проект - [x] Интегрировать приложение DocuSign в проект
- [x] Развернуть сервис в Docker - [x] Развернуть сервис в Docker
- [x] Добавить крутое README - [x] Добавить крутое README
- [ ] Добавить страницу с отображением статуса пользователю - [x] Добавить страницу с отображением статуса пользователю
- [ ] Покрыть приложение тестами - [x] Покрыть приложение тестами
- [ ] Отполировать все до блеска - [ ] Отполировать все до блеска
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
<h1 style="text-align: center; margin-top: 10vh" class="display-6">DocuSign Esign <br> <h1 style="text-align: center; margin-top: 10vh" class="display-6">DocuSign Esign <br>
<small class="text-muted">Подпишите документ с помощью docusign</small> <small class="text-muted">Подпишите документ с помощью docusign</small>
</h1> </h1>
<main style="background: lightgray; width: 70vh; margin-inline: auto"> <main style="background: lightgray; width: 800px; margin-inline: auto">
<form style="width: 70vh; margin: 10vh auto; padding: 20px 30px;" id='form' method="POST"> <form style="width: 800px; margin: 10vh auto; padding: 20px 30px;" id='form' method="POST">
<div class="form-group"> <div class="form-group">
<label for="formGroupExampleInput">Введите свое имя</label> <label for="formGroupExampleInput">Введите свое имя</label>
<input name="signer_name" type="text" class="form-control" id="formGroupExampleInput" placeholder="Вася" <input name="signer_name" type="text" class="form-control" id="formGroupExampleInput" placeholder="Вася"
...@@ -31,8 +31,11 @@ ...@@ -31,8 +31,11 @@
aria-describedby="emailHelp" aria-describedby="emailHelp"
placeholder="vasyaPupkin@.mail.com" required> placeholder="vasyaPupkin@.mail.com" required>
</div> </div>
<div class="d-flex justify-content-between flex-wrap">
<button type="submit" class="btn btn-primary">Подтвердить и подписать документ <button type="submit" class="btn btn-primary">Подтвердить и подписать документ
</button> </button>
<a style="display: none" href="{% url 'view_status' %}" class="btn btn-light" id="link">Показать статус</a>
</div>
</form> </form>
</main> </main>
...@@ -44,15 +47,16 @@ ...@@ -44,15 +47,16 @@
fetch(`${window.location.protocol + '//' + window.location.host}/api/v1/`, { fetch(`${window.location.protocol + '//' + window.location.host}/api/v1/`, {
method: 'POST', method: 'POST',
body: new FormData(form) body: new FormData(form)
}).then(form.reset()) })
.then(() =>{
const linkBtn = document.querySelector('#link')
linkBtn.style.display = 'inline-block'
})
.catch(error => console.error('Произошла ошибка: ', error))
.finally(form.reset())
} }
const form = document.querySelector('#form'); const form = document.querySelector('#form');
try {
form.addEventListener('submit', sendForm); form.addEventListener('submit', sendForm);
} catch (e) {
throw e
}
</script> </script>
</html> </html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DocuSign test page</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
</head>
<body>
<div style="max-width: 800px; margin: 20vh auto;" class="container">
<div class="card" style="max-width: 800px;">
<div class="card-header text-center">
Данные отправителя и статус отправки
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">{{ data.signer.signer_name }}</li>
<li class="list-group-item">{{ data.signer.signer_surname }}</li>
<li class="list-group-item">{{ data.signer.signer_email }}</li>
</ul>
<div class="card text-white
{% if data.status == 'success' %}
bg-success
{% elif data.status == 'fail' %}
bg-danger
{% else %}
bg-primary
{% endif %}
mb-0" style="max-width: 800px;">
<div class="card-body">
<h5 class="card-title"><strong>Статус: </strong>{{ data.signer.status }}</h5>
</div>
</div>
</div>
</div>
</body>
</html>
\ No newline at end of file
from django.test import TestCase from django.urls import reverse
# Create your tests here. import pytest
from rest_framework.test import APIClient
from rest_framework import status
@pytest.fixture
def client():
return APIClient()
@pytest.fixture
def valid_data():
return {'signer_name': 'Гвидыч', 'signer_surname': 'Ванросыч', 'signer_email': 'robogop2510@gmail.com'}
@pytest.fixture
def invalid_data():
return {'signer_name': 'Чебурашка', 'signer_surname': 'Генадьева'}
@pytest.fixture
def expected_data():
return {'id': 1, 'signer_name': 'Гвидыч', 'signer_surname': 'Ванросыч', 'signer_email': 'robogop2510@gmail.com',
'status': 'Документ отправлен на подпись, проверьте Вашу почту'}
def test_index_view_redirects_to_send_email(client):
response = client.get(reverse('index'))
assert response.status_code == status.HTTP_302_FOUND
assert response.url == reverse('send_email')
def test_get_send_document_view(client):
response = client.get(reverse('send_email'))
assert response.status_code == status.HTTP_200_OK
assert 'index.html' in response.template_name
@pytest.mark.django_db
def test_post_valid_data(client, valid_data, expected_data):
response = client.post(reverse('send_email'), valid_data)
assert response.status_code == status.HTTP_200_OK
assert response.data == expected_data
@pytest.mark.django_db
def test_post_invalid_data(client, invalid_data):
response = client.post(reverse('send_email'), invalid_data)
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.data == {'error': 'Bad Request', 'description': 'Введенные Вами данные не валидны'}
from http.client import HTTPException from http.client import HTTPException
from django.shortcuts import redirect from django.shortcuts import redirect, render
from rest_framework.renderers import TemplateHTMLRenderer from rest_framework.renderers import TemplateHTMLRenderer
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
from api.models import StatusChoices from api.models import StatusChoices, SignerInfo
from api.serializers import DocumentNDASerializer from api.serializers import DocumentNDASerializer
from api.services import send_docusign_email from api.services import send_docusign_email
...@@ -19,8 +19,7 @@ class SendDocumentView(APIView): ...@@ -19,8 +19,7 @@ class SendDocumentView(APIView):
template_name = 'index.html' template_name = 'index.html'
def get(self, request): def get(self, request):
data = {'error': 'error'} return Response(template_name=self.template_name, status=200)
return Response(data, template_name=self.template_name, status=200)
def post(self, request): def post(self, request):
serializer = DocumentNDASerializer(data=request.data) serializer = DocumentNDASerializer(data=request.data)
...@@ -36,3 +35,14 @@ class SendDocumentView(APIView): ...@@ -36,3 +35,14 @@ class SendDocumentView(APIView):
signer.save() signer.save()
return Response({'error': e, 'signer': signer}, status=503) return Response({'error': e, 'signer': signer}, status=503)
return Response({'error': 'Bad Request', 'description': 'Введенные Вами данные не валидны'}, status=400) return Response({'error': 'Bad Request', 'description': 'Введенные Вами данные не валидны'}, status=400)
def view_status(request):
signer = SignerInfo.objects.last()
if signer.status == StatusChoices.REJECT:
data = {'signer': signer, 'status': 'fail'}
elif signer.status == StatusChoices.RESOLVE:
data = {'signer': signer, 'status': 'success'}
else:
data = {'signer': signer, 'status': 'default'}
return render(request, 'status.html', context={'data': data}, status=200)
...@@ -13,6 +13,7 @@ https://docs.djangoproject.com/en/4.2/ref/settings/ ...@@ -13,6 +13,7 @@ https://docs.djangoproject.com/en/4.2/ref/settings/
import os import os
from pathlib import Path from pathlib import Path
import pytest
from dotenv import load_dotenv from dotenv import load_dotenv
...@@ -118,7 +119,6 @@ AUTH_PASSWORD_VALIDATORS = [ ...@@ -118,7 +119,6 @@ AUTH_PASSWORD_VALIDATORS = [
}, },
] ]
CORS_ALLOWED_ORIGINS = [ CORS_ALLOWED_ORIGINS = [
'http://localhost:8000', 'http://localhost:8000',
'http://0.0.0.0:8000', 'http://0.0.0.0:8000',
......
...@@ -17,11 +17,12 @@ Including another URLconf ...@@ -17,11 +17,12 @@ Including another URLconf
from django.contrib import admin from django.contrib import admin
from django.urls import path from django.urls import path
from api.views import index_view, SendDocumentView from api.views import index_view, SendDocumentView, view_status
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('', index_view, name='index'), path('', index_view, name='index'),
path('api/v1/', SendDocumentView.as_view(), name='send_email'), path('api/v1/', SendDocumentView.as_view(), name='send_email'),
path('api/v1/status/', view_status, name='view_status'),
] ]
...@@ -11,6 +11,7 @@ then ...@@ -11,6 +11,7 @@ then
echo "PostgreSQL started" echo "PostgreSQL started"
fi fi
pytest .
python manage.py migrate --noinput python manage.py migrate --noinput
python manage.py collectstatic --no-input --clear python manage.py collectstatic --no-input --clear
......
[pytest]
DJANGO_SETTINGS_MODULE = core.settings
python_files = tests.py test_*.py *_tests.py
...@@ -5,3 +5,6 @@ python-dotenv==1.0.* ...@@ -5,3 +5,6 @@ python-dotenv==1.0.*
docusign-esign==3.22.* docusign-esign==3.22.*
django-cors-headers==4.0.* django-cors-headers==4.0.*
gunicorn==20.1.* gunicorn==20.1.*
pytest==7.3.*
pytest-django==4.5.*
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment