Fix critical bugs in app_urls
- init_db.py: parameterize SQL queries to prevent SQL injection - scheduled_tasks.json: resolve duplicate periodic task pk (4 -> 15) - db_utils.py: use function parameter in _get_status_pattern_matching instead of capturing the enclosing scope variable - url_detail.html: fix wrong field name image_urls -> images_url - settings.py: align Celery queues (default/light/heavy) with the task queues and supervisord workers - Add /task/publish_<id>/ route to fix broken publish links in templates
This commit is contained in:
@@ -123,7 +123,8 @@ CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers.DatabaseScheduler'
|
|||||||
|
|
||||||
CELERY_TASK_QUEUES = (
|
CELERY_TASK_QUEUES = (
|
||||||
Queue('default'),
|
Queue('default'),
|
||||||
Queue('low'),
|
Queue('light'),
|
||||||
|
Queue('heavy'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ class DB_Handler():
|
|||||||
# Sort pattern tuples by priority. (pattern, priority, status)
|
# Sort pattern tuples by priority. (pattern, priority, status)
|
||||||
for regex_pattern, regex_priority, status_if_match in sorted(list_pattern_status_tuple, key=lambda tup: tup[1], reverse=True):
|
for regex_pattern, regex_priority, status_if_match in sorted(list_pattern_status_tuple, key=lambda tup: tup[1], reverse=True):
|
||||||
# Regular expression pattern matching: https://regexr.com/
|
# Regular expression pattern matching: https://regexr.com/
|
||||||
if bool(re.match(regex_pattern, obj_url.url)):
|
if bool(re.match(regex_pattern, url)):
|
||||||
# logger.debug("Regex pattern found, status '{}' for URL: {}".format(status_if_match, url))
|
# logger.debug("Regex pattern found, status '{}' for URL: {}".format(status_if_match, url))
|
||||||
return status_if_match
|
return status_if_match
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -246,7 +246,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Image URLs</th>
|
<th>Image URLs</th>
|
||||||
<td>{{ url_content.image_urls|default:"" }}</td>
|
<td>{{ url_content.images_url|default:"" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Video URLs</th>
|
<th>Video URLs</th>
|
||||||
|
|||||||
@@ -17,4 +17,5 @@ urlpatterns = [
|
|||||||
#
|
#
|
||||||
path('urls/', views.filtered_urls, name='filtered_urls'),
|
path('urls/', views.filtered_urls, name='filtered_urls'),
|
||||||
path('urls/<int:id>/', views.url_detail_view, name='url_detail'),
|
path('urls/<int:id>/', views.url_detail_view, name='url_detail'),
|
||||||
|
path('task/publish_<int:id>/', views.publish, name='publish'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ from .views_base import link_list, logs, log_db #, trigger_task,
|
|||||||
|
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
from django.shortcuts import render, get_object_or_404
|
from django.shortcuts import render, get_object_or_404
|
||||||
from django.http import StreamingHttpResponse, JsonResponse
|
from django.http import StreamingHttpResponse, JsonResponse, HttpResponse
|
||||||
from django.db.models import Q, Count
|
from django.db.models import Q, Count
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.timezone import now, timedelta
|
from django.utils.timezone import now, timedelta
|
||||||
from .models import Urls, Source, Search, UrlContent, UrlsSourceSearch, UrlsDuplicate
|
from .models import Urls, Source, Search, UrlContent, UrlsSourceSearch, UrlsDuplicate
|
||||||
from .src.llm import OllamaClient
|
from .src.llm import OllamaClient
|
||||||
|
from .src.publisher import Publisher
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
|
||||||
@@ -62,6 +63,15 @@ def url_detail_view(request, id):
|
|||||||
}
|
}
|
||||||
return render(request, 'url_detail.html', context)
|
return render(request, 'url_detail.html', context)
|
||||||
|
|
||||||
|
def publish(request, id):
|
||||||
|
# Publish URL content to Ghost
|
||||||
|
try:
|
||||||
|
Publisher().publish(id)
|
||||||
|
message = "URL ID {} published".format(id)
|
||||||
|
except Exception as e:
|
||||||
|
message = "Error publishing URL ID {}: {}".format(id, str(e))
|
||||||
|
return HttpResponse(message)
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
def charts(request):
|
def charts(request):
|
||||||
return render(request, 'charts.html')
|
return render(request, 'charts.html')
|
||||||
|
|||||||
+7
-10
@@ -210,10 +210,9 @@ def initialize_data():
|
|||||||
for list_pattern_status_priority in data_json.get("REGEX_PATTERN_STATUS_PRIORITY", []):
|
for list_pattern_status_priority in data_json.get("REGEX_PATTERN_STATUS_PRIORITY", []):
|
||||||
# Decode
|
# Decode
|
||||||
pattern, status, priority = list_pattern_status_priority
|
pattern, status, priority = list_pattern_status_priority
|
||||||
# Query
|
# Query (parameterized to avoid SQL injection)
|
||||||
query = "INSERT INTO STATUS_PATTERN_MATCHING (pattern, priority, status) VALUES ('{}', {}, '{}');".format(pattern, priority, status)
|
query = "INSERT INTO STATUS_PATTERN_MATCHING (pattern, priority, status) VALUES (%s, %s, %s);"
|
||||||
print(query)
|
cur.execute(query, (pattern, priority, status))
|
||||||
cur.execute(query)
|
|
||||||
|
|
||||||
# Connect to an existing database
|
# Connect to an existing database
|
||||||
with psycopg.connect(connection_info) as conn:
|
with psycopg.connect(connection_info) as conn:
|
||||||
@@ -222,9 +221,8 @@ def initialize_data():
|
|||||||
# Feeds, URL host, keyword search
|
# Feeds, URL host, keyword search
|
||||||
for search_type, list_searches in data_json.get("SEARCH", {}).items():
|
for search_type, list_searches in data_json.get("SEARCH", {}).items():
|
||||||
for search in list_searches:
|
for search in list_searches:
|
||||||
query = "INSERT INTO SEARCH (search, type) VALUES ('{}', '{}');".format(search, search_type)
|
insert_search_sql = "INSERT INTO SEARCH (search, type) VALUES (%s, %s);"
|
||||||
print(query)
|
cur.execute(insert_search_sql, (search, search_type))
|
||||||
cur.execute(query)
|
|
||||||
|
|
||||||
# Try finding RSS feed
|
# Try finding RSS feed
|
||||||
if (search_type == "url_host"):
|
if (search_type == "url_host"):
|
||||||
@@ -232,9 +230,8 @@ def initialize_data():
|
|||||||
list_feeds = find_feeds(url_host)
|
list_feeds = find_feeds(url_host)
|
||||||
# If not exists, insert feed
|
# If not exists, insert feed
|
||||||
for feed in list_feeds:
|
for feed in list_feeds:
|
||||||
query = "INSERT INTO SEARCH (search, type) VALUES ('{}', '{}') ON CONFLICT DO NOTHING;".format(feed, "rss_feed")
|
insert_feed_sql = "INSERT INTO SEARCH (search, type) VALUES (%s, %s) ON CONFLICT DO NOTHING;"
|
||||||
print(query)
|
cur.execute(insert_feed_sql, (feed, "rss_feed"))
|
||||||
cur.execute(query)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -393,7 +393,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"model": "django_celery_beat.periodictask",
|
"model": "django_celery_beat.periodictask",
|
||||||
"pk": 4,
|
"pk": 15,
|
||||||
"fields": {
|
"fields": {
|
||||||
"name": "Notify status",
|
"name": "Notify status",
|
||||||
"task": "fetcher.tasks.notify_status",
|
"task": "fetcher.tasks.notify_status",
|
||||||
|
|||||||
Reference in New Issue
Block a user