2019-05-01 03:13:21 +00:00
|
|
|
__package__ = 'archivebox.core'
|
2019-04-02 20:36:41 +00:00
|
|
|
|
2020-08-25 18:15:42 +00:00
|
|
|
from io import StringIO
|
|
|
|
from contextlib import redirect_stdout
|
|
|
|
|
2019-05-01 03:13:21 +00:00
|
|
|
from django.shortcuts import render, redirect
|
2019-04-17 09:42:21 +00:00
|
|
|
|
2019-05-01 03:13:21 +00:00
|
|
|
from django.http import HttpResponse
|
|
|
|
from django.views import View, static
|
2020-08-20 14:04:34 +00:00
|
|
|
from django.views.generic.list import ListView
|
2020-08-28 14:58:32 +00:00
|
|
|
from django.views.generic import FormView
|
|
|
|
from django.contrib.auth.mixins import UserPassesTestMixin
|
2020-08-20 20:43:28 +00:00
|
|
|
|
2019-05-01 03:44:51 +00:00
|
|
|
from core.models import Snapshot
|
2020-08-25 18:15:42 +00:00
|
|
|
from core.forms import AddLinkForm
|
|
|
|
|
2019-05-02 23:15:16 +00:00
|
|
|
from ..config import (
|
|
|
|
OUTPUT_DIR,
|
|
|
|
PUBLIC_INDEX,
|
|
|
|
PUBLIC_SNAPSHOTS,
|
2020-11-28 06:29:34 +00:00
|
|
|
PUBLIC_ADD_VIEW,
|
|
|
|
VERSION,
|
|
|
|
FOOTER_INFO,
|
2019-05-02 23:15:16 +00:00
|
|
|
)
|
2020-08-25 18:15:42 +00:00
|
|
|
from main import add
|
|
|
|
from ..util import base_url, ansi_to_html
|
2020-11-28 07:12:27 +00:00
|
|
|
from ..index.html import snapshot_icons
|
2020-07-02 20:54:25 +00:00
|
|
|
|
2019-04-17 09:42:21 +00:00
|
|
|
|
|
|
|
class MainIndex(View):
|
|
|
|
template = 'main_index.html'
|
|
|
|
|
|
|
|
def get(self, request):
|
2020-07-28 03:56:35 +00:00
|
|
|
if request.user.is_authenticated:
|
|
|
|
return redirect('/admin/core/snapshot/')
|
|
|
|
|
|
|
|
if PUBLIC_INDEX:
|
2020-08-27 01:44:06 +00:00
|
|
|
return redirect('public-index')
|
2020-07-28 03:56:35 +00:00
|
|
|
|
|
|
|
return redirect(f'/admin/login/?next={request.path}')
|
|
|
|
|
2019-04-22 23:08:01 +00:00
|
|
|
|
2019-04-17 09:42:21 +00:00
|
|
|
class LinkDetails(View):
|
2019-05-01 03:13:21 +00:00
|
|
|
def get(self, request, path):
|
|
|
|
# missing trailing slash -> redirect to index
|
|
|
|
if '/' not in path:
|
|
|
|
return redirect(f'{path}/index.html')
|
|
|
|
|
2019-05-02 23:15:16 +00:00
|
|
|
if not request.user.is_authenticated and not PUBLIC_SNAPSHOTS:
|
|
|
|
return redirect(f'/admin/login/?next={request.path}')
|
|
|
|
|
2019-05-01 03:13:21 +00:00
|
|
|
try:
|
|
|
|
slug, archivefile = path.split('/', 1)
|
|
|
|
except (IndexError, ValueError):
|
|
|
|
slug, archivefile = path.split('/', 1)[0], 'index.html'
|
|
|
|
|
2019-05-01 03:44:51 +00:00
|
|
|
all_pages = list(Snapshot.objects.all())
|
2019-05-01 03:13:21 +00:00
|
|
|
|
|
|
|
# slug is a timestamp
|
|
|
|
by_ts = {page.timestamp: page for page in all_pages}
|
|
|
|
try:
|
2020-07-28 09:53:26 +00:00
|
|
|
# print('SERVING STATICFILE', by_ts[slug].link_dir, request.path, path)
|
|
|
|
response = static.serve(request, archivefile, document_root=by_ts[slug].link_dir, show_indexes=True)
|
2020-07-16 17:43:22 +00:00
|
|
|
response["Link"] = f'<{by_ts[slug].url}>; rel="canonical"'
|
|
|
|
return response
|
2019-05-01 03:13:21 +00:00
|
|
|
except KeyError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
# slug is a hash
|
|
|
|
by_hash = {page.url_hash: page for page in all_pages}
|
|
|
|
try:
|
|
|
|
timestamp = by_hash[slug].timestamp
|
|
|
|
return redirect(f'/archive/{timestamp}/{archivefile}')
|
|
|
|
except KeyError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
# slug is a URL
|
|
|
|
by_url = {page.base_url: page for page in all_pages}
|
|
|
|
try:
|
|
|
|
# TODO: add multiple snapshot support by showing index of all snapshots
|
|
|
|
# for given url instead of redirecting to timestamp index
|
|
|
|
timestamp = by_url[base_url(path)].timestamp
|
|
|
|
return redirect(f'/archive/{timestamp}/index.html')
|
|
|
|
except KeyError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
return HttpResponse(
|
|
|
|
'No archived link matches the given timestamp or hash.',
|
|
|
|
content_type="text/plain",
|
|
|
|
status=404,
|
|
|
|
)
|
2020-08-20 14:04:34 +00:00
|
|
|
|
|
|
|
class PublicArchiveView(ListView):
|
|
|
|
template = 'snapshot_list.html'
|
|
|
|
model = Snapshot
|
2020-08-25 17:35:06 +00:00
|
|
|
paginate_by = 100
|
2020-12-01 15:46:11 +00:00
|
|
|
ordering = ['title']
|
2020-08-20 20:43:28 +00:00
|
|
|
|
2020-11-28 06:29:34 +00:00
|
|
|
def get_context_data(self, **kwargs):
|
|
|
|
return {
|
|
|
|
**super().get_context_data(**kwargs),
|
|
|
|
'VERSION': VERSION,
|
|
|
|
'FOOTER_INFO': FOOTER_INFO,
|
|
|
|
}
|
|
|
|
|
2020-08-25 17:50:31 +00:00
|
|
|
def get_queryset(self, **kwargs):
|
|
|
|
qs = super().get_queryset(**kwargs)
|
2020-08-25 19:31:09 +00:00
|
|
|
query = self.request.GET.get('q')
|
|
|
|
if query:
|
2020-12-01 15:46:11 +00:00
|
|
|
qs = qs.filter(title__icontains=query)
|
2020-08-20 20:43:28 +00:00
|
|
|
for snapshot in qs:
|
2020-11-28 07:12:27 +00:00
|
|
|
snapshot.icons = snapshot_icons(snapshot)
|
2020-08-20 20:43:28 +00:00
|
|
|
return qs
|
|
|
|
|
|
|
|
def get(self, *args, **kwargs):
|
|
|
|
if PUBLIC_INDEX or self.request.user.is_authenticated:
|
|
|
|
response = super().get(*args, **kwargs)
|
|
|
|
return response
|
|
|
|
else:
|
|
|
|
return redirect(f'/admin/login/?next={self.request.path}')
|
|
|
|
|
2020-08-25 18:15:42 +00:00
|
|
|
|
2020-08-28 14:58:32 +00:00
|
|
|
class AddView(UserPassesTestMixin, FormView):
|
|
|
|
template_name = "add_links.html"
|
|
|
|
form_class = AddLinkForm
|
|
|
|
|
2020-10-03 19:57:55 +00:00
|
|
|
def get_initial(self):
|
|
|
|
"""Prefill the AddLinkForm with the 'url' GET parameter"""
|
|
|
|
if self.request.method == 'GET':
|
|
|
|
url = self.request.GET.get('url', None)
|
|
|
|
if url:
|
|
|
|
return {'url': url}
|
|
|
|
else:
|
|
|
|
return super().get_initial()
|
|
|
|
|
2020-08-28 14:58:32 +00:00
|
|
|
def test_func(self):
|
|
|
|
return PUBLIC_ADD_VIEW or self.request.user.is_authenticated
|
|
|
|
|
2020-11-28 07:01:53 +00:00
|
|
|
def get_context_data(self, **kwargs):
|
|
|
|
return {
|
|
|
|
**super().get_context_data(**kwargs),
|
|
|
|
'title': "Add URLs",
|
|
|
|
# We can't just call request.build_absolute_uri in the template, because it would include query parameters
|
|
|
|
'absolute_add_path': self.request.build_absolute_uri(self.request.path),
|
|
|
|
'VERSION': VERSION,
|
|
|
|
'FOOTER_INFO': FOOTER_INFO,
|
|
|
|
}
|
2020-08-28 14:58:32 +00:00
|
|
|
|
|
|
|
def form_valid(self, form):
|
|
|
|
url = form.cleaned_data["url"]
|
|
|
|
print(f'[+] Adding URL: {url}')
|
|
|
|
depth = 0 if form.cleaned_data["depth"] == "0" else 1
|
2020-12-10 17:45:30 +00:00
|
|
|
extractors = ','.join(form.cleaned_data["archive_methods"])
|
2020-08-28 14:58:32 +00:00
|
|
|
input_kwargs = {
|
|
|
|
"urls": url,
|
|
|
|
"depth": depth,
|
|
|
|
"update_all": False,
|
|
|
|
"out_dir": OUTPUT_DIR,
|
|
|
|
}
|
2020-12-10 15:51:57 +00:00
|
|
|
if extractors:
|
2020-12-10 16:08:27 +00:00
|
|
|
input_kwargs.update({"extractors": extractors})
|
2020-08-28 14:58:32 +00:00
|
|
|
add_stdout = StringIO()
|
|
|
|
with redirect_stdout(add_stdout):
|
|
|
|
add(**input_kwargs)
|
|
|
|
print(add_stdout.getvalue())
|
|
|
|
|
|
|
|
context = self.get_context_data()
|
|
|
|
|
|
|
|
context.update({
|
|
|
|
"stdout": ansi_to_html(add_stdout.getvalue().strip()),
|
|
|
|
"form": AddLinkForm()
|
|
|
|
})
|
2020-08-28 15:06:48 +00:00
|
|
|
return render(template_name=self.template_name, request=self.request, context=context)
|