mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-08-03 18:54:40 -05:00
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
88f9fb6fc8 | ||
![]() |
855e9f6c83 | ||
![]() |
e63e9e389e | ||
![]() |
c646cd4977 | ||
![]() |
6b53c0dc27 | ||
![]() |
afb4e317f0 | ||
![]() |
a698c69b4d | ||
![]() |
4121876116 | ||
![]() |
060d3011f7 | ||
![]() |
1f0fea2937 | ||
![]() |
92e178cc59 | ||
![]() |
dc222cefd4 | ||
![]() |
0defa9d0ba | ||
![]() |
e3edb02090 | ||
![]() |
a32625ca04 | ||
![]() |
3c08fa9b33 | ||
![]() |
e6526d3fd4 | ||
![]() |
bee0867a2a | ||
![]() |
1711030cb5 | ||
![]() |
7b586e6857 |
@@ -1,6 +1,20 @@
|
||||
Changelog
|
||||
#########
|
||||
|
||||
* 0.3.4
|
||||
* BasicAuth support for document and thumbnail downloads, as well as the Push
|
||||
API thanks to @thomasbrueggemann. See `#179`_.
|
||||
|
||||
* 0.3.3
|
||||
* Thumbnails in the UI and a Django-suit -based face-lift courtesy of @ekw!
|
||||
* Timezone, items per page, and default language are now all configurable,
|
||||
also thanks to @ekw.
|
||||
|
||||
* 0.3.2
|
||||
* Fix for `#172`_: defaulting ALLOWED_HOSTS to ``["*"]`` and allowing the
|
||||
user to set her own value via ``PAPERLESS_ALLOWED_HOSTS`` should the need
|
||||
arise.
|
||||
|
||||
* 0.3.1
|
||||
* Added a default value for ``CONVERT_BINARY``
|
||||
|
||||
@@ -152,3 +166,5 @@ Changelog
|
||||
.. _#146: https://github.com/danielquinn/paperless/issues/146
|
||||
.. _#148: https://github.com/danielquinn/paperless/pull/148
|
||||
.. _#150: https://github.com/danielquinn/paperless/pull/150
|
||||
.. _#172: https://github.com/danielquinn/paperless/issues/172
|
||||
.. _#179: https://github.com/danielquinn/paperless/pull/179
|
||||
|
@@ -92,3 +92,23 @@ PAPERLESS_SHARED_SECRET=""
|
||||
# PAPERLESS_CONSUMPTION_DIR. If you tend to write documents to this directory
|
||||
# very slowly, you may want to use a higher value than the default (10).
|
||||
# PAPERLESS_CONSUMER_LOOP_TIME=10
|
||||
|
||||
# If you're planning on putting Paperless on the open internet, then you
|
||||
# really should set this value to the domain name you're using. Failing to do
|
||||
# so leaves you open to HTTP host header attacks:
|
||||
# https://docs.djangoproject.com/en/1.10/topics/security/#host-headers-virtual-hosting
|
||||
#
|
||||
# Just remember that this is a comma-separated list, so "example.com" is fine,
|
||||
# as is "example.com,www.example.com", but NOT " example.com" or "example.com,"
|
||||
#PAPERLESS_ALLOWED_HOSTS="example.com,www.example.com"
|
||||
|
||||
# Override the default UTC time zone here
|
||||
#PAPERLESS_TIME_ZONE=UTC
|
||||
|
||||
# Customize number of list items to show per page
|
||||
#PAPERLESS_LIST_PER_PAGE=50
|
||||
|
||||
# Customize the default language that tesseract will attempt to use when parsing
|
||||
# documents. It should be a 3-letter language code consistent with ISO 639.
|
||||
#PAPERLESS_OCR_LANGUAGE=eng
|
||||
|
||||
|
@@ -53,13 +53,24 @@ class DocumentAdmin(admin.ModelAdmin):
|
||||
}
|
||||
|
||||
search_fields = ("correspondent__name", "title", "content")
|
||||
list_display = ("created", "correspondent", "title", "tags_", "document")
|
||||
list_display = ("created", "title", "thumbnail", "correspondent", "tags_")
|
||||
list_filter = ("tags", "correspondent", MonthListFilter)
|
||||
list_per_page = 25
|
||||
ordering = ["-created", "correspondent"]
|
||||
|
||||
def created_(self, obj):
|
||||
return obj.created.date().strftime("%Y-%m-%d")
|
||||
|
||||
def thumbnail(self, obj):
|
||||
png_img = self._html_tag(
|
||||
"img",
|
||||
src="/fetch/thumb/{}".format(obj.id),
|
||||
width=180,
|
||||
alt="thumbnail",
|
||||
title=obj.file_name
|
||||
)
|
||||
return self._html_tag("a", png_img, href=obj.download_url)
|
||||
thumbnail.allow_tags = True
|
||||
|
||||
def tags_(self, obj):
|
||||
r = ""
|
||||
for tag in obj.tags.all():
|
||||
|
@@ -1,3 +1,8 @@
|
||||
from django.contrib.auth.mixins import AccessMixin
|
||||
from django.contrib.auth import authenticate, login
|
||||
import base64
|
||||
|
||||
|
||||
class Renderable(object):
|
||||
"""
|
||||
A handy mixin to make it easier/cleaner to print output based on a
|
||||
@@ -7,3 +12,46 @@ class Renderable(object):
|
||||
def _render(self, text, verbosity):
|
||||
if self.verbosity >= verbosity:
|
||||
print(text)
|
||||
|
||||
|
||||
class SessionOrBasicAuthMixin(AccessMixin):
|
||||
"""
|
||||
Session or Basic Authentication mixin for Django.
|
||||
It determines if the requester is already logged in or if they have
|
||||
provided proper http-authorization and returning the view if all goes
|
||||
well, otherwise responding with a 401.
|
||||
|
||||
Base for mixin found here: https://djangosnippets.org/snippets/3073/
|
||||
"""
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
|
||||
# check if user is authenticated via the session
|
||||
if request.user.is_authenticated:
|
||||
|
||||
# Already logged in, just return the view.
|
||||
return super(SessionOrBasicAuthMixin, self).dispatch(
|
||||
request, *args, **kwargs
|
||||
)
|
||||
|
||||
# apparently not authenticated via session, maybe via HTTP Basic?
|
||||
if 'HTTP_AUTHORIZATION' in request.META:
|
||||
auth = request.META['HTTP_AUTHORIZATION'].split()
|
||||
if len(auth) == 2:
|
||||
# NOTE: Support for only basic authentication
|
||||
if auth[0].lower() == "basic":
|
||||
authString = base64.b64decode(auth[1]).decode('utf-8')
|
||||
uname, passwd = authString.split(':')
|
||||
user = authenticate(username=uname, password=passwd)
|
||||
if user is not None:
|
||||
if user.is_active:
|
||||
login(request, user)
|
||||
request.user = user
|
||||
return super(
|
||||
SessionOrBasicAuthMixin, self
|
||||
).dispatch(
|
||||
request, *args, **kwargs
|
||||
)
|
||||
|
||||
# nope, really not authenticated
|
||||
return self.handle_no_permission()
|
||||
|
@@ -1,4 +1,3 @@
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.http import HttpResponse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic import DetailView, FormView, TemplateView
|
||||
@@ -28,6 +27,7 @@ from .serialisers import (
|
||||
LogSerializer,
|
||||
TagSerializer
|
||||
)
|
||||
from .mixins import SessionOrBasicAuthMixin
|
||||
|
||||
|
||||
class IndexView(TemplateView):
|
||||
@@ -41,7 +41,7 @@ class IndexView(TemplateView):
|
||||
return TemplateView.get_context_data(self, **kwargs)
|
||||
|
||||
|
||||
class FetchView(LoginRequiredMixin, DetailView):
|
||||
class FetchView(SessionOrBasicAuthMixin, DetailView):
|
||||
|
||||
model = Document
|
||||
|
||||
@@ -74,7 +74,7 @@ class FetchView(LoginRequiredMixin, DetailView):
|
||||
return response
|
||||
|
||||
|
||||
class PushView(LoginRequiredMixin, FormView):
|
||||
class PushView(SessionOrBasicAuthMixin, FormView):
|
||||
"""
|
||||
A crude REST-ish API for creating documents.
|
||||
"""
|
||||
|
@@ -29,7 +29,11 @@ DEBUG = True
|
||||
|
||||
LOGIN_URL = '/admin/login'
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
|
||||
_allowed_hosts = os.getenv("PAPERLESS_ALLOWED_HOSTS")
|
||||
if _allowed_hosts:
|
||||
ALLOWED_HOSTS = _allowed_hosts.split(",")
|
||||
|
||||
# Tap paperless.conf if it's available
|
||||
if os.path.exists("/etc/paperless.conf"):
|
||||
@@ -137,7 +141,7 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
TIME_ZONE = os.getenv("PAPERLESS_TIME_ZONE", "UTC")
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
@@ -183,7 +187,7 @@ LOGGING = {
|
||||
|
||||
# The default language that tesseract will attempt to use when parsing
|
||||
# documents. It should be a 3-letter language code consistent with ISO 639.
|
||||
OCR_LANGUAGE = "eng"
|
||||
OCR_LANGUAGE = os.getenv("PAPERLESS_OCR_LANGUAGE", "eng")
|
||||
|
||||
# The amount of threads to use for OCR
|
||||
OCR_THREADS = os.getenv("PAPERLESS_OCR_THREADS")
|
||||
|
@@ -1 +1 @@
|
||||
__version__ = (0, 3, 1)
|
||||
__version__ = (0, 3, 4)
|
||||
|
Reference in New Issue
Block a user