delayed add url and search
This commit is contained in:
parent
9904586ea0
commit
dddbb034e5
@ -34,6 +34,7 @@ services:
|
||||
max-file: "5"
|
||||
|
||||
later42:
|
||||
build: .
|
||||
container_name: later42
|
||||
image: dntskdev/later42:master
|
||||
restart: always
|
||||
@ -59,6 +60,28 @@ services:
|
||||
- "traefik.http.routers.later42-opt.tls.certresolver=myresolver"
|
||||
- "extdns.cf.later42.hostname=later42.com"
|
||||
|
||||
# later42_tasks:
|
||||
# build: .
|
||||
# container_name: later42_tasks
|
||||
# image: dntskdev/later42:master
|
||||
# restart: always
|
||||
# command: celery -A later42 worker --loglevel=info
|
||||
# environment:
|
||||
# SECRET: "ahth3chaquodahh6que8thie1EThe5Iephich8eikei2Uojaemae6gee0kaet4aush2aoqu0ruL9oGhaiR9luu7cohreH6lebo0v"
|
||||
# DB_TYPE: postgres
|
||||
# DB_HOST: later42db
|
||||
# DB_NAME: later42
|
||||
# DB_USER: later42
|
||||
# DB_PASS: later42
|
||||
# DOMAIN: later42.com
|
||||
# READABILITY_HOST: http://ureadability:8080/
|
||||
# REDIS_URL: redis://redis:6379
|
||||
# logging:
|
||||
# driver: json-file
|
||||
# options:
|
||||
# max-size: "10m"
|
||||
# max-file: "5"
|
||||
|
||||
later42db:
|
||||
container_name: later42db
|
||||
image: postgres
|
||||
|
@ -0,0 +1,31 @@
|
||||
# Generated by Django 4.1.2 on 2022-11-14 12:28
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('later42', '0005_rename_articles_article'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='url',
|
||||
name='content',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='url',
|
||||
name='title',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='article',
|
||||
name='short',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='article',
|
||||
name='title',
|
||||
field=models.CharField(blank=True, max_length=2000, null=True),
|
||||
),
|
||||
]
|
@ -1,4 +1,3 @@
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import models
|
||||
from later42.models.urls import URL
|
||||
|
||||
@ -7,3 +6,5 @@ class Article(models.Model):
|
||||
id = models.AutoField(auto_created=True, primary_key=True)
|
||||
url = models.ForeignKey(URL, on_delete=models.CASCADE)
|
||||
content = models.TextField(blank=True, null=True)
|
||||
title = models.CharField(max_length=2000, blank=True, null=True)
|
||||
short = models.TextField(blank=True, null=True)
|
||||
|
@ -8,6 +8,4 @@ class URL(models.Model):
|
||||
id = models.AutoField(auto_created=True, primary_key=True)
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
url = models.CharField(max_length=2000)
|
||||
title = models.CharField(max_length=2000)
|
||||
archived = models.BooleanField(default=False)
|
||||
content = models.TextField(blank=True, null=True)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import os
|
||||
import pybrake
|
||||
from celery import shared_task
|
||||
from django.contrib.auth.models import User
|
||||
from pybrake.middleware.celery import patch_celery
|
||||
from later42.models.urls import URL
|
||||
from later42.models.article import Article
|
||||
@ -19,9 +20,17 @@ if AIRBRAKE_PROJECT_ID is not None and AIRBRAKE_PROJECT_KEY is not None:
|
||||
|
||||
|
||||
@shared_task()
|
||||
def get_url_content_task(id):
|
||||
url = URL.objects.get(id=id)
|
||||
article = Article.objects.create(url=url)
|
||||
content = get_content(url.url)['rich_content']
|
||||
article.content = content
|
||||
def get_url_content_task(url, user_id):
|
||||
print(url)
|
||||
print(user_id)
|
||||
user = User.objects.get(pk=int(user_id))
|
||||
url_object = URL(url=url, user=user)
|
||||
url_object.save()
|
||||
|
||||
data = get_content(url)
|
||||
|
||||
article = Article.objects.create(url=url_object)
|
||||
article.content = data['rich_content']
|
||||
article.title = data['title']
|
||||
article.short = data['excerpt']
|
||||
article.save()
|
||||
|
@ -2,54 +2,57 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="post-preview">
|
||||
{% if urls|length > 0 %}
|
||||
{% for url in urls %}
|
||||
{% if data|length > 0 %}
|
||||
{% for d in data %}
|
||||
<!-- Post preview-->
|
||||
<div class="post-preview">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="p-2">
|
||||
<a href="{% url 'reader' url.id %}">
|
||||
<h2 class="post-title">{{ url.title }}</h2>
|
||||
<a href="{% url 'reader' d.url.id %}">
|
||||
<h2 class="post-title">{% if d.title %}{{ d.title }}{% else %}Без заголовка{% endif %}</h2>
|
||||
</a>
|
||||
</div>
|
||||
<div class="p-2">
|
||||
<a href="/delete/{{ url.id }}"><span class="fa-regular fa-trash-can"></span></a>
|
||||
<a href="/delete/{{ d.url.id }}"><span class="fa-regular fa-trash-can"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
{% if url.content %}
|
||||
{% if d.short %}
|
||||
<p class="post-meta">
|
||||
{{ url.content }}
|
||||
{{ d.short }}
|
||||
</p>
|
||||
{% endif %}
|
||||
<p class="post-meta">
|
||||
<a href="{{ url.url }}">
|
||||
{{ url.url }}
|
||||
<a href="{{ d.url.url }}">
|
||||
{{ d.url.url }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<!-- Divider-->
|
||||
<hr class="my-4" />
|
||||
{% endfor %}
|
||||
|
||||
{% if data.number %}
|
||||
<div class="pagination container row justify-content-end">
|
||||
<div></div>
|
||||
<div class="step-links col-auto">
|
||||
{% if urls.has_previous %}
|
||||
{% if data.has_previous %}
|
||||
<a href="?page=1">«</a>
|
||||
<a href="?page={{ urls.previous_page_number }}">‹</a>
|
||||
<a href="?page={{ data.previous_page_number }}">‹</a>
|
||||
{% endif %}
|
||||
|
||||
<span class="current">
|
||||
страница {{ urls.number }} из {{ urls.paginator.num_pages }}
|
||||
страница {{ data.number }} из {{ data.paginator.num_pages }}
|
||||
</span>
|
||||
|
||||
{% if urls.has_next %}
|
||||
<a href="?page={{ urls.next_page_number }}">›</a>
|
||||
<a href="?page={{ urls.paginator.num_pages }}">»</a>
|
||||
{% if data.has_next %}
|
||||
<a href="?page={{ data.next_page_number }}">›</a>
|
||||
<a href="?page={{ data.paginator.num_pages }}">»</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<h2 class="post-title">У вас нет ссылок в архиве</h2>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
@ -57,6 +57,7 @@
|
||||
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{% url 'about' %}">О нас</a></li>
|
||||
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{% url 'profile' %}">Профиль</a></li>
|
||||
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{% url 'archive' %}">Архив</a></li>
|
||||
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{% url 'search' %}">Поиск</a></li>
|
||||
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{% url 'logout' %}">Выйти</a></li>
|
||||
{% else %}
|
||||
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{% url 'signup' %}">Регистрация</a></li>
|
||||
|
@ -1,27 +1,27 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
{% if user.is_authenticated and urls|length > 0 %}
|
||||
{% for url in urls %}
|
||||
{% if user.is_authenticated and data|length > 0 %}
|
||||
{% for d in data %}
|
||||
<!-- Post preview-->
|
||||
<div class="post-preview">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="p-2">
|
||||
<a href="{% url 'reader' url.id %}">
|
||||
<h2 class="post-title">{{ url.title }}</h2>
|
||||
<a href="{% url 'reader' d.url_id %}">
|
||||
<h2 class="post-title">{% if d.title %}{{ d.title }}{% else %}Без заголовка{% endif %}</h2>
|
||||
</a>
|
||||
</div>
|
||||
<div class="p-2">
|
||||
<a href="{% url 'archive_url' url.id %}"><span class="fa-regular fa-square-check"></span></a>
|
||||
<a href="{% url 'archive_url' d.url_id %}"><span class="fa-regular fa-square-check"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
{% if url.content %}
|
||||
{% if d.short %}
|
||||
<p class="post-meta">
|
||||
{{ url.content }}
|
||||
{{ d.short }}
|
||||
</p>
|
||||
{% endif %}
|
||||
<p class="post-meta">
|
||||
{{ url.url|urlizetrunc:70 }}
|
||||
{{ d.url.url|urlizetrunc:70 }}
|
||||
</p>
|
||||
</div>
|
||||
<!-- Divider-->
|
||||
|
58
later42/templates/search.html
Normal file
58
later42/templates/search.html
Normal file
@ -0,0 +1,58 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Поиск{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<form action="{% url 'search' %}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="text" name="search" placeholder="Что ищем?">
|
||||
<input type="submit" value="Искать" />
|
||||
</form>
|
||||
<br />
|
||||
{% for d in data %}
|
||||
<!-- Post preview-->
|
||||
<div class="post-preview">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="p-2">
|
||||
<a href="{% url 'reader' d.url.id %}">
|
||||
<h2 class="post-title">{{ d.title }}</h2>
|
||||
</a>
|
||||
</div>
|
||||
<div class="p-2">
|
||||
<a href="{% url 'archive_url' d.url.id %}"><span class="fa-regular fa-square-check"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
{% if d.short %}
|
||||
<p class="post-meta">
|
||||
{{ d.short }}
|
||||
</p>
|
||||
{% endif %}
|
||||
<p class="post-meta">
|
||||
{{ d.url.url|urlizetrunc:70 }}
|
||||
</p>
|
||||
</div>
|
||||
<!-- Divider-->
|
||||
<hr class="my-4" />
|
||||
{% endfor %}
|
||||
{% if data.number %}
|
||||
<div class="pagination container row justify-content-end">
|
||||
<div></div>
|
||||
<div class="step-links col-auto">
|
||||
{% if data.has_previous %}
|
||||
<a href="?page=1">«</a>
|
||||
<a href="?page={{ data.previous_page_number }}">‹</a>
|
||||
{% endif %}
|
||||
|
||||
<span class="current">
|
||||
страница {{ data.number }} из {{ data.paginator.num_pages }}
|
||||
</span>
|
||||
|
||||
{% if data.has_next %}
|
||||
<a href="?page={{ data.next_page_number }}">›</a>
|
||||
<a href="?page={{ data.paginator.num_pages }}">»</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
@ -22,7 +22,7 @@ from django.contrib.auth.models import User
|
||||
from rest_framework import routers, serializers, viewsets
|
||||
|
||||
# from later42.forms import CustomLoginForm
|
||||
from later42.views import account_activation, index, profile, api, api_token, reader, signup, about
|
||||
from later42.views import account_activation, index, profile, api, api_token, reader, search, signup, about
|
||||
|
||||
|
||||
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
||||
@ -54,4 +54,5 @@ urlpatterns = [
|
||||
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'),
|
||||
]
|
||||
|
@ -8,26 +8,8 @@ from django.conf import settings
|
||||
|
||||
class URL(APIView):
|
||||
def post(self, request, format=None):
|
||||
url = request.GET.get('url')
|
||||
if url:
|
||||
page = get_content(url)
|
||||
|
||||
try:
|
||||
title = page['title']
|
||||
except KeyError:
|
||||
title = ''
|
||||
|
||||
content = None
|
||||
if settings.READABILITY_HOST:
|
||||
try:
|
||||
content = page['excerpt']
|
||||
except KeyError:
|
||||
content = ''
|
||||
|
||||
url = URLModel(url=url, user=request.user,
|
||||
title=title, content=content)
|
||||
url.save()
|
||||
get_url_content_task.delay(url.id)
|
||||
if 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'})
|
||||
|
@ -3,16 +3,20 @@ 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 later42.models.article import Article
|
||||
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')
|
||||
except:
|
||||
urls = []
|
||||
context = {'urls': urls}
|
||||
context = {'data': data}
|
||||
return render(request, 'index.html', context)
|
||||
|
||||
|
||||
@ -24,12 +28,13 @@ def archive(request, url_id=None):
|
||||
try:
|
||||
urls = URL.objects.filter(
|
||||
user=request.user, archived=True).order_by('-id')
|
||||
paginator = Paginator(urls, settings.URLS_PER_PAGE)
|
||||
data = Article.objects.filter(url__in=urls).select_related('url')
|
||||
paginator = Paginator(data, settings.URLS_PER_PAGE)
|
||||
page_number = request.GET.get('page')
|
||||
urls = paginator.get_page(page_number)
|
||||
data = paginator.get_page(page_number)
|
||||
except:
|
||||
urls = []
|
||||
context = {'urls': urls}
|
||||
context = {'data': data}
|
||||
return render(request, 'archive.html', context)
|
||||
|
||||
|
||||
|
@ -6,16 +6,13 @@ from django.conf import settings
|
||||
from later42.libs.content import get_content, sanitize_img_size
|
||||
from later42.models.article import Article
|
||||
from later42.models.urls import URL
|
||||
from later42.tasks import get_url_content_task
|
||||
|
||||
|
||||
@login_required
|
||||
def get(request, url_id=None):
|
||||
url = URL.objects.get(
|
||||
user=request.user, id=url_id)
|
||||
|
||||
content = {}
|
||||
|
||||
try:
|
||||
article = Article.objects.get(url=url)
|
||||
content['rich_content'] = article.content
|
||||
@ -24,6 +21,5 @@ def get(request, url_id=None):
|
||||
content['rich_content'] = sanitize_img_size(content['rich_content'])
|
||||
except:
|
||||
content = get_content(url.url)
|
||||
get_url_content_task.delay(url.id)
|
||||
context = {'url': url, 'content': content}
|
||||
return render(request, 'reader.html', context)
|
||||
|
29
later42/views/search.py
Normal file
29
later42/views/search.py
Normal file
@ -0,0 +1,29 @@
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.paginator import Paginator
|
||||
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')
|
||||
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')
|
||||
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')
|
||||
paginator = Paginator(data, settings.URLS_PER_PAGE)
|
||||
page_number = request.GET.get('page')
|
||||
data = paginator.get_page(page_number)
|
||||
context = {'data': data}
|
||||
return render(request, 'search.html', context)
|
Loading…
Reference in New Issue
Block a user