This commit is contained in:
parent
500f4dfbdd
commit
520acb9477
@ -39,7 +39,7 @@ indent_style = tab
|
||||
[docs/**.txt]
|
||||
max_line_length = 79
|
||||
|
||||
[*.yml]
|
||||
[*.yaml]
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
|
5
.flake8
Normal file
5
.flake8
Normal file
@ -0,0 +1,5 @@
|
||||
[flake8]
|
||||
max-line-length = 120
|
||||
per-file-ignores =
|
||||
later42/views/index.py: E722
|
||||
later42/views/reader.py: E722
|
27
.pre-commit-config.yaml
Normal file
27
.pre-commit-config.yaml
Normal file
@ -0,0 +1,27 @@
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: check-added-large-files
|
||||
- id: check-ast
|
||||
- id: check-byte-order-marker
|
||||
- id: check-case-conflict
|
||||
- id: check-docstring-first
|
||||
- id: check-executables-have-shebangs
|
||||
- id: check-merge-conflict
|
||||
- id: check-yaml
|
||||
args: [--allow-multiple-documents]
|
||||
- id: debug-statements
|
||||
- id: detect-private-key
|
||||
- id: end-of-file-fixer
|
||||
- id: requirements-txt-fixer
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 6.0.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/ambv/black
|
||||
rev: stable
|
||||
hooks:
|
||||
- id: black
|
||||
language_version: python3.11
|
@ -1,3 +1,3 @@
|
||||
from .celery import app as celery_app
|
||||
|
||||
__all__ = ('celery_app',)
|
||||
__all__ = ("celery_app",)
|
||||
|
@ -11,6 +11,6 @@ import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'later42.settings')
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "later42.settings")
|
||||
|
||||
application = get_asgi_application()
|
||||
|
@ -3,15 +3,15 @@ import os
|
||||
from celery import Celery
|
||||
|
||||
# Set the default Django settings module for the 'celery' program.
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'later42.settings')
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "later42.settings")
|
||||
|
||||
app = Celery('later42')
|
||||
app = Celery("later42")
|
||||
|
||||
# Using a string here means the worker doesn't have to serialize
|
||||
# the configuration object to child processes.
|
||||
# - namespace='CELERY' means all celery-related configuration keys
|
||||
# should have a `CELERY_` prefix.
|
||||
app.config_from_object('django.conf:settings', namespace='CELERY')
|
||||
app.config_from_object("django.conf:settings", namespace="CELERY")
|
||||
|
||||
# Load task modules from all registered Django apps.
|
||||
app.autodiscover_tasks()
|
||||
@ -19,4 +19,4 @@ app.autodiscover_tasks()
|
||||
|
||||
@app.task(bind=True)
|
||||
def debug_task(self):
|
||||
print(f'Request: {self.request!r}')
|
||||
print(f"Request: {self.request!r}")
|
||||
|
@ -7,29 +7,24 @@ from django.contrib.auth.forms import UserCreationForm
|
||||
class SignUpForm(UserCreationForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['username'].widget.attrs.update(
|
||||
{'class': 'form-control'}
|
||||
)
|
||||
self.fields['password1'].widget.attrs.update(
|
||||
{'class': 'form-control'}
|
||||
)
|
||||
self.fields['password2'].widget.attrs.update(
|
||||
{'class': 'form-control'}
|
||||
)
|
||||
self.fields['username'].label = 'Логин'
|
||||
self.fields["username"].widget.attrs.update({"class": "form-control"})
|
||||
self.fields["password1"].widget.attrs.update({"class": "form-control"})
|
||||
self.fields["password2"].widget.attrs.update({"class": "form-control"})
|
||||
self.fields["username"].label = "Логин"
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ('username', 'email', 'password1', 'password2',)
|
||||
fields = (
|
||||
"username",
|
||||
"email",
|
||||
"password1",
|
||||
"password2",
|
||||
)
|
||||
|
||||
|
||||
class CustomLoginForm(AuthenticationForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['username'].widget.attrs.update(
|
||||
{'class': 'form-control'}
|
||||
)
|
||||
self.fields['password'].widget.attrs.update(
|
||||
{'class': 'form-control'}
|
||||
)
|
||||
self.fields['username'].label = 'Логин'
|
||||
self.fields["username"].widget.attrs.update({"class": "form-control"})
|
||||
self.fields["password"].widget.attrs.update({"class": "form-control"})
|
||||
self.fields["username"].label = "Логин"
|
||||
|
@ -3,10 +3,10 @@ from newspaper import Article, Config
|
||||
|
||||
|
||||
def sanitize_img_size(html: str):
|
||||
soup = BeautifulSoup(html, 'html.parser')
|
||||
for img in soup.find_all('img'):
|
||||
img['width'] = '100%'
|
||||
img['height'] = 'auto'
|
||||
soup = BeautifulSoup(html, "html.parser")
|
||||
for img in soup.find_all("img"):
|
||||
img["width"] = "100%"
|
||||
img["height"] = "auto"
|
||||
return str(soup)
|
||||
|
||||
|
||||
|
@ -1,10 +1,8 @@
|
||||
class ExceptionLoggingMiddleware(object):
|
||||
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
def __call__(self, request):
|
||||
|
||||
# Code to be executed for each request before
|
||||
# the view (and later middleware) are called.
|
||||
print(request.body)
|
||||
|
@ -6,7 +6,6 @@ import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
@ -15,12 +14,23 @@ class Migration(migrations.Migration):
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='URL',
|
||||
name="URL",
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('url', models.CharField(max_length=2000)),
|
||||
('title', models.CharField(max_length=2000)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("url", models.CharField(max_length=2000)),
|
||||
("title", models.CharField(max_length=2000)),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
@ -4,15 +4,14 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('later42', '0001_initial'),
|
||||
("later42", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='url',
|
||||
name='archived',
|
||||
model_name="url",
|
||||
name="archived",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
|
@ -4,15 +4,14 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('later42', '0002_url_archived'),
|
||||
("later42", "0002_url_archived"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='url',
|
||||
name='content',
|
||||
model_name="url",
|
||||
name="content",
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
@ -5,18 +5,27 @@ import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('later42', '0003_url_content'),
|
||||
("later42", "0003_url_content"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Articles',
|
||||
name="Articles",
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('content', models.TextField(blank=True, null=True)),
|
||||
('url', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='later42.url')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("content", models.TextField(blank=True, null=True)),
|
||||
(
|
||||
"url",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="later42.url"
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
@ -4,14 +4,13 @@ from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('later42', '0004_articles'),
|
||||
("later42", "0004_articles"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameModel(
|
||||
old_name='Articles',
|
||||
new_name='Article',
|
||||
old_name="Articles",
|
||||
new_name="Article",
|
||||
),
|
||||
]
|
||||
|
@ -4,28 +4,27 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('later42', '0005_rename_articles_article'),
|
||||
("later42", "0005_rename_articles_article"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='url',
|
||||
name='content',
|
||||
model_name="url",
|
||||
name="content",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='url',
|
||||
name='title',
|
||||
model_name="url",
|
||||
name="title",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='article',
|
||||
name='short',
|
||||
model_name="article",
|
||||
name="short",
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='article',
|
||||
name='title',
|
||||
model_name="article",
|
||||
name="title",
|
||||
field=models.CharField(blank=True, max_length=2000, null=True),
|
||||
),
|
||||
]
|
||||
|
@ -4,15 +4,14 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
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"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='article',
|
||||
name='img',
|
||||
model_name="article",
|
||||
name="img",
|
||||
field=models.URLField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
@ -1,7 +1,7 @@
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import models
|
||||
|
||||
User._meta.get_field('email')._unique = True
|
||||
User._meta.get_field("email")._unique = True
|
||||
|
||||
|
||||
class URL(models.Model):
|
||||
|
@ -5,10 +5,10 @@ from rest_framework import serializers
|
||||
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ['url', 'username', 'email', 'groups']
|
||||
fields = ["url", "username", "email", "groups"]
|
||||
|
||||
|
||||
class GroupSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = Group
|
||||
fields = ['url', 'name']
|
||||
fields = ["url", "name"]
|
||||
|
@ -21,80 +21,81 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = os.getenv(
|
||||
'SECRET', 'django-insecure-c%g@wujt4dco#e%k-!25o3)0%t+wm5=k%l(m!kk^p_g%kknod!')
|
||||
"SECRET", "django-insecure-c%g@wujt4dco#e%k-!25o3)0%t+wm5=k%l(m!kk^p_g%kknod!"
|
||||
)
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = os.getenv('DEBUG', False)
|
||||
DEBUG = os.getenv("DEBUG", False)
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
CSRF_TRUSTED_ORIGINS = ['https://' + os.getenv('DOMAIN', 'localhost')]
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
CSRF_TRUSTED_ORIGINS = ["https://" + os.getenv("DOMAIN", "localhost")]
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'later42',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'rest_framework',
|
||||
'rest_framework.authtoken',
|
||||
"later42",
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"rest_framework",
|
||||
"rest_framework.authtoken",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
# 'later42.logging.debug.ExceptionLoggingMiddleware',
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"whitenoise.middleware.WhiteNoiseMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'later42.urls'
|
||||
ROOT_URLCONF = "later42.urls"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [],
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'later42.wsgi.application'
|
||||
WSGI_APPLICATION = "later42.wsgi.application"
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': BASE_DIR / 'db/db.sqlite3',
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": BASE_DIR / "db/db.sqlite3",
|
||||
}
|
||||
}
|
||||
|
||||
if os.getenv('DB_TYPE', 'SQLite') == 'postgres':
|
||||
if os.getenv("DB_TYPE", "SQLite") == "postgres":
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
'HOST': os.environ.get('DB_HOST', None),
|
||||
'NAME': os.environ.get('DB_NAME', None),
|
||||
'USER': os.environ.get('DB_USER', None),
|
||||
'PASSWORD': os.environ.get('DB_PASS', None),
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.postgresql",
|
||||
"HOST": os.environ.get("DB_HOST", None),
|
||||
"NAME": os.environ.get("DB_NAME", None),
|
||||
"USER": os.environ.get("DB_USER", None),
|
||||
"PASSWORD": os.environ.get("DB_PASS", None),
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,16 +105,16 @@ if os.getenv('DB_TYPE', 'SQLite') == 'postgres':
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||
},
|
||||
]
|
||||
|
||||
@ -121,9 +122,9 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/4.1/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'ru-ru'
|
||||
LANGUAGE_CODE = "ru-ru"
|
||||
|
||||
TIME_ZONE = os.getenv('TZ', 'UTC')
|
||||
TIME_ZONE = os.getenv("TZ", "UTC")
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
@ -133,7 +134,7 @@ USE_TZ = True
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.1/howto/static-files/
|
||||
|
||||
STATIC_URL = 'static/'
|
||||
STATIC_URL = "static/"
|
||||
STATICFILES_DIRS = [
|
||||
BASE_DIR / "later42/static",
|
||||
]
|
||||
@ -143,70 +144,68 @@ STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
LOGIN_REDIRECT_URL = "index"
|
||||
LOGOUT_REDIRECT_URL = "index"
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
|
||||
'PAGE_SIZE': 10,
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'rest_framework.authentication.TokenAuthentication',
|
||||
),
|
||||
'DEFAULT_PERMISSION_CLASSES': (
|
||||
'rest_framework.permissions.IsAuthenticated',
|
||||
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
|
||||
"PAGE_SIZE": 10,
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||
"rest_framework.authentication.TokenAuthentication",
|
||||
),
|
||||
"DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
|
||||
}
|
||||
|
||||
# Celery Configuration Options
|
||||
CELERY_TIMEZONE = TIME_ZONE
|
||||
CELERY_TASK_TRACK_STARTED = True
|
||||
CELERY_TASK_TIME_LIMIT = 30 * 60
|
||||
CELERY_BROKER_URL = os.getenv('REDIS_URL', 'redis://localhost:6379')
|
||||
CELERY_RESULT_BACKEND = os.getenv('REDIS_URL', 'redis://localhost:6379')
|
||||
CELERY_BROKER_URL = os.getenv("REDIS_URL", "redis://localhost:6379")
|
||||
CELERY_RESULT_BACKEND = os.getenv("REDIS_URL", "redis://localhost:6379")
|
||||
|
||||
URLS_PER_PAGE = 20
|
||||
READABILITY_HOST = os.getenv('READABILITY_HOST', "http://localhost:8080/")
|
||||
READABILITY_HOST = os.getenv("READABILITY_HOST", "http://localhost:8080/")
|
||||
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
||||
if DEBUG:
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
EMAIL_USE_TLS = os.getenv('EMAIL_USE_TLS', False)
|
||||
EMAIL_HOST = os.getenv('EMAIL_HOST', 'smtp')
|
||||
EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER', None)
|
||||
EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD', None)
|
||||
EMAIL_PORT = os.getenv('EMAIL_PORT', '25')
|
||||
EMAIL_FROM = os.getenv('EMAIL_FROM', 'noreply@later42.com')
|
||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||
EMAIL_USE_TLS = os.getenv("EMAIL_USE_TLS", False)
|
||||
EMAIL_HOST = os.getenv("EMAIL_HOST", "smtp")
|
||||
EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER", None)
|
||||
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD", None)
|
||||
EMAIL_PORT = os.getenv("EMAIL_PORT", "25")
|
||||
EMAIL_FROM = os.getenv("EMAIL_FROM", "noreply@later42.com")
|
||||
|
||||
|
||||
AIRBRAKE = dict(
|
||||
project_id=os.getenv('AIRBRAKE_PROJECT_ID', None),
|
||||
project_key=os.getenv('AIRBRAKE_PROJECT_KEY', None),
|
||||
environment=os.getenv('AIRBRAKE_ENVIRONMENT', 'development'),
|
||||
project_id=os.getenv("AIRBRAKE_PROJECT_ID", None),
|
||||
project_key=os.getenv("AIRBRAKE_PROJECT_KEY", None),
|
||||
environment=os.getenv("AIRBRAKE_ENVIRONMENT", "development"),
|
||||
)
|
||||
|
||||
if AIRBRAKE['project_id'] is not None and AIRBRAKE['project_key'] is not None:
|
||||
MIDDLEWARE += ['pybrake.middleware.django.AirbrakeMiddleware']
|
||||
if AIRBRAKE["project_id"] is not None and AIRBRAKE["project_key"] is not None:
|
||||
MIDDLEWARE += ["pybrake.middleware.django.AirbrakeMiddleware"]
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'handlers': {
|
||||
'airbrake': {
|
||||
'level': 'ERROR',
|
||||
'class': 'pybrake.LoggingHandler',
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"handlers": {
|
||||
"airbrake": {
|
||||
"level": "ERROR",
|
||||
"class": "pybrake.LoggingHandler",
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'app': {
|
||||
'handlers': ['airbrake'],
|
||||
'level': 'ERROR',
|
||||
'propagate': True,
|
||||
"loggers": {
|
||||
"app": {
|
||||
"handlers": ["airbrake"],
|
||||
"level": "ERROR",
|
||||
"propagate": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
SENTRY_DSN = os.getenv('SENTRY_DSN', None)
|
||||
SENTRY_DSN = os.getenv("SENTRY_DSN", None)
|
||||
|
||||
if SENTRY_DSN is not None:
|
||||
import sentry_sdk
|
||||
|
@ -13,7 +13,11 @@ AIRBRAKE_PROJECT_ID = os.getenv("AIRBRAKE_PROJECT_ID", None)
|
||||
AIRBRAKE_PROJECT_KEY = os.getenv("AIRBRAKE_PROJECT_KEY", None)
|
||||
|
||||
if AIRBRAKE_PROJECT_ID is not None and AIRBRAKE_PROJECT_KEY is not None:
|
||||
notifier = pybrake.Notifier(project_id=AIRBRAKE_PROJECT_ID, project_key=AIRBRAKE_PROJECT_KEY, environment="celery")
|
||||
notifier = pybrake.Notifier(
|
||||
project_id=AIRBRAKE_PROJECT_ID,
|
||||
project_key=AIRBRAKE_PROJECT_KEY,
|
||||
environment="celery",
|
||||
)
|
||||
patch_celery(notifier)
|
||||
|
||||
|
||||
|
@ -1,25 +1,20 @@
|
||||
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 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.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.url = "https://google.com"
|
||||
|
||||
self.c = Client()
|
||||
self.c.login(username=self.username, password=self.password)
|
||||
@ -29,7 +24,7 @@ class ApiTests(TestCase):
|
||||
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}')
|
||||
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.assertContains(response, "success")
|
||||
|
@ -6,24 +6,21 @@ 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.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'))
|
||||
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/'
|
||||
assert self.response.url == "/profile/"
|
||||
|
||||
def test_api_key_created(self):
|
||||
token = Token.objects.get(user=self.user)
|
||||
@ -31,6 +28,6 @@ class ApiKeyTests(TestCase):
|
||||
|
||||
def test_api_key_reset(self):
|
||||
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)
|
||||
assert token_old != token_new
|
||||
|
@ -1,20 +1,16 @@
|
||||
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 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.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()
|
||||
|
||||
@ -23,11 +19,8 @@ class IndexTests(TestCase):
|
||||
self.assertTrue(self.user.is_authenticated)
|
||||
|
||||
def test_url_delete(self):
|
||||
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()
|
||||
self.c.delete(reverse('delete', kwargs={'url_id': url.id}))
|
||||
self.c.delete(reverse("delete", kwargs={"url_id": url.id}))
|
||||
url = URL.objects.filter(id=url.id)
|
||||
assert len(url) == 0
|
||||
|
@ -5,13 +5,10 @@ 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.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()
|
||||
|
||||
@ -20,22 +17,22 @@ class LoginPageTests(TestCase):
|
||||
self.assertTrue(self.user.is_authenticated)
|
||||
|
||||
def test_login_page(self):
|
||||
response = self.client.get(reverse('login'))
|
||||
response = self.client.get(reverse("login"))
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_index_page_after_login(self):
|
||||
response = self.c.get(reverse('index'))
|
||||
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/')
|
||||
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'))
|
||||
response = self.c.get(reverse("profile"))
|
||||
assert response.status_code == 200
|
||||
self.assertTemplateUsed(response, 'profile.html')
|
||||
self.assertTemplateUsed(response, "profile.html")
|
||||
|
||||
def test_api_key_creation_button(self):
|
||||
response = self.c.get(reverse('profile'))
|
||||
response = self.c.get(reverse("profile"))
|
||||
assert response.status_code == 200
|
||||
self.assertContains(response, 'id="createbutton"')
|
||||
|
@ -5,15 +5,15 @@ from django.urls import reverse
|
||||
|
||||
class PageTests(TestCase):
|
||||
def test_index_page_url(self):
|
||||
response = self.client.get(reverse('index'))
|
||||
response = self.client.get(reverse("index"))
|
||||
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):
|
||||
response = self.client.get(reverse('about'))
|
||||
response = self.client.get(reverse("about"))
|
||||
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):
|
||||
response = self.client.get(reverse('profile'))
|
||||
response = self.client.get(reverse("profile"))
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
@ -6,27 +6,30 @@ from django.urls import reverse
|
||||
|
||||
class SignUpPageTests(TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.username = 'testuser'
|
||||
self.email = 'testuser@email.com'
|
||||
self.password = 'password1234567QWERTY'
|
||||
self.username = "testuser"
|
||||
self.email = "testuser@email.com"
|
||||
self.password = "password1234567QWERTY"
|
||||
|
||||
def test_signup_page_url(self):
|
||||
response = self.client.get(reverse('signup'))
|
||||
response = self.client.get(reverse("signup"))
|
||||
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):
|
||||
response = self.client.get(reverse('signup'))
|
||||
response = self.client.get(reverse("signup"))
|
||||
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):
|
||||
response = self.client.post(reverse('signup'), data={
|
||||
'username': self.username,
|
||||
'email': self.email,
|
||||
'password1': self.password,
|
||||
'password2': self.password
|
||||
})
|
||||
response = self.client.post(
|
||||
reverse("signup"),
|
||||
data={
|
||||
"username": self.username,
|
||||
"email": self.email,
|
||||
"password1": self.password,
|
||||
"password2": self.password,
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
users = get_user_model().objects.all()
|
||||
|
@ -5,8 +5,9 @@ import six
|
||||
class TokenGenerator(PasswordResetTokenGenerator):
|
||||
def _make_hash_value(self, user, timestamp):
|
||||
return (
|
||||
six.text_type(user.pk) + six.text_type(timestamp) +
|
||||
six.text_type(user.is_active)
|
||||
six.text_type(user.pk)
|
||||
+ six.text_type(timestamp)
|
||||
+ six.text_type(user.is_active)
|
||||
)
|
||||
|
||||
|
||||
|
@ -17,18 +17,29 @@ from django.contrib import admin
|
||||
|
||||
from django.urls import path, include
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
# from django.contrib.auth import views
|
||||
|
||||
from rest_framework import routers, serializers, viewsets
|
||||
|
||||
# from later42.forms import CustomLoginForm
|
||||
from later42.views import account_activation, index, profile, api, api_token, reader, search, signup, about
|
||||
from later42.views import (
|
||||
account_activation,
|
||||
index,
|
||||
profile,
|
||||
api,
|
||||
api_token,
|
||||
reader,
|
||||
search,
|
||||
signup,
|
||||
about,
|
||||
)
|
||||
|
||||
|
||||
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ['url', 'username', 'email', 'is_staff']
|
||||
fields = ["url", "username", "email", "is_staff"]
|
||||
|
||||
|
||||
class UserViewSet(viewsets.ModelViewSet):
|
||||
@ -37,22 +48,25 @@ class UserViewSet(viewsets.ModelViewSet):
|
||||
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register(r'users', UserViewSet)
|
||||
router.register(r"users", UserViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('signup/', signup.register, name='signup'),
|
||||
path(r'^activate/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
|
||||
account_activation.activate, name='activate'),
|
||||
path('accounts/', include('django.contrib.auth.urls')),
|
||||
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'),
|
||||
path('archive/', index.archive, name='archive'),
|
||||
path('archive/<int:url_id>', index.archive, name='archive_url'),
|
||||
path('reader/<int:url_id>', reader.get, name='reader'),
|
||||
path('search/', search.search, name='search'),
|
||||
path("admin/", admin.site.urls),
|
||||
path("signup/", signup.register, name="signup"),
|
||||
path(
|
||||
r"^activate/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$",
|
||||
account_activation.activate,
|
||||
name="activate",
|
||||
),
|
||||
path("accounts/", include("django.contrib.auth.urls")),
|
||||
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"),
|
||||
path("archive/", index.archive, name="archive"),
|
||||
path("archive/<int:url_id>", index.archive, name="archive_url"),
|
||||
path("reader/<int:url_id>", reader.get, name="reader"),
|
||||
path("search/", search.search, name="search"),
|
||||
]
|
||||
|
@ -2,4 +2,4 @@ from django.shortcuts import render
|
||||
|
||||
|
||||
def get(request):
|
||||
return render(request, 'about.html')
|
||||
return render(request, "about.html")
|
||||
|
@ -1,16 +1,13 @@
|
||||
import django
|
||||
from django.core.mail import EmailMessage
|
||||
from django.contrib.auth import login
|
||||
from django.contrib.auth.models import User
|
||||
from later42.tokens import account_activation_token
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render, redirect
|
||||
from django.contrib.auth import login, authenticate
|
||||
from later42.forms import SignUpForm
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.utils.encoding import force_bytes
|
||||
from django.shortcuts import redirect
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.http import urlsafe_base64_decode
|
||||
|
||||
from later42.tokens import account_activation_token
|
||||
|
||||
django.utils.encoding.force_text = force_str
|
||||
|
||||
|
||||
@ -24,6 +21,6 @@ def activate(request, uidb64, token):
|
||||
user.is_active = True
|
||||
user.save()
|
||||
login(request, user)
|
||||
return redirect('index')
|
||||
return redirect("index")
|
||||
else:
|
||||
return HttpResponse('Activation link is invalid!')
|
||||
return HttpResponse("Activation link is invalid!")
|
||||
|
@ -1,10 +1,10 @@
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import URLValidator
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from django.core.validators import URLValidator
|
||||
|
||||
from later42.models.urls import URL as URLModel
|
||||
from later42.tasks import get_url_content_task
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def validate_url(to_validate: str) -> bool:
|
||||
@ -12,25 +12,25 @@ def validate_url(to_validate:str) -> bool:
|
||||
try:
|
||||
validator(to_validate)
|
||||
return True
|
||||
except ValidationError as exception:
|
||||
except ValidationError:
|
||||
return False
|
||||
|
||||
|
||||
class URL(APIView):
|
||||
def post(self, request, format=None):
|
||||
if validate_url(request.GET.get('url')):
|
||||
get_url_content_task.delay(request.GET.get('url'), request.user.id)
|
||||
return Response({'status': 'success'})
|
||||
if validate_url(request.GET.get("url")):
|
||||
get_url_content_task.delay(request.GET.get("url"), request.user.id)
|
||||
return Response({"status": "success"})
|
||||
else:
|
||||
return Response({'status': 'error'})
|
||||
return Response({"status": "error"})
|
||||
|
||||
def delete(self, request, format=None):
|
||||
id = request.GET.get('id')
|
||||
id = request.GET.get("id")
|
||||
if id:
|
||||
url = URLModel.objects.filter(id=id).first()
|
||||
if url:
|
||||
url.archived = True
|
||||
url.save()
|
||||
return Response({'status': 'success'})
|
||||
return Response({"status": "success"})
|
||||
else:
|
||||
return Response({'status': 'error'})
|
||||
return Response({"status": "error"})
|
||||
|
@ -10,4 +10,4 @@ def create(request):
|
||||
token.delete()
|
||||
token = Token.objects.create(user=request.user)
|
||||
token.save()
|
||||
return redirect('profile')
|
||||
return redirect("profile")
|
||||
|
@ -1,8 +1,7 @@
|
||||
from multiprocessing import context
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import render, redirect
|
||||
from django.core.paginator import Paginator
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.paginator import Paginator
|
||||
from django.shortcuts import redirect, render
|
||||
|
||||
from later42.models.article import Article
|
||||
from later42.models.urls import URL
|
||||
@ -11,36 +10,36 @@ from later42.models.urls import URL
|
||||
def get(request):
|
||||
data = {}
|
||||
try:
|
||||
urls = URL.objects.filter(
|
||||
user=request.user, archived=False).order_by('-id')
|
||||
data = Article.objects.filter(
|
||||
url__in=urls).select_related('url').order_by('-id')
|
||||
urls = URL.objects.filter(user=request.user, archived=False).order_by("-id")
|
||||
data = (
|
||||
Article.objects.filter(url__in=urls).select_related("url").order_by("-id")
|
||||
)
|
||||
except:
|
||||
urls = []
|
||||
context = {'data': data}
|
||||
return render(request, 'index.html', context)
|
||||
context = {"data": data}
|
||||
return render(request, "index.html", context)
|
||||
|
||||
|
||||
@login_required
|
||||
def archive(request, url_id=None):
|
||||
if url_id:
|
||||
URL.objects.filter(id=url_id, user=request.user).update(archived=True)
|
||||
return redirect('index')
|
||||
return redirect("index")
|
||||
try:
|
||||
urls = URL.objects.filter(
|
||||
user=request.user, archived=True).order_by('-id')
|
||||
data = Article.objects.filter(
|
||||
url__in=urls).select_related('url').order_by('-id')
|
||||
urls = URL.objects.filter(user=request.user, archived=True).order_by("-id")
|
||||
data = (
|
||||
Article.objects.filter(url__in=urls).select_related("url").order_by("-id")
|
||||
)
|
||||
paginator = Paginator(data, settings.URLS_PER_PAGE)
|
||||
page_number = request.GET.get('page')
|
||||
page_number = request.GET.get("page")
|
||||
data = paginator.get_page(page_number)
|
||||
except:
|
||||
data = []
|
||||
context = {'data': data}
|
||||
return render(request, 'archive.html', context)
|
||||
context = {"data": data}
|
||||
return render(request, "archive.html", context)
|
||||
|
||||
|
||||
@login_required
|
||||
def delete(request, url_id):
|
||||
URL.objects.filter(id=url_id, user=request.user).delete()
|
||||
return redirect('archive')
|
||||
return redirect("archive")
|
||||
|
@ -10,9 +10,8 @@ def get(request):
|
||||
user = User.objects.get(username=request.user)
|
||||
|
||||
if token:
|
||||
context = {'token': token[0], 'user': user}
|
||||
context = {"token": token[0], "user": user}
|
||||
else:
|
||||
context = {'token': None, 'user': user}
|
||||
|
||||
return render(request, 'profile.html', context)
|
||||
context = {"token": None, "user": user}
|
||||
|
||||
return render(request, "profile.html", context)
|
||||
|
@ -7,16 +7,15 @@ from later42.models.urls import URL
|
||||
|
||||
@login_required
|
||||
def get(request, url_id=None):
|
||||
url = URL.objects.get(
|
||||
user=request.user, id=url_id)
|
||||
url = URL.objects.get(user=request.user, id=url_id)
|
||||
content = {}
|
||||
try:
|
||||
article = Article.objects.get(url=url)
|
||||
content['title'] = article.title
|
||||
content['url'] = url.url
|
||||
content['rich_content'] = sanitize_img_size(article.content)
|
||||
content["title"] = article.title
|
||||
content["url"] = url.url
|
||||
content["rich_content"] = sanitize_img_size(article.content)
|
||||
except:
|
||||
content = get_content(url.url)
|
||||
content['rich_content'] = sanitize_img_size(content.article_html)
|
||||
context = {'url': url, 'content': content}
|
||||
return render(request, 'reader.html', context)
|
||||
content["rich_content"] = sanitize_img_size(content.article_html)
|
||||
context = {"url": url, "content": content}
|
||||
return render(request, "reader.html", context)
|
||||
|
@ -5,25 +5,24 @@ from django.db.models import Q
|
||||
from django.shortcuts import render
|
||||
|
||||
from later42.models.article import Article
|
||||
from later42.models.urls import URL as URL
|
||||
|
||||
|
||||
@login_required
|
||||
def search(request):
|
||||
pattern = request.POST.get('search')
|
||||
pattern = request.POST.get("search")
|
||||
context = {}
|
||||
if request.method == 'GET':
|
||||
return render(request, 'search.html', context)
|
||||
elif request.method == 'POST':
|
||||
urls = URL.objects.filter(
|
||||
user=request.user).order_by('-id')
|
||||
if request.method == "GET":
|
||||
return render(request, "search.html", context)
|
||||
elif request.method == "POST":
|
||||
data = Article.objects.filter(
|
||||
Q(title__contains=pattern) |
|
||||
Q(content__contains=pattern) |
|
||||
Q(short__contains=pattern) |
|
||||
Q(url__url__contains=pattern), url__user_id=request.user.id).select_related('url')
|
||||
Q(title__contains=pattern)
|
||||
| Q(content__contains=pattern)
|
||||
| Q(short__contains=pattern)
|
||||
| Q(url__url__contains=pattern),
|
||||
url__user_id=request.user.id,
|
||||
).select_related("url")
|
||||
paginator = Paginator(data, settings.URLS_PER_PAGE)
|
||||
page_number = request.GET.get('page')
|
||||
page_number = request.GET.get("page")
|
||||
data = paginator.get_page(page_number)
|
||||
context = {'data': data}
|
||||
return render(request, 'search.html', context)
|
||||
context = {"data": data}
|
||||
return render(request, "search.html", context)
|
||||
|
@ -1,41 +1,43 @@
|
||||
from django.contrib.auth import authenticate, login
|
||||
from django.shortcuts import redirect, render
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
|
||||
from django.utils.encoding import force_bytes, force_text
|
||||
from django.core.mail import EmailMessage
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.core.mail import EmailMessage
|
||||
from django.shortcuts import render
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.encoding import force_bytes
|
||||
from django.utils.http import urlsafe_base64_encode
|
||||
|
||||
from later42.forms import SignUpForm
|
||||
from later42.tokens import account_activation_token
|
||||
|
||||
|
||||
def register(request):
|
||||
if request.method == 'POST':
|
||||
if request.method == "POST":
|
||||
form = SignUpForm(request.POST)
|
||||
if form.is_valid():
|
||||
user = form.save(commit=False)
|
||||
user.is_active = False
|
||||
user.save()
|
||||
raw_password = form.cleaned_data.get('password1')
|
||||
# raw_password = form.cleaned_data.get("password1")
|
||||
|
||||
current_site = get_current_site(request)
|
||||
|
||||
mail_subject = 'Later42: Активация аккаунта'
|
||||
message = render_to_string('registration/email_activation.html', {
|
||||
'user': user,
|
||||
'domain': current_site.domain,
|
||||
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
|
||||
'token': account_activation_token.make_token(user),
|
||||
})
|
||||
to_email = form.cleaned_data.get('email')
|
||||
mail_subject = "Later42: Активация аккаунта"
|
||||
message = render_to_string(
|
||||
"registration/email_activation.html",
|
||||
{
|
||||
"user": user,
|
||||
"domain": current_site.domain,
|
||||
"uid": urlsafe_base64_encode(force_bytes(user.pk)),
|
||||
"token": account_activation_token.make_token(user),
|
||||
},
|
||||
)
|
||||
to_email = form.cleaned_data.get("email")
|
||||
email = EmailMessage(
|
||||
mail_subject, message, to=[
|
||||
to_email], from_email=settings.EMAIL_FROM
|
||||
mail_subject, message, to=[to_email], from_email=settings.EMAIL_FROM
|
||||
)
|
||||
email.send()
|
||||
|
||||
return render(request, 'registration/email_sent.html')
|
||||
return render(request, "registration/email_sent.html")
|
||||
else:
|
||||
form = SignUpForm()
|
||||
return render(request, 'registration/signup.html', {'form': form})
|
||||
return render(request, "registration/signup.html", {"form": form})
|
||||
|
@ -11,6 +11,6 @@ import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'later42.settings')
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "later42.settings")
|
||||
|
||||
application = get_wsgi_application()
|
||||
|
@ -6,7 +6,7 @@ import sys
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'later42.settings')
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "later42.settings")
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
@ -18,5 +18,5 @@ def main():
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -1,8 +1,8 @@
|
||||
-r requirements.txt
|
||||
|
||||
black
|
||||
django-stubs
|
||||
isort
|
||||
mypy
|
||||
pylint
|
||||
pylint-django
|
||||
mypy
|
||||
django-stubs
|
||||
|
@ -1,13 +1,13 @@
|
||||
bs4==0.0.1
|
||||
celery[redis]==5.2.7
|
||||
Django==4.1.3
|
||||
djangorestframework==3.14.0
|
||||
gunicorn==20.1.0
|
||||
loguru==0.6.0
|
||||
bs4==0.0.1
|
||||
requests==2.28.1
|
||||
djangorestframework==3.14.0
|
||||
whitenoise==6.2.0
|
||||
psycopg2-binary==2.9.5
|
||||
six==1.16.0
|
||||
celery[redis]==5.2.7
|
||||
pybrake==1.10.0
|
||||
sentry-sdk==1.11.0
|
||||
newspaper3k==0.2.8
|
||||
psycopg2-binary==2.9.5
|
||||
pybrake==1.10.0
|
||||
requests==2.28.1
|
||||
sentry-sdk==1.11.0
|
||||
six==1.16.0
|
||||
whitenoise==6.2.0
|
||||
|
Loading…
Reference in New Issue
Block a user