feat: add tests
This commit is contained in:
6
later42/templates/about.html
Normal file
6
later42/templates/about.html
Normal file
@ -0,0 +1,6 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'about_include.html' %}
|
||||
{% include 'faq_include.html' %}
|
||||
{% endblock %}
|
24
later42/templates/about_include.html
Normal file
24
later42/templates/about_include.html
Normal file
@ -0,0 +1,24 @@
|
||||
<h2>Сервис для сохранения ссылок</h2>
|
||||
|
||||
<p>
|
||||
Сохраняйте заинтересовавшие вас ссылки для последующего вдумчивого чтения.
|
||||
</p>
|
||||
<p>
|
||||
В наше спешащее время мы не успеваем читать вдумчиво и спокойно. Пролистываем тонны информации за день.
|
||||
Теперь можно не спешить, а просто отложить ссылку на интересную статью, чтобы потом вернуться к ней и в спокойной
|
||||
обстановке вдумчиво ее прочитать.
|
||||
</p>
|
||||
|
||||
<h2>Как это работает</h2>
|
||||
|
||||
<p>
|
||||
Для начала работы нужно только зарегистрироваться и получить API ключ.
|
||||
</p>
|
||||
<p>
|
||||
Дальше устанавливаете Команду "Shortcut" в ваше iOS или MacOS устройство и через меню "Поделиться" добавляете ссылку.
|
||||
</p>
|
||||
<p>
|
||||
При первом запуске Команда спросит ваш API ключ. Дальше все будет работать прозрачно и без лишних вопросов.
|
||||
</p>
|
||||
|
||||
<p></p>
|
@ -29,6 +29,7 @@
|
||||
<div class="collapse navbar-collapse" id="navbarResponsive">
|
||||
<ul class="navbar-nav ms-auto py-4 py-lg-0">
|
||||
{% if user.is_authenticated %}
|
||||
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{% url 'about' %}">О нас</a></li>
|
||||
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{% url 'profile' %}">Профиль</a></li>
|
||||
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{% url 'logout' %}">Выйти</a></li>
|
||||
{% else %}
|
||||
@ -77,7 +78,7 @@
|
||||
</a>
|
||||
</li>
|
||||
<li class="list-inline-item">
|
||||
<a href="#!">
|
||||
<a href="https://github.com/dntsk/later42">
|
||||
<span class="fa-stack fa-lg">
|
||||
<i class="fas fa-circle fa-stack-2x"></i>
|
||||
<i class="fab fa-github fa-stack-1x fa-inverse"></i>
|
||||
@ -85,7 +86,8 @@
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="small text-center text-muted fst-italic">© dntsk.dev, 2022</div>
|
||||
<div class="small text-center text-muted fst-italic">Later 42 by <a href="https://dntsk.dev">dntsk.dev</a>, 2022</div>
|
||||
<div class="small text-center text-muted fst-italic">v0.0.1</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,2 +0,0 @@
|
||||
Test content block
|
||||
<p></p>
|
9
later42/templates/faq_include.html
Normal file
9
later42/templates/faq_include.html
Normal file
@ -0,0 +1,9 @@
|
||||
{% load static %}
|
||||
<h2>Часто задаваемые вопросы:</h2>
|
||||
<p></p>
|
||||
<h4>Где взять команду Shortcuts для iOS/MacOS?</h4>
|
||||
<p><a href="{% static 'apps/later42.shortcut' %}">Скачать команду</a>.</p>
|
||||
<p>После установки команды и первого запуска из меню "Поделиться" вас попросит ввести ваш API ключ. Взять его вы
|
||||
можете в <a href="{% url 'profile' %}">вашем профиле</a>.</p>
|
||||
<h4>Будет ли поддержка Android?</h4>
|
||||
<p>Да, поддержка устройств на OS Android планируется через бота в Telegram. Сроки пока не известны.</p>
|
@ -25,6 +25,6 @@
|
||||
<h2 class="post-title">У вас нет сохраненных ссылок</h2>
|
||||
</div>
|
||||
{% elif not user.is_authenticated %}
|
||||
{% include 'docs.html' %}
|
||||
{% include 'about_include.html' %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
@ -36,12 +36,12 @@
|
||||
{{ token }}
|
||||
<form action="{% url 'api_token' %}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="Сбросить на новый">
|
||||
<input class="btn btn-primary text-uppercase" type="submit" id="resetbutton" value="Сбросить на новый">
|
||||
</form>
|
||||
{% else %}
|
||||
<form action="{% url 'api_token' %}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="Создать">
|
||||
<input class="btn btn-primary text-uppercase" type="submit" id="createbutton" value="Создать">
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
0
later42/tests/__init__.py
Normal file
0
later42/tests/__init__.py
Normal file
0
later42/tests/views/__init__.py
Normal file
0
later42/tests/views/__init__.py
Normal file
36
later42/tests/views/test_api.py
Normal file
36
later42/tests/views/test_api.py
Normal file
@ -0,0 +1,36 @@
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase, Client
|
||||
from django.urls import reverse
|
||||
from rest_framework.authtoken.models import Token
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from later42.models.urls import URL
|
||||
|
||||
|
||||
class ApiTests(TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.username = 'testuser1'
|
||||
self.email = 'testuser1@email.com'
|
||||
self.password = 'password1234567QWERTY'
|
||||
self.user = User.objects.create(
|
||||
username=self.username,
|
||||
email=self.email
|
||||
)
|
||||
self.user.set_password(self.password)
|
||||
self.user.save()
|
||||
|
||||
self.url = 'https://google.com'
|
||||
|
||||
self.c = Client()
|
||||
self.c.login(username=self.username, password=self.password)
|
||||
self.assertTrue(self.user.is_authenticated)
|
||||
self.token = Token.objects.create(user=self.user)
|
||||
|
||||
def test_url_create(self):
|
||||
token = Token.objects.get(user=self.user)
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION='Token ' + token.key)
|
||||
response = client.post(reverse('urls') + f'?url={self.url}')
|
||||
assert response.status_code == 200
|
||||
self.assertContains(response, 'success')
|
||||
self.assertEqual(URL.objects.count(), 1)
|
36
later42/tests/views/test_api_token.py
Normal file
36
later42/tests/views/test_api_token.py
Normal file
@ -0,0 +1,36 @@
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase, Client
|
||||
from django.urls import reverse
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
|
||||
class ApiKeyTests(TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.username = 'testuser1'
|
||||
self.email = 'testuser1@email.com'
|
||||
self.password = 'password1234567QWERTY'
|
||||
self.user = User.objects.create(
|
||||
username=self.username,
|
||||
email=self.email
|
||||
)
|
||||
self.user.set_password(self.password)
|
||||
self.user.save()
|
||||
|
||||
self.c = Client()
|
||||
self.c.login(username=self.username, password=self.password)
|
||||
self.assertTrue(self.user.is_authenticated)
|
||||
self.response = self.c.get(reverse('api_token'))
|
||||
|
||||
def test_api_key_creation(self):
|
||||
assert self.response.status_code == 302
|
||||
assert self.response.url == '/profile/'
|
||||
|
||||
def test_api_key_created(self):
|
||||
token = Token.objects.get(user=self.user)
|
||||
assert token is not None
|
||||
|
||||
def test_api_key_reset(self):
|
||||
token_old = Token.objects.get(user=self.user)
|
||||
self.response = self.c.get(reverse('api_token'))
|
||||
token_new = Token.objects.get(user=self.user)
|
||||
assert token_old != token_new
|
33
later42/tests/views/test_index.py
Normal file
33
later42/tests/views/test_index.py
Normal file
@ -0,0 +1,33 @@
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase, Client
|
||||
from django.urls import reverse
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
from later42.models.urls import URL
|
||||
|
||||
|
||||
class IndexTests(TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.username = 'testuser1'
|
||||
self.email = 'testuser1@email.com'
|
||||
self.password = 'password1234567QWERTY'
|
||||
self.user = User.objects.create(
|
||||
username=self.username,
|
||||
email=self.email
|
||||
)
|
||||
self.user.set_password(self.password)
|
||||
self.user.save()
|
||||
|
||||
self.c = Client()
|
||||
self.c.login(username=self.username, password=self.password)
|
||||
self.assertTrue(self.user.is_authenticated)
|
||||
|
||||
def test_url_delete(self):
|
||||
url = URL.objects.create(
|
||||
url='https://www.google.com/',
|
||||
user=self.user
|
||||
)
|
||||
url.save()
|
||||
self.c.delete(reverse('delete', kwargs={'url_id': url.id}))
|
||||
url = URL.objects.filter(id=url.id)
|
||||
assert len(url) == 0
|
41
later42/tests/views/test_login.py
Normal file
41
later42/tests/views/test_login.py
Normal file
@ -0,0 +1,41 @@
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase, Client
|
||||
from django.urls import reverse
|
||||
|
||||
|
||||
class LoginPageTests(TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.username = 'testuser1'
|
||||
self.email = 'testuser1@email.com'
|
||||
self.password = 'password1234567QWERTY'
|
||||
self.user = User.objects.create(
|
||||
username=self.username,
|
||||
email=self.email
|
||||
)
|
||||
self.user.set_password(self.password)
|
||||
self.user.save()
|
||||
|
||||
self.c = Client()
|
||||
self.c.login(username=self.username, password=self.password)
|
||||
self.assertTrue(self.user.is_authenticated)
|
||||
|
||||
def test_login_page(self):
|
||||
response = self.client.get(reverse('login'))
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_index_page_after_login(self):
|
||||
response = self.c.get(reverse('index'))
|
||||
assert response.status_code == 200
|
||||
assert response.context['user'].is_authenticated
|
||||
self.assertTemplateUsed(response, 'index.html')
|
||||
self.assertContains(response, '/accounts/logout/')
|
||||
|
||||
def test_profile_page_template(self):
|
||||
response = self.c.get(reverse('profile'))
|
||||
assert response.status_code == 200
|
||||
self.assertTemplateUsed(response, 'profile.html')
|
||||
|
||||
def test_api_key_creation_button(self):
|
||||
response = self.c.get(reverse('profile'))
|
||||
assert response.status_code == 200
|
||||
self.assertContains(response, 'id="createbutton"')
|
19
later42/tests/views/test_pages.py
Normal file
19
later42/tests/views/test_pages.py
Normal file
@ -0,0 +1,19 @@
|
||||
from django.test import TestCase
|
||||
|
||||
from django.urls import reverse
|
||||
|
||||
|
||||
class PageTests(TestCase):
|
||||
def test_index_page_url(self):
|
||||
response = self.client.get(reverse('index'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, template_name='index.html')
|
||||
|
||||
def test_about_page_url(self):
|
||||
response = self.client.get(reverse('about'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, template_name='about.html')
|
||||
|
||||
def test_profile_page_url_redirect(self):
|
||||
response = self.client.get(reverse('profile'))
|
||||
self.assertEqual(response.status_code, 302)
|
33
later42/tests/views/test_signup.py
Normal file
33
later42/tests/views/test_signup.py
Normal file
@ -0,0 +1,33 @@
|
||||
from django.test import TestCase
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.urls import reverse
|
||||
|
||||
|
||||
class SignUpPageTests(TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.username = 'testuser'
|
||||
self.email = 'testuser@email.com'
|
||||
self.password = 'password1234567QWERTY'
|
||||
|
||||
def test_signup_page_url(self):
|
||||
response = self.client.get(reverse('signup'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, template_name='signup.html')
|
||||
|
||||
def test_signup_page_view_name(self):
|
||||
response = self.client.get(reverse('signup'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, template_name='signup.html')
|
||||
|
||||
def test_signup_form(self):
|
||||
response = self.client.post(reverse('signup'), data={
|
||||
'username': self.username,
|
||||
'email': self.email,
|
||||
'password1': self.password,
|
||||
'password2': self.password
|
||||
})
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
users = get_user_model().objects.all()
|
||||
self.assertEqual(users.count(), 1)
|
@ -22,7 +22,7 @@ from django.contrib.auth.views import LoginView
|
||||
from rest_framework import routers, serializers, viewsets
|
||||
|
||||
from later42.forms import CustomLoginForm
|
||||
from later42.views import index, profile, api, api_token, signup
|
||||
from later42.views import index, profile, api, api_token, signup, about
|
||||
|
||||
|
||||
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
||||
@ -45,9 +45,10 @@ urlpatterns = [
|
||||
path("accounts/login/", LoginView.as_view(authentication_form=CustomLoginForm), name="login"),
|
||||
path('accounts/', include('django_registration.backends.activation.urls')),
|
||||
path("accounts/", include("django.contrib.auth.urls")),
|
||||
path('api/url/', api.URL.as_view(), name='urls'),
|
||||
path('', index.get, name='index'),
|
||||
path('delete/<int:url_id>', index.delete, name='delete'),
|
||||
path('profile/', profile.get, name='profile'),
|
||||
path('api/url/', api.URL.as_view(), name='urls'),
|
||||
path('delete/<int:url_id>', index.delete, name='delete'),
|
||||
path('api_token/', api_token.create, name='api_token'),
|
||||
path('', index.get, name='index'),
|
||||
path('about/', about.get, name='about'),
|
||||
]
|
||||
|
5
later42/views/about.py
Normal file
5
later42/views/about.py
Normal file
@ -0,0 +1,5 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
|
||||
def get(request):
|
||||
return render(request, 'about.html')
|
@ -1,13 +1,13 @@
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import redirect
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
|
||||
@login_required
|
||||
def create(request):
|
||||
token = Token.objects.filter(user=request.user)
|
||||
try:
|
||||
if len(token) > 0:
|
||||
token.delete()
|
||||
except:
|
||||
pass
|
||||
token = Token.objects.create(user=request.user)
|
||||
token.save()
|
||||
return redirect('profile')
|
Reference in New Issue
Block a user