diff --git a/later42/templates/about.html b/later42/templates/about.html new file mode 100644 index 0000000..0fc9f20 --- /dev/null +++ b/later42/templates/about.html @@ -0,0 +1,6 @@ +{% extends 'base.html' %} + +{% block content %} + {% include 'about_include.html' %} + {% include 'faq_include.html' %} +{% endblock %} diff --git a/later42/templates/about_include.html b/later42/templates/about_include.html new file mode 100644 index 0000000..9379eb8 --- /dev/null +++ b/later42/templates/about_include.html @@ -0,0 +1,24 @@ +

Сервис для сохранения ссылок

+ +

+ Сохраняйте заинтересовавшие вас ссылки для последующего вдумчивого чтения. +

+

+ В наше спешащее время мы не успеваем читать вдумчиво и спокойно. Пролистываем тонны информации за день. + Теперь можно не спешить, а просто отложить ссылку на интересную статью, чтобы потом вернуться к ней и в спокойной + обстановке вдумчиво ее прочитать. +

+ +

Как это работает

+ +

+ Для начала работы нужно только зарегистрироваться и получить API ключ. +

+

+ Дальше устанавливаете Команду "Shortcut" в ваше iOS или MacOS устройство и через меню "Поделиться" добавляете ссылку. +

+

+ При первом запуске Команда спросит ваш API ключ. Дальше все будет работать прозрачно и без лишних вопросов. +

+ +

diff --git a/later42/templates/base.html b/later42/templates/base.html index 2af7d45..2ee4029 100644 --- a/later42/templates/base.html +++ b/later42/templates/base.html @@ -29,6 +29,7 @@ diff --git a/later42/templates/docs.html b/later42/templates/docs.html deleted file mode 100644 index 71df6fe..0000000 --- a/later42/templates/docs.html +++ /dev/null @@ -1,2 +0,0 @@ -Test content block -

diff --git a/later42/templates/faq_include.html b/later42/templates/faq_include.html new file mode 100644 index 0000000..94265a3 --- /dev/null +++ b/later42/templates/faq_include.html @@ -0,0 +1,9 @@ +{% load static %} +

Часто задаваемые вопросы:

+

+

Где взять команду Shortcuts для iOS/MacOS?

+

Скачать команду.

+

После установки команды и первого запуска из меню "Поделиться" вас попросит ввести ваш API ключ. Взять его вы + можете в вашем профиле.

+

Будет ли поддержка Android?

+

Да, поддержка устройств на OS Android планируется через бота в Telegram. Сроки пока не известны.

diff --git a/later42/templates/index.html b/later42/templates/index.html index 11e6af0..84dfb2d 100644 --- a/later42/templates/index.html +++ b/later42/templates/index.html @@ -25,6 +25,6 @@

У вас нет сохраненных ссылок

{% elif not user.is_authenticated %} - {% include 'docs.html' %} + {% include 'about_include.html' %} {% endif %} {% endblock %} diff --git a/later42/templates/profile.html b/later42/templates/profile.html index e373a8a..26b2546 100644 --- a/later42/templates/profile.html +++ b/later42/templates/profile.html @@ -36,12 +36,12 @@ {{ token }}
{% csrf_token %} - +
{% else %}
{% csrf_token %} - +
{% endif %} diff --git a/later42/tests/__init__.py b/later42/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/later42/tests/views/__init__.py b/later42/tests/views/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/later42/tests/views/test_api.py b/later42/tests/views/test_api.py new file mode 100644 index 0000000..c354634 --- /dev/null +++ b/later42/tests/views/test_api.py @@ -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) diff --git a/later42/tests/views/test_api_token.py b/later42/tests/views/test_api_token.py new file mode 100644 index 0000000..c3943c9 --- /dev/null +++ b/later42/tests/views/test_api_token.py @@ -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 diff --git a/later42/tests/views/test_index.py b/later42/tests/views/test_index.py new file mode 100644 index 0000000..727cebd --- /dev/null +++ b/later42/tests/views/test_index.py @@ -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 diff --git a/later42/tests/views/test_login.py b/later42/tests/views/test_login.py new file mode 100644 index 0000000..4314c1e --- /dev/null +++ b/later42/tests/views/test_login.py @@ -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"') diff --git a/later42/tests/views/test_pages.py b/later42/tests/views/test_pages.py new file mode 100644 index 0000000..966ec07 --- /dev/null +++ b/later42/tests/views/test_pages.py @@ -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) diff --git a/later42/tests/views/test_signup.py b/later42/tests/views/test_signup.py new file mode 100644 index 0000000..ddf1925 --- /dev/null +++ b/later42/tests/views/test_signup.py @@ -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) diff --git a/later42/urls.py b/later42/urls.py index 5beb9ad..21af61f 100644 --- a/later42/urls.py +++ b/later42/urls.py @@ -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/', index.delete, name='delete'), path('profile/', profile.get, name='profile'), + path('api/url/', api.URL.as_view(), name='urls'), + path('delete/', index.delete, name='delete'), path('api_token/', api_token.create, name='api_token'), + path('', index.get, name='index'), + path('about/', about.get, name='about'), ] diff --git a/later42/views/about.py b/later42/views/about.py new file mode 100644 index 0000000..8d35a2d --- /dev/null +++ b/later42/views/about.py @@ -0,0 +1,5 @@ +from django.shortcuts import render + + +def get(request): + return render(request, 'about.html') diff --git a/later42/views/api_token.py b/later42/views/api_token.py index c5c25fe..2c0e16a 100644 --- a/later42/views/api_token.py +++ b/later42/views/api_token.py @@ -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') \ No newline at end of file + return redirect('profile') diff --git a/later42/views/signup.py b/later42/views/signup.py index 59ad96e..4ac27d7 100644 --- a/later42/views/signup.py +++ b/later42/views/signup.py @@ -18,4 +18,4 @@ def register(request): return redirect('index') else: form = SignUpForm() - return render(request, 'signup.html', {'form': form}) \ No newline at end of file + return render(request, 'signup.html', {'form': form})