This commit is contained in:
parent
520acb9477
commit
8e182fd08e
@ -25,3 +25,8 @@ repos:
|
|||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
language_version: python3.11
|
language_version: python3.11
|
||||||
|
- repo: https://github.com/econchick/interrogate
|
||||||
|
rev: 1.5.0
|
||||||
|
hooks:
|
||||||
|
- id: interrogate
|
||||||
|
args: [--quiet, --fail-under=95]
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
"""Later42 is a Django app that allows you to schedule tasks for later execution."""
|
||||||
from .celery import app as celery_app
|
from .celery import app as celery_app
|
||||||
|
|
||||||
__all__ = ("celery_app",)
|
__all__ = ("celery_app",)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
"""Admin configuration for later42 app."""
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models.urls import URL
|
from .models.urls import URL
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
"""Celery configuration module."""
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from celery import Celery
|
from celery import Celery
|
||||||
@ -15,8 +16,3 @@ app.config_from_object("django.conf:settings", namespace="CELERY")
|
|||||||
|
|
||||||
# Load task modules from all registered Django apps.
|
# Load task modules from all registered Django apps.
|
||||||
app.autodiscover_tasks()
|
app.autodiscover_tasks()
|
||||||
|
|
||||||
|
|
||||||
@app.task(bind=True)
|
|
||||||
def debug_task(self):
|
|
||||||
print(f"Request: {self.request!r}")
|
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
from django.contrib.auth.forms import AuthenticationForm
|
"""Forms for later42 app."""
|
||||||
|
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.forms import UserCreationForm
|
|
||||||
|
|
||||||
|
|
||||||
class SignUpForm(UserCreationForm):
|
class SignUpForm(UserCreationForm):
|
||||||
|
"""Sign up form."""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""Init method."""
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.fields["username"].widget.attrs.update({"class": "form-control"})
|
self.fields["username"].widget.attrs.update({"class": "form-control"})
|
||||||
self.fields["password1"].widget.attrs.update({"class": "form-control"})
|
self.fields["password1"].widget.attrs.update({"class": "form-control"})
|
||||||
@ -13,6 +15,8 @@ class SignUpForm(UserCreationForm):
|
|||||||
self.fields["username"].label = "Логин"
|
self.fields["username"].label = "Логин"
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
"""Meta."""
|
||||||
|
|
||||||
model = User
|
model = User
|
||||||
fields = (
|
fields = (
|
||||||
"username",
|
"username",
|
||||||
@ -23,7 +27,10 @@ class SignUpForm(UserCreationForm):
|
|||||||
|
|
||||||
|
|
||||||
class CustomLoginForm(AuthenticationForm):
|
class CustomLoginForm(AuthenticationForm):
|
||||||
|
"""Custom login form."""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""Init method."""
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.fields["username"].widget.attrs.update({"class": "form-control"})
|
self.fields["username"].widget.attrs.update({"class": "form-control"})
|
||||||
self.fields["password"].widget.attrs.update({"class": "form-control"})
|
self.fields["password"].widget.attrs.update({"class": "form-control"})
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
"""Libs for later42"""
|
@ -1,8 +1,10 @@
|
|||||||
|
"""Content module."""
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from newspaper import Article, Config
|
from newspaper import Article, Config
|
||||||
|
|
||||||
|
|
||||||
def sanitize_img_size(html: str):
|
def sanitize_img_size(html: str):
|
||||||
|
"""Sanitize image size."""
|
||||||
soup = BeautifulSoup(html, "html.parser")
|
soup = BeautifulSoup(html, "html.parser")
|
||||||
for img in soup.find_all("img"):
|
for img in soup.find_all("img"):
|
||||||
img["width"] = "100%"
|
img["width"] = "100%"
|
||||||
@ -11,6 +13,7 @@ def sanitize_img_size(html: str):
|
|||||||
|
|
||||||
|
|
||||||
def get_content(url: str):
|
def get_content(url: str):
|
||||||
|
"""Get content."""
|
||||||
config = Config()
|
config = Config()
|
||||||
config.keep_article_html = True
|
config.keep_article_html = True
|
||||||
article = Article(url, config=config)
|
article = Article(url, config=config)
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
"""Loging module"""
|
@ -1,10 +1,18 @@
|
|||||||
|
"""Logging middleware for debugging purposes."""
|
||||||
|
|
||||||
|
|
||||||
class ExceptionLoggingMiddleware(object):
|
class ExceptionLoggingMiddleware(object):
|
||||||
|
"""Middleware for logging exceptions."""
|
||||||
|
|
||||||
def __init__(self, get_response):
|
def __init__(self, get_response):
|
||||||
|
"""Init method."""
|
||||||
self.get_response = get_response
|
self.get_response = get_response
|
||||||
|
|
||||||
def __call__(self, request):
|
def __call__(self, request):
|
||||||
# Code to be executed for each request before
|
"""
|
||||||
# the view (and later middleware) are called.
|
Code to be executed for each request before
|
||||||
|
the view (and later middleware) are called.
|
||||||
|
"""
|
||||||
print(request.body)
|
print(request.body)
|
||||||
print(request.scheme)
|
print(request.scheme)
|
||||||
print(request.method)
|
print(request.method)
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
# Generated by Django 4.1.2 on 2022-10-12 10:05
|
"""Generated by Django 4.1.2 on 2022-10-12 10:05"""
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
"""Migration"""
|
||||||
|
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
# Generated by Django 4.1.2 on 2022-10-24 13:04
|
"""Generated by Django 4.1.2 on 2022-10-24 13:04"""
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
"""Migration"""
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("later42", "0001_initial"),
|
("later42", "0001_initial"),
|
||||||
]
|
]
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
# Generated by Django 4.1.2 on 2022-10-25 08:05
|
"""Generated by Django 4.1.2 on 2022-10-25 08:05"""
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
"""Migration"""
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("later42", "0002_url_archived"),
|
("later42", "0002_url_archived"),
|
||||||
]
|
]
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
# Generated by Django 4.1.2 on 2022-11-05 17:10
|
"""Generated by Django 4.1.2 on 2022-11-05 17:10"""
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
"""Migration"""
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("later42", "0003_url_content"),
|
("later42", "0003_url_content"),
|
||||||
]
|
]
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
# Generated by Django 4.1.2 on 2022-11-05 17:11
|
"""Generated by Django 4.1.2 on 2022-11-05 17:11"""
|
||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
"""Migration"""
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("later42", "0004_articles"),
|
("later42", "0004_articles"),
|
||||||
]
|
]
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
# Generated by Django 4.1.2 on 2022-11-14 12:28
|
"""Generated by Django 4.1.2 on 2022-11-14 12:28"""
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
"""Migration"""
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("later42", "0005_rename_articles_article"),
|
("later42", "0005_rename_articles_article"),
|
||||||
]
|
]
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
# Generated by Django 4.1.3 on 2022-11-30 06:10
|
"""Generated by Django 4.1.3 on 2022-11-30 06:10"""
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
"""Migration"""
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("later42", "0006_remove_url_content_remove_url_title_article_short_and_more"),
|
("later42", "0006_remove_url_content_remove_url_title_article_short_and_more"),
|
||||||
]
|
]
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
"""Migrations for later42."""
|
@ -0,0 +1 @@
|
|||||||
|
"""Models for later42."""
|
@ -1,8 +1,11 @@
|
|||||||
|
"""Article model.""" ""
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from later42.models.urls import URL
|
from later42.models.urls import URL
|
||||||
|
|
||||||
|
|
||||||
class Article(models.Model):
|
class Article(models.Model):
|
||||||
|
"""Article model."""
|
||||||
|
|
||||||
id = models.AutoField(auto_created=True, primary_key=True)
|
id = models.AutoField(auto_created=True, primary_key=True)
|
||||||
url = models.ForeignKey(URL, on_delete=models.CASCADE)
|
url = models.ForeignKey(URL, on_delete=models.CASCADE)
|
||||||
content = models.TextField(blank=True, null=True)
|
content = models.TextField(blank=True, null=True)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
"""URL model."""
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
@ -5,6 +6,8 @@ User._meta.get_field("email")._unique = True
|
|||||||
|
|
||||||
|
|
||||||
class URL(models.Model):
|
class URL(models.Model):
|
||||||
|
"""URL model."""
|
||||||
|
|
||||||
id = models.AutoField(auto_created=True, primary_key=True)
|
id = models.AutoField(auto_created=True, primary_key=True)
|
||||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
url = models.CharField(max_length=2000)
|
url = models.CharField(max_length=2000)
|
||||||
|
@ -1,14 +1,24 @@
|
|||||||
from django.contrib.auth.models import User, Group
|
"""Serializers for later42 app."""
|
||||||
|
|
||||||
|
from django.contrib.auth.models import Group, User
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
|
||||||
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
|
"""User serializer"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
"""Meta"""
|
||||||
|
|
||||||
model = User
|
model = User
|
||||||
fields = ["url", "username", "email", "groups"]
|
fields = ["url", "username", "email", "groups"]
|
||||||
|
|
||||||
|
|
||||||
class GroupSerializer(serializers.HyperlinkedModelSerializer):
|
class GroupSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
|
"""Group serializer"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
"""Meta"""
|
||||||
|
|
||||||
model = Group
|
model = Group
|
||||||
fields = ["url", "name"]
|
fields = ["url", "name"]
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
"""Celery tasks"""
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import pybrake
|
import pybrake
|
||||||
@ -23,6 +24,7 @@ if AIRBRAKE_PROJECT_ID is not None and AIRBRAKE_PROJECT_KEY is not None:
|
|||||||
|
|
||||||
@shared_task(bind=True, max_retries=3, default_retry_delay=60)
|
@shared_task(bind=True, max_retries=3, default_retry_delay=60)
|
||||||
def get_url_content_task(self, url, user_id):
|
def get_url_content_task(self, url, user_id):
|
||||||
|
"""Get content from url and save it to database"""
|
||||||
data = get_content(url)
|
data = get_content(url)
|
||||||
|
|
||||||
user = User.objects.get(pk=int(user_id))
|
user = User.objects.get(pk=int(user_id))
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
"""Tests"""
|
@ -0,0 +1 @@
|
|||||||
|
"""Tests for later42."""
|
@ -1,3 +1,4 @@
|
|||||||
|
"""Test API views."""
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.test import Client, TestCase
|
from django.test import Client, TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
@ -6,7 +7,10 @@ from rest_framework.test import APIClient
|
|||||||
|
|
||||||
|
|
||||||
class ApiTests(TestCase):
|
class ApiTests(TestCase):
|
||||||
|
"""Test API views."""
|
||||||
|
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
|
"""Set up test data."""
|
||||||
self.username = "testuser1"
|
self.username = "testuser1"
|
||||||
self.email = "testuser1@email.com"
|
self.email = "testuser1@email.com"
|
||||||
self.password = "password1234567QWERTY"
|
self.password = "password1234567QWERTY"
|
||||||
@ -22,6 +26,7 @@ class ApiTests(TestCase):
|
|||||||
self.token = Token.objects.create(user=self.user)
|
self.token = Token.objects.create(user=self.user)
|
||||||
|
|
||||||
def test_url_create(self):
|
def test_url_create(self):
|
||||||
|
"""Test the url creation."""
|
||||||
token = Token.objects.get(user=self.user)
|
token = Token.objects.get(user=self.user)
|
||||||
client = APIClient()
|
client = APIClient()
|
||||||
client.credentials(HTTP_AUTHORIZATION="Token " + token.key)
|
client.credentials(HTTP_AUTHORIZATION="Token " + token.key)
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
|
"""Test the api_token view."""
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.test import TestCase, Client
|
from django.test import Client, TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from rest_framework.authtoken.models import Token
|
from rest_framework.authtoken.models import Token
|
||||||
|
|
||||||
|
|
||||||
class ApiKeyTests(TestCase):
|
class ApiKeyTests(TestCase):
|
||||||
|
"""Test the api_token view."""
|
||||||
|
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
|
"""Set up the test environment."""
|
||||||
self.username = "testuser1"
|
self.username = "testuser1"
|
||||||
self.email = "testuser1@email.com"
|
self.email = "testuser1@email.com"
|
||||||
self.password = "password1234567QWERTY"
|
self.password = "password1234567QWERTY"
|
||||||
@ -19,14 +24,17 @@ class ApiKeyTests(TestCase):
|
|||||||
self.response = self.c.get(reverse("api_token"))
|
self.response = self.c.get(reverse("api_token"))
|
||||||
|
|
||||||
def test_api_key_creation(self):
|
def test_api_key_creation(self):
|
||||||
|
"""Test the api_token view."""
|
||||||
assert self.response.status_code == 302
|
assert self.response.status_code == 302
|
||||||
assert self.response.url == "/profile/"
|
assert self.response.url == "/profile/"
|
||||||
|
|
||||||
def test_api_key_created(self):
|
def test_api_key_created(self):
|
||||||
|
"""Test the api_token creation."""
|
||||||
token = Token.objects.get(user=self.user)
|
token = Token.objects.get(user=self.user)
|
||||||
assert token is not None
|
assert token is not None
|
||||||
|
|
||||||
def test_api_key_reset(self):
|
def test_api_key_reset(self):
|
||||||
|
"""Test the api_token reset."""
|
||||||
token_old = Token.objects.get(user=self.user)
|
token_old = Token.objects.get(user=self.user)
|
||||||
self.response = self.c.get(reverse("api_token"))
|
self.response = self.c.get(reverse("api_token"))
|
||||||
token_new = Token.objects.get(user=self.user)
|
token_new = Token.objects.get(user=self.user)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
"""Test index view."""
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.test import Client, TestCase
|
from django.test import Client, TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
@ -6,7 +7,10 @@ from later42.models.urls import URL
|
|||||||
|
|
||||||
|
|
||||||
class IndexTests(TestCase):
|
class IndexTests(TestCase):
|
||||||
|
"""Test index view."""
|
||||||
|
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
|
"""Set up test data."""
|
||||||
self.username = "testuser1"
|
self.username = "testuser1"
|
||||||
self.email = "testuser1@email.com"
|
self.email = "testuser1@email.com"
|
||||||
self.password = "password1234567QWERTY"
|
self.password = "password1234567QWERTY"
|
||||||
@ -19,6 +23,7 @@ class IndexTests(TestCase):
|
|||||||
self.assertTrue(self.user.is_authenticated)
|
self.assertTrue(self.user.is_authenticated)
|
||||||
|
|
||||||
def test_url_delete(self):
|
def test_url_delete(self):
|
||||||
|
"""Test the url deletion."""
|
||||||
url = URL.objects.create(url="https://www.google.com/", user=self.user)
|
url = URL.objects.create(url="https://www.google.com/", user=self.user)
|
||||||
url.save()
|
url.save()
|
||||||
self.c.delete(reverse("delete", kwargs={"url_id": url.id}))
|
self.c.delete(reverse("delete", kwargs={"url_id": url.id}))
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
|
"""Test login page and profile page"""
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.test import TestCase, Client
|
from django.test import Client, TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
|
|
||||||
class LoginPageTests(TestCase):
|
class LoginPageTests(TestCase):
|
||||||
|
"""Test login page and profile page"""
|
||||||
|
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
|
"""Set up test data"""
|
||||||
self.username = "testuser1"
|
self.username = "testuser1"
|
||||||
self.email = "testuser1@email.com"
|
self.email = "testuser1@email.com"
|
||||||
self.password = "password1234567QWERTY"
|
self.password = "password1234567QWERTY"
|
||||||
@ -17,10 +21,12 @@ class LoginPageTests(TestCase):
|
|||||||
self.assertTrue(self.user.is_authenticated)
|
self.assertTrue(self.user.is_authenticated)
|
||||||
|
|
||||||
def test_login_page(self):
|
def test_login_page(self):
|
||||||
|
"""Test login page"""
|
||||||
response = self.client.get(reverse("login"))
|
response = self.client.get(reverse("login"))
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
def test_index_page_after_login(self):
|
def test_index_page_after_login(self):
|
||||||
|
"""Test index page after login"""
|
||||||
response = self.c.get(reverse("index"))
|
response = self.c.get(reverse("index"))
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.context["user"].is_authenticated
|
assert response.context["user"].is_authenticated
|
||||||
@ -28,11 +34,13 @@ class LoginPageTests(TestCase):
|
|||||||
self.assertContains(response, "/accounts/logout/")
|
self.assertContains(response, "/accounts/logout/")
|
||||||
|
|
||||||
def test_profile_page_template(self):
|
def test_profile_page_template(self):
|
||||||
|
"""Test profile page template"""
|
||||||
response = self.c.get(reverse("profile"))
|
response = self.c.get(reverse("profile"))
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
self.assertTemplateUsed(response, "profile.html")
|
self.assertTemplateUsed(response, "profile.html")
|
||||||
|
|
||||||
def test_api_key_creation_button(self):
|
def test_api_key_creation_button(self):
|
||||||
|
"""Test api key creation button"""
|
||||||
response = self.c.get(reverse("profile"))
|
response = self.c.get(reverse("profile"))
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
self.assertContains(response, 'id="createbutton"')
|
self.assertContains(response, 'id="createbutton"')
|
||||||
|
@ -1,19 +1,24 @@
|
|||||||
|
"""Test pages views."""
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
|
|
||||||
class PageTests(TestCase):
|
class PageTests(TestCase):
|
||||||
|
"""Test pages views."""
|
||||||
|
|
||||||
def test_index_page_url(self):
|
def test_index_page_url(self):
|
||||||
|
"""Test index page url"""
|
||||||
response = self.client.get(reverse("index"))
|
response = self.client.get(reverse("index"))
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertTemplateUsed(response, template_name="index.html")
|
self.assertTemplateUsed(response, template_name="index.html")
|
||||||
|
|
||||||
def test_about_page_url(self):
|
def test_about_page_url(self):
|
||||||
|
"""Test about page url"""
|
||||||
response = self.client.get(reverse("about"))
|
response = self.client.get(reverse("about"))
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertTemplateUsed(response, template_name="about.html")
|
self.assertTemplateUsed(response, template_name="about.html")
|
||||||
|
|
||||||
def test_profile_page_url_redirect(self):
|
def test_profile_page_url_redirect(self):
|
||||||
|
"""Test profile page url redirect"""
|
||||||
response = self.client.get(reverse("profile"))
|
response = self.client.get(reverse("profile"))
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
|
@ -1,26 +1,32 @@
|
|||||||
from django.test import TestCase
|
"""Test signup view."""
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.test import TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
|
|
||||||
class SignUpPageTests(TestCase):
|
class SignUpPageTests(TestCase):
|
||||||
|
"""Test signup view."""
|
||||||
|
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
|
"""Set up test data."""
|
||||||
self.username = "testuser"
|
self.username = "testuser"
|
||||||
self.email = "testuser@email.com"
|
self.email = "testuser@email.com"
|
||||||
self.password = "password1234567QWERTY"
|
self.password = "password1234567QWERTY"
|
||||||
|
|
||||||
def test_signup_page_url(self):
|
def test_signup_page_url(self):
|
||||||
|
"""Test the signup page url."""
|
||||||
response = self.client.get(reverse("signup"))
|
response = self.client.get(reverse("signup"))
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertTemplateUsed(response, template_name="registration/signup.html")
|
self.assertTemplateUsed(response, template_name="registration/signup.html")
|
||||||
|
|
||||||
def test_signup_page_view_name(self):
|
def test_signup_page_view_name(self):
|
||||||
|
"""Test the signup page view name."""
|
||||||
response = self.client.get(reverse("signup"))
|
response = self.client.get(reverse("signup"))
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertTemplateUsed(response, template_name="registration/signup.html")
|
self.assertTemplateUsed(response, template_name="registration/signup.html")
|
||||||
|
|
||||||
def test_signup_form(self):
|
def test_signup_form(self):
|
||||||
|
"""Test the signup form."""
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse("signup"),
|
reverse("signup"),
|
||||||
data={
|
data={
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
|
"""Token generator for user activation.""" ""
|
||||||
from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
|
||||||
class TokenGenerator(PasswordResetTokenGenerator):
|
class TokenGenerator(PasswordResetTokenGenerator):
|
||||||
|
"""Token generator for user activation."""
|
||||||
|
|
||||||
def _make_hash_value(self, user, timestamp):
|
def _make_hash_value(self, user, timestamp):
|
||||||
|
"""Make hash value for user activation."""
|
||||||
return (
|
return (
|
||||||
six.text_type(user.pk)
|
six.text_type(user.pk)
|
||||||
+ six.text_type(timestamp)
|
+ six.text_type(timestamp)
|
||||||
|
@ -14,35 +14,39 @@ Including another URLconf
|
|||||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
"""
|
"""
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from django.urls import path, include
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.urls import include, path
|
||||||
# from django.contrib.auth import views
|
|
||||||
|
|
||||||
from rest_framework import routers, serializers, viewsets
|
from rest_framework import routers, serializers, viewsets
|
||||||
|
|
||||||
# from later42.forms import CustomLoginForm
|
# from later42.forms import CustomLoginForm
|
||||||
from later42.views import (
|
from later42.views import (
|
||||||
|
about,
|
||||||
account_activation,
|
account_activation,
|
||||||
index,
|
|
||||||
profile,
|
|
||||||
api,
|
api,
|
||||||
api_token,
|
api_token,
|
||||||
|
index,
|
||||||
|
profile,
|
||||||
reader,
|
reader,
|
||||||
search,
|
search,
|
||||||
signup,
|
signup,
|
||||||
about,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# from django.contrib.auth import views
|
||||||
|
|
||||||
|
|
||||||
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
|
"""User serializer"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
"""Meta"""
|
||||||
|
|
||||||
model = User
|
model = User
|
||||||
fields = ["url", "username", "email", "is_staff"]
|
fields = ["url", "username", "email", "is_staff"]
|
||||||
|
|
||||||
|
|
||||||
class UserViewSet(viewsets.ModelViewSet):
|
class UserViewSet(viewsets.ModelViewSet):
|
||||||
|
"""User viewset"""
|
||||||
|
|
||||||
queryset = User.objects.all()
|
queryset = User.objects.all()
|
||||||
serializer_class = UserSerializer
|
serializer_class = UserSerializer
|
||||||
|
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
"""Views for the later42 app."""
|
@ -1,5 +1,7 @@
|
|||||||
|
"""About page view."""
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
|
||||||
def get(request):
|
def get(request):
|
||||||
|
"""About page view."""
|
||||||
return render(request, "about.html")
|
return render(request, "about.html")
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
"""Account activation view."""
|
||||||
import django
|
import django
|
||||||
from django.contrib.auth import login
|
from django.contrib.auth import login
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
@ -12,6 +13,7 @@ django.utils.encoding.force_text = force_str
|
|||||||
|
|
||||||
|
|
||||||
def activate(request, uidb64, token):
|
def activate(request, uidb64, token):
|
||||||
|
"""Activate user account."""
|
||||||
try:
|
try:
|
||||||
uid = django.utils.encoding.force_text(urlsafe_base64_decode(uidb64))
|
uid = django.utils.encoding.force_text(urlsafe_base64_decode(uidb64))
|
||||||
user = User.objects.get(pk=uid)
|
user = User.objects.get(pk=uid)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
"""API views for later42."""
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.validators import URLValidator
|
from django.core.validators import URLValidator
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
@ -8,6 +9,7 @@ from later42.tasks import get_url_content_task
|
|||||||
|
|
||||||
|
|
||||||
def validate_url(to_validate: str) -> bool:
|
def validate_url(to_validate: str) -> bool:
|
||||||
|
"""Validate url."""
|
||||||
validator = URLValidator()
|
validator = URLValidator()
|
||||||
try:
|
try:
|
||||||
validator(to_validate)
|
validator(to_validate)
|
||||||
@ -17,7 +19,10 @@ def validate_url(to_validate: str) -> bool:
|
|||||||
|
|
||||||
|
|
||||||
class URL(APIView):
|
class URL(APIView):
|
||||||
|
"""URL API view."""
|
||||||
|
|
||||||
def post(self, request, format=None):
|
def post(self, request, format=None):
|
||||||
|
"""Post url to be processed."""
|
||||||
if validate_url(request.GET.get("url")):
|
if validate_url(request.GET.get("url")):
|
||||||
get_url_content_task.delay(request.GET.get("url"), request.user.id)
|
get_url_content_task.delay(request.GET.get("url"), request.user.id)
|
||||||
return Response({"status": "success"})
|
return Response({"status": "success"})
|
||||||
@ -25,6 +30,7 @@ class URL(APIView):
|
|||||||
return Response({"status": "error"})
|
return Response({"status": "error"})
|
||||||
|
|
||||||
def delete(self, request, format=None):
|
def delete(self, request, format=None):
|
||||||
|
"""Delete url from database."""
|
||||||
id = request.GET.get("id")
|
id = request.GET.get("id")
|
||||||
if id:
|
if id:
|
||||||
url = URLModel.objects.filter(id=id).first()
|
url = URLModel.objects.filter(id=id).first()
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
"""API Token Views."""
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from rest_framework.authtoken.models import Token
|
from rest_framework.authtoken.models import Token
|
||||||
@ -5,6 +6,7 @@ from rest_framework.authtoken.models import Token
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def create(request):
|
def create(request):
|
||||||
|
"""Create API Token for user."""
|
||||||
token = Token.objects.filter(user=request.user)
|
token = Token.objects.filter(user=request.user)
|
||||||
if len(token) > 0:
|
if len(token) > 0:
|
||||||
token.delete()
|
token.delete()
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
"""Index view."""
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
@ -8,6 +9,7 @@ from later42.models.urls import URL
|
|||||||
|
|
||||||
|
|
||||||
def get(request):
|
def get(request):
|
||||||
|
"""Index view."""
|
||||||
data = {}
|
data = {}
|
||||||
try:
|
try:
|
||||||
urls = URL.objects.filter(user=request.user, archived=False).order_by("-id")
|
urls = URL.objects.filter(user=request.user, archived=False).order_by("-id")
|
||||||
@ -22,6 +24,7 @@ def get(request):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def archive(request, url_id=None):
|
def archive(request, url_id=None):
|
||||||
|
"""Archive view."""
|
||||||
if url_id:
|
if url_id:
|
||||||
URL.objects.filter(id=url_id, user=request.user).update(archived=True)
|
URL.objects.filter(id=url_id, user=request.user).update(archived=True)
|
||||||
return redirect("index")
|
return redirect("index")
|
||||||
@ -41,5 +44,6 @@ def archive(request, url_id=None):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def delete(request, url_id):
|
def delete(request, url_id):
|
||||||
|
"""Delete url from database."""
|
||||||
URL.objects.filter(id=url_id, user=request.user).delete()
|
URL.objects.filter(id=url_id, user=request.user).delete()
|
||||||
return redirect("archive")
|
return redirect("archive")
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
"""Profile view."""
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
@ -6,6 +7,7 @@ from rest_framework.authtoken.models import Token
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def get(request):
|
def get(request):
|
||||||
|
"""Profile view."""
|
||||||
token = Token.objects.filter(user=request.user)
|
token = Token.objects.filter(user=request.user)
|
||||||
user = User.objects.get(username=request.user)
|
user = User.objects.get(username=request.user)
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
"""Reader view."""
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
|
||||||
from later42.libs.content import get_content, sanitize_img_size
|
from later42.libs.content import get_content, sanitize_img_size
|
||||||
from later42.models.article import Article
|
from later42.models.article import Article
|
||||||
from later42.models.urls import URL
|
from later42.models.urls import URL
|
||||||
@ -7,6 +9,7 @@ from later42.models.urls import URL
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def get(request, url_id=None):
|
def get(request, url_id=None):
|
||||||
|
"""Reader view."""
|
||||||
url = URL.objects.get(user=request.user, id=url_id)
|
url = URL.objects.get(user=request.user, id=url_id)
|
||||||
content = {}
|
content = {}
|
||||||
try:
|
try:
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
"""Search view."""
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
@ -9,6 +10,7 @@ from later42.models.article import Article
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def search(request):
|
def search(request):
|
||||||
|
"""Search view."""
|
||||||
pattern = request.POST.get("search")
|
pattern = request.POST.get("search")
|
||||||
context = {}
|
context = {}
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
"""Signup view."""
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.sites.shortcuts import get_current_site
|
from django.contrib.sites.shortcuts import get_current_site
|
||||||
from django.core.mail import EmailMessage
|
from django.core.mail import EmailMessage
|
||||||
@ -11,6 +12,7 @@ from later42.tokens import account_activation_token
|
|||||||
|
|
||||||
|
|
||||||
def register(request):
|
def register(request):
|
||||||
|
"""Register user."""
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = SignUpForm(request.POST)
|
form = SignUpForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
Loading…
Reference in New Issue
Block a user