DJANGO REWRITE // DJANGO REWRITE // DJANGO REWRITE
feature parity, except pdf labels
This commit is contained in:
parent
603005f683
commit
8d4010702a
59 changed files with 917 additions and 1873 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1,9 +1,6 @@
|
||||||
pile.db
|
db.sqlite3
|
||||||
docs
|
docs
|
||||||
dev
|
dev
|
||||||
|
|
||||||
_vendor
|
|
||||||
*.ttf
|
*.ttf
|
||||||
*.woff
|
*.woff
|
||||||
|
|
||||||
error_log
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
CREATE TABLE Documents (
|
|
||||||
ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
||||||
Title TEXT NOT NULL,
|
|
||||||
Description TEXT,
|
|
||||||
Author TEXT,
|
|
||||||
Published TEXT,
|
|
||||||
URL TEXT
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE DocumentsToTags (
|
|
||||||
Document INTEGER NOT NULL,
|
|
||||||
Tag INTEGER NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE Tags (
|
|
||||||
ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
||||||
Name TEXT NOT NULL,
|
|
||||||
Description TEXT,
|
|
||||||
Parent INTEGER
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE Users (
|
|
||||||
ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
||||||
Username TEXT NOT NULL,
|
|
||||||
Password TEXT NOT NULL
|
|
||||||
);
|
|
|
@ -1 +0,0 @@
|
||||||
ALTER TABLE Documents ADD UploadedTime INTEGER;
|
|
|
@ -1,21 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
|
||||||
|
|
||||||
if [ -z "$1" ]; then
|
|
||||||
echo "Please specify database file."
|
|
||||||
exit -1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! which sqlite3; then
|
|
||||||
echo "Couldn't find \`sqlite3\` in \$PATH!"
|
|
||||||
exit -1
|
|
||||||
fi
|
|
||||||
|
|
||||||
set -e
|
|
||||||
FILES=$(ls ${DIR}/*.sql|sort)
|
|
||||||
for sql_file in $FILES;do
|
|
||||||
echo "Processing \"${sql_file}\"..."
|
|
||||||
sqlite3 -echo "$1" < "$sql_file"
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Done."
|
|
|
@ -1,21 +0,0 @@
|
||||||
FROM php:7.2-apache
|
|
||||||
|
|
||||||
COPY www/ /var/www/html/
|
|
||||||
RUN rm -f /var/www/html/pile.db
|
|
||||||
COPY opt/ /opt/pile
|
|
||||||
RUN mkdir -p /var/tmp/pile
|
|
||||||
COPY db_versions/ /var/tmp/pile/db_versions
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get -y install sqlite3 wget \
|
|
||||||
libfreetype6-dev \
|
|
||||||
libjpeg62-turbo-dev \
|
|
||||||
libpng-dev
|
|
||||||
|
|
||||||
RUN docker-php-ext-install -j$(nproc) iconv \
|
|
||||||
&& docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
|
|
||||||
&& docker-php-ext-install -j$(nproc) gd
|
|
||||||
|
|
||||||
RUN cd /opt/pile/ && /opt/pile/install_composer.sh
|
|
||||||
RUN cd /var/www/html && /opt/pile/composer.phar install
|
|
||||||
|
|
||||||
RUN /var/tmp/pile/db_versions/apply_all.sh /var/www/html/pile.db
|
|
|
@ -1,11 +0,0 @@
|
||||||
version: '3'
|
|
||||||
|
|
||||||
services:
|
|
||||||
pile:
|
|
||||||
build:
|
|
||||||
context: ../
|
|
||||||
dockerfile: ./docker/Dockerfile
|
|
||||||
ports:
|
|
||||||
- "8080:80"
|
|
||||||
volumes:
|
|
||||||
- ../www:/var/www/html
|
|
21
manage.py
Executable file
21
manage.py
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
"""Django's command-line utility for administrative tasks."""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sdbs_pile.settings')
|
||||||
|
try:
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
except ImportError as exc:
|
||||||
|
raise ImportError(
|
||||||
|
"Couldn't import Django. Are you sure it's installed and "
|
||||||
|
"available on your PYTHONPATH environment variable? Did you "
|
||||||
|
"forget to activate a virtual environment?"
|
||||||
|
) from exc
|
||||||
|
execute_from_command_line(sys.argv)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
|
@ -1,17 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
EXPECTED_SIGNATURE="$(wget -q -O - https://composer.github.io/installer.sig)"
|
|
||||||
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
|
||||||
ACTUAL_SIGNATURE="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
|
|
||||||
|
|
||||||
if [ "$EXPECTED_SIGNATURE" != "$ACTUAL_SIGNATURE" ]
|
|
||||||
then
|
|
||||||
>&2 echo 'ERROR: Invalid installer signature'
|
|
||||||
rm composer-setup.php
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
php composer-setup.php --quiet
|
|
||||||
RESULT=$?
|
|
||||||
rm composer-setup.php
|
|
||||||
exit $RESULT
|
|
324
poetry.lock
generated
Normal file
324
poetry.lock
generated
Normal file
|
@ -0,0 +1,324 @@
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Disable App Nap on OS X 10.9"
|
||||||
|
marker = "sys_platform == \"darwin\""
|
||||||
|
name = "appnope"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "ASGI specs, helper code, and adapters"
|
||||||
|
name = "asgiref"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5"
|
||||||
|
version = "3.2.5"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
tests = ["pytest (>=4.3.0,<4.4.0)", "pytest-asyncio (>=0.10.0,<0.11.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Specifications for callback functions passed in to an API"
|
||||||
|
name = "backcall"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Cross-platform colored terminal text."
|
||||||
|
marker = "sys_platform == \"win32\""
|
||||||
|
name = "colorama"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
version = "0.4.3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Decorators for Humans"
|
||||||
|
name = "decorator"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.6, !=3.0.*, !=3.1.*"
|
||||||
|
version = "4.4.2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
|
||||||
|
name = "django"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
version = "3.0.4"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
asgiref = ">=3.2,<4.0"
|
||||||
|
pytz = "*"
|
||||||
|
sqlparse = ">=0.2.2"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
argon2 = ["argon2-cffi (>=16.1.0)"]
|
||||||
|
bcrypt = ["bcrypt"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Django model mixins and utilities"
|
||||||
|
name = "django-model-utils"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "4.0.0"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
Django = ">=2.0.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "IPython: Productive Interactive Computing"
|
||||||
|
name = "ipython"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
version = "7.13.0"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
appnope = "*"
|
||||||
|
backcall = "*"
|
||||||
|
colorama = "*"
|
||||||
|
decorator = "*"
|
||||||
|
jedi = ">=0.10"
|
||||||
|
pexpect = "*"
|
||||||
|
pickleshare = "*"
|
||||||
|
prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0"
|
||||||
|
pygments = "*"
|
||||||
|
setuptools = ">=18.5"
|
||||||
|
traitlets = ">=4.2"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
all = ["numpy (>=1.14)", "testpath", "notebook", "nose (>=0.10.1)", "nbconvert", "requests", "ipywidgets", "qtconsole", "ipyparallel", "Sphinx (>=1.3)", "pygments", "nbformat", "ipykernel"]
|
||||||
|
doc = ["Sphinx (>=1.3)"]
|
||||||
|
kernel = ["ipykernel"]
|
||||||
|
nbconvert = ["nbconvert"]
|
||||||
|
nbformat = ["nbformat"]
|
||||||
|
notebook = ["notebook", "ipywidgets"]
|
||||||
|
parallel = ["ipyparallel"]
|
||||||
|
qtconsole = ["qtconsole"]
|
||||||
|
test = ["nose (>=0.10.1)", "requests", "testpath", "pygments", "nbformat", "ipykernel", "numpy (>=1.14)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Vestigial utilities from IPython"
|
||||||
|
name = "ipython-genutils"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "0.2.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "An autocompletion tool for Python that can be used for text editors."
|
||||||
|
name = "jedi"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
version = "0.16.0"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
parso = ">=0.5.2"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
qa = ["flake8 (3.7.9)"]
|
||||||
|
testing = ["colorama (0.4.1)", "docopt", "pytest (>=3.9.0,<5.0.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "A Python Parser"
|
||||||
|
name = "parso"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
version = "0.6.2"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
testing = ["docopt", "pytest (>=3.0.7)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Pexpect allows easy control of interactive console applications."
|
||||||
|
marker = "sys_platform != \"win32\""
|
||||||
|
name = "pexpect"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "4.8.0"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
ptyprocess = ">=0.5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Tiny 'shelve'-like database with concurrency support"
|
||||||
|
name = "pickleshare"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "0.7.5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Library for building powerful interactive command lines in Python"
|
||||||
|
name = "prompt-toolkit"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6.1"
|
||||||
|
version = "3.0.4"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
wcwidth = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Run a subprocess in a pseudo terminal"
|
||||||
|
marker = "sys_platform != \"win32\""
|
||||||
|
name = "ptyprocess"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "0.6.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Pygments is a syntax highlighting package written in Python."
|
||||||
|
name = "pygments"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5"
|
||||||
|
version = "2.6.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "World timezone definitions, modern and historical"
|
||||||
|
name = "pytz"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "2019.3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Python 2 and 3 compatibility utilities"
|
||||||
|
name = "six"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||||
|
version = "1.14.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Non-validating SQL parser"
|
||||||
|
name = "sqlparse"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
version = "0.3.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Traitlets Python config system"
|
||||||
|
name = "traitlets"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "4.3.3"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
decorator = "*"
|
||||||
|
ipython-genutils = "*"
|
||||||
|
six = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
test = ["pytest", "mock"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Measures number of Terminal column cells of wide-character codes"
|
||||||
|
name = "wcwidth"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "0.1.8"
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
content-hash = "29f69026d536c0781f6a7eb9b4f1221a083dcc7cd39e8dce9975de116abfafe2"
|
||||||
|
python-versions = "^3.8"
|
||||||
|
|
||||||
|
[metadata.files]
|
||||||
|
appnope = [
|
||||||
|
{file = "appnope-0.1.0-py2.py3-none-any.whl", hash = "sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0"},
|
||||||
|
{file = "appnope-0.1.0.tar.gz", hash = "sha256:8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71"},
|
||||||
|
]
|
||||||
|
asgiref = [
|
||||||
|
{file = "asgiref-3.2.5-py2.py3-none-any.whl", hash = "sha256:3e4192eaec0758b99722f0b0666d5fbfaa713054d92e8de5b58ba84ec5ce696f"},
|
||||||
|
{file = "asgiref-3.2.5.tar.gz", hash = "sha256:c8f49dd3b42edcc51d09dd2eea8a92b3cfc987ff7e6486be734b4d0cbfd5d315"},
|
||||||
|
]
|
||||||
|
backcall = [
|
||||||
|
{file = "backcall-0.1.0.tar.gz", hash = "sha256:38ecd85be2c1e78f77fd91700c76e14667dc21e2713b63876c0eb901196e01e4"},
|
||||||
|
{file = "backcall-0.1.0.zip", hash = "sha256:bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2"},
|
||||||
|
]
|
||||||
|
colorama = [
|
||||||
|
{file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
|
||||||
|
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
|
||||||
|
]
|
||||||
|
decorator = [
|
||||||
|
{file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"},
|
||||||
|
{file = "decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"},
|
||||||
|
]
|
||||||
|
django = [
|
||||||
|
{file = "Django-3.0.4-py3-none-any.whl", hash = "sha256:89e451bfbb815280b137e33e454ddd56481fdaa6334054e6e031041ee1eda360"},
|
||||||
|
{file = "Django-3.0.4.tar.gz", hash = "sha256:50b781f6cbeb98f673aa76ed8e572a019a45e52bdd4ad09001072dfd91ab07c8"},
|
||||||
|
]
|
||||||
|
django-model-utils = [
|
||||||
|
{file = "django-model-utils-4.0.0.tar.gz", hash = "sha256:adf09e5be15122a7f4e372cb5a6dd512bbf8d78a23a90770ad0983ee9d909061"},
|
||||||
|
{file = "django_model_utils-4.0.0-py2.py3-none-any.whl", hash = "sha256:9cf882e5b604421b62dbe57ad2b18464dc9c8f963fc3f9831badccae66c1139c"},
|
||||||
|
]
|
||||||
|
ipython = [
|
||||||
|
{file = "ipython-7.13.0-py3-none-any.whl", hash = "sha256:eb8d075de37f678424527b5ef6ea23f7b80240ca031c2dd6de5879d687a65333"},
|
||||||
|
{file = "ipython-7.13.0.tar.gz", hash = "sha256:ca478e52ae1f88da0102360e57e528b92f3ae4316aabac80a2cd7f7ab2efb48a"},
|
||||||
|
]
|
||||||
|
ipython-genutils = [
|
||||||
|
{file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"},
|
||||||
|
{file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"},
|
||||||
|
]
|
||||||
|
jedi = [
|
||||||
|
{file = "jedi-0.16.0-py2.py3-none-any.whl", hash = "sha256:b4f4052551025c6b0b0b193b29a6ff7bdb74c52450631206c262aef9f7159ad2"},
|
||||||
|
{file = "jedi-0.16.0.tar.gz", hash = "sha256:d5c871cb9360b414f981e7072c52c33258d598305280fef91c6cae34739d65d5"},
|
||||||
|
]
|
||||||
|
parso = [
|
||||||
|
{file = "parso-0.6.2-py2.py3-none-any.whl", hash = "sha256:8515fc12cfca6ee3aa59138741fc5624d62340c97e401c74875769948d4f2995"},
|
||||||
|
{file = "parso-0.6.2.tar.gz", hash = "sha256:0c5659e0c6eba20636f99a04f469798dca8da279645ce5c387315b2c23912157"},
|
||||||
|
]
|
||||||
|
pexpect = [
|
||||||
|
{file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"},
|
||||||
|
{file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"},
|
||||||
|
]
|
||||||
|
pickleshare = [
|
||||||
|
{file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"},
|
||||||
|
{file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"},
|
||||||
|
]
|
||||||
|
prompt-toolkit = [
|
||||||
|
{file = "prompt_toolkit-3.0.4-py3-none-any.whl", hash = "sha256:859e1b205b6cf6a51fa57fa34202e45365cf58f8338f0ee9f4e84a4165b37d5b"},
|
||||||
|
{file = "prompt_toolkit-3.0.4.tar.gz", hash = "sha256:ebe6b1b08c888b84c50d7f93dee21a09af39860144ff6130aadbd61ae8d29783"},
|
||||||
|
]
|
||||||
|
ptyprocess = [
|
||||||
|
{file = "ptyprocess-0.6.0-py2.py3-none-any.whl", hash = "sha256:d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f"},
|
||||||
|
{file = "ptyprocess-0.6.0.tar.gz", hash = "sha256:923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0"},
|
||||||
|
]
|
||||||
|
pygments = [
|
||||||
|
{file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"},
|
||||||
|
{file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"},
|
||||||
|
]
|
||||||
|
pytz = [
|
||||||
|
{file = "pytz-2019.3-py2.py3-none-any.whl", hash = "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d"},
|
||||||
|
{file = "pytz-2019.3.tar.gz", hash = "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"},
|
||||||
|
]
|
||||||
|
six = [
|
||||||
|
{file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"},
|
||||||
|
{file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"},
|
||||||
|
]
|
||||||
|
sqlparse = [
|
||||||
|
{file = "sqlparse-0.3.1-py2.py3-none-any.whl", hash = "sha256:022fb9c87b524d1f7862b3037e541f68597a730a8843245c349fc93e1643dc4e"},
|
||||||
|
{file = "sqlparse-0.3.1.tar.gz", hash = "sha256:e162203737712307dfe78860cc56c8da8a852ab2ee33750e33aeadf38d12c548"},
|
||||||
|
]
|
||||||
|
traitlets = [
|
||||||
|
{file = "traitlets-4.3.3-py2.py3-none-any.whl", hash = "sha256:70b4c6a1d9019d7b4f6846832288f86998aa3b9207c6821f3578a6a6a467fe44"},
|
||||||
|
{file = "traitlets-4.3.3.tar.gz", hash = "sha256:d023ee369ddd2763310e4c3eae1ff649689440d4ae59d7485eb4cfbbe3e359f7"},
|
||||||
|
]
|
||||||
|
wcwidth = [
|
||||||
|
{file = "wcwidth-0.1.8-py2.py3-none-any.whl", hash = "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603"},
|
||||||
|
{file = "wcwidth-0.1.8.tar.gz", hash = "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8"},
|
||||||
|
]
|
17
pyproject.toml
Normal file
17
pyproject.toml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
[tool.poetry]
|
||||||
|
name = "pile"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = ""
|
||||||
|
authors = ["Tomáš Mládek <t@mldk.cz>"]
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "^3.8"
|
||||||
|
django = "^3.0.4"
|
||||||
|
django-model-utils = "^4.0.0"
|
||||||
|
|
||||||
|
[tool.poetry.dev-dependencies]
|
||||||
|
ipython = "^7.13.0"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry>=0.12"]
|
||||||
|
build-backend = "poetry.masonry.api"
|
16
sdbs_pile/asgi.py
Normal file
16
sdbs_pile/asgi.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
"""
|
||||||
|
ASGI config for sdbs_pile project.
|
||||||
|
|
||||||
|
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.asgi import get_asgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sdbs_pile.settings')
|
||||||
|
|
||||||
|
application = get_asgi_application()
|
0
sdbs_pile/pile/__init__.py
Normal file
0
sdbs_pile/pile/__init__.py
Normal file
27
sdbs_pile/pile/admin.py
Normal file
27
sdbs_pile/pile/admin.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from sdbs_pile.pile.models import Tag, Document
|
||||||
|
|
||||||
|
|
||||||
|
class TagAdmin(admin.ModelAdmin):
|
||||||
|
exclude = ('is_removed',)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def document_count(tag: Tag):
|
||||||
|
return tag.documents.count()
|
||||||
|
|
||||||
|
list_display = ('name', 'document_count')
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentAdmin(admin.ModelAdmin):
|
||||||
|
exclude = ('is_removed',)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def filed_under(document: Document):
|
||||||
|
return ", ".join(tag.name for tag in document.tags.all())
|
||||||
|
|
||||||
|
list_display = ('title', 'filed_under')
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(Tag, TagAdmin)
|
||||||
|
admin.site.register(Document, DocumentAdmin)
|
5
sdbs_pile/pile/apps.py
Normal file
5
sdbs_pile/pile/apps.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class PileConfig(AppConfig):
|
||||||
|
name = 'pile'
|
44
sdbs_pile/pile/migrations/0001_initial.py
Normal file
44
sdbs_pile/pile/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
# Generated by Django 3.0.4 on 2020-03-17 22:29
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Tag',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('is_removed', models.BooleanField(default=False)),
|
||||||
|
('name', models.CharField(max_length=128)),
|
||||||
|
('description', models.TextField(blank=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Document',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('is_removed', models.BooleanField(default=False)),
|
||||||
|
('title', models.CharField(max_length=512)),
|
||||||
|
('description', models.TextField(blank=True)),
|
||||||
|
('author', models.CharField(blank=True, max_length=512)),
|
||||||
|
('published', models.CharField(blank=True, max_length=128)),
|
||||||
|
('external_url', models.URLField(blank=True, null=True)),
|
||||||
|
('file', models.FileField(blank=True, null=True, upload_to='')),
|
||||||
|
('uploaded', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('tags', models.ManyToManyField(related_name='documents', to='pile.Tag')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
18
sdbs_pile/pile/migrations/0002_auto_20200317_2357.py
Normal file
18
sdbs_pile/pile/migrations/0002_auto_20200317_2357.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.0.4 on 2020-03-17 22:57
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pile', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='document',
|
||||||
|
name='uploaded',
|
||||||
|
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
0
sdbs_pile/pile/migrations/__init__.py
Normal file
0
sdbs_pile/pile/migrations/__init__.py
Normal file
39
sdbs_pile/pile/models.py
Normal file
39
sdbs_pile/pile/models.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.core.files.storage import FileSystemStorage
|
||||||
|
from django.db import models
|
||||||
|
from model_utils.models import SoftDeletableModel
|
||||||
|
|
||||||
|
|
||||||
|
class Tag(SoftDeletableModel):
|
||||||
|
name = models.CharField(max_length=128, null=False, blank=False)
|
||||||
|
description = models.TextField(null=False, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class Document(SoftDeletableModel):
|
||||||
|
title = models.CharField(max_length=512, null=False, blank=False)
|
||||||
|
description = models.TextField(null=False, blank=True)
|
||||||
|
author = models.CharField(max_length=512, null=False, blank=True)
|
||||||
|
published = models.CharField(max_length=128, null=False, blank=True)
|
||||||
|
external_url = models.URLField(null=True, blank=True)
|
||||||
|
file = models.FileField(null=True, blank=True, storage=FileSystemStorage(location='docs'))
|
||||||
|
tags = models.ManyToManyField(Tag, related_name="documents")
|
||||||
|
uploaded = models.DateTimeField(auto_now_add=True, null=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['-id']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url(self):
|
||||||
|
if self.file:
|
||||||
|
return self.file.url
|
||||||
|
return self.external_url
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
if not (self.file or self.external_url):
|
||||||
|
raise ValidationError("An uploaded document or an external URL is required.")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.title}{f' ({self.author})' if self.author else ''}"
|
|
@ -44,7 +44,7 @@ ul > li:before {
|
||||||
background-color: #202020;
|
background-color: #202020;
|
||||||
color: white;
|
color: white;
|
||||||
|
|
||||||
background-image: url(/assets/pile_white.svg);
|
background-image: url(/static/pile_white.svg);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center 1.5em;
|
background-position: center 1.5em;
|
||||||
background-size: 50%;
|
background-size: 50%;
|
||||||
|
@ -167,6 +167,14 @@ ul > li:before {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.doc-description {
|
||||||
|
padding: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doc-description p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.doc-link-intro:before {
|
.doc-link-intro:before {
|
||||||
content: "➜ ";
|
content: "➜ ";
|
||||||
}
|
}
|
||||||
|
@ -234,16 +242,8 @@ ul > li:before {
|
||||||
right: 2rem;
|
right: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#login input {
|
#login a {
|
||||||
height: 14pt;
|
color: black;
|
||||||
border: 1px solid lightgray;
|
|
||||||
}
|
|
||||||
|
|
||||||
#login button {
|
|
||||||
height: 14pt;
|
|
||||||
font-size: 8pt;
|
|
||||||
border: 1px solid lightgray;
|
|
||||||
background: white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.czech {
|
.czech {
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB |
56
sdbs_pile/pile/templates/front_base.html
Normal file
56
sdbs_pile/pile/templates/front_base.html
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
{% load static %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>The /-\ pile{% block title %}{% endblock %}</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% static "main.css" %}">
|
||||||
|
<link rel="icon" type="image/png" href="{% static "favicon.png" %}">
|
||||||
|
{% block meta-og %}{% endblock %}
|
||||||
|
<meta property="og:image" content="{% static "favicon.png" %}"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="sidebar">
|
||||||
|
<div id="sidebar-head">
|
||||||
|
<h1><a href="..">The /-\ pile</a></h1>
|
||||||
|
</div>
|
||||||
|
<div id="sidebar-taglist">
|
||||||
|
<ul>
|
||||||
|
<li id="sidebar-taglist-top"><a href="{% url "pile:tag" "*" %}">ALL ({{ document_count }})</a></li>
|
||||||
|
{% if untagged.count %}
|
||||||
|
<li id="sidebar-taglist-top"><a href="?tag=_">UNTAGGED ({{ untagged_count }})</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% for tag in tags %}
|
||||||
|
{% if tag.documents.count > 0 %}
|
||||||
|
<li><a href="{% url 'pile:tag' tag.id %}">{{ tag.name }} ({{ tag.documents.count }})</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="content">
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="login">
|
||||||
|
<a href="/admin">[maintain]</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
window.counter = 'https://sdbs_pile.goatcounter.com/count'
|
||||||
|
|
||||||
|
var script = document.createElement('script');
|
||||||
|
script.async = 1;
|
||||||
|
script.src = '//gc.zgo.at/count.js';
|
||||||
|
var ins = document.getElementsByTagName('script')[0];
|
||||||
|
ins.parentNode.insertBefore(script, ins)
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
56
sdbs_pile/pile/templates/front_doc_detail.html
Normal file
56
sdbs_pile/pile/templates/front_doc_detail.html
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
{% extends "front_base.html" %}
|
||||||
|
|
||||||
|
{% block title %}: {{ document.title }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="text document">
|
||||||
|
<h1>{{ document.title }}</h1>
|
||||||
|
|
||||||
|
{% if document.author %}
|
||||||
|
<h2>{{ document.author }}</h2>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if document.published %}
|
||||||
|
<h3>Published: {{ document.published }}</h3>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if document.tags.count > 0 %}
|
||||||
|
<h3 class="doc-taglist">
|
||||||
|
<span>Tags:</span>
|
||||||
|
{% for tag in document.tags.all %}
|
||||||
|
<li>
|
||||||
|
<a href="{% url "pile:tag" tag.id %}" title="{{ tag.description }}">
|
||||||
|
{{ tag.name }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</h3>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if document.description %}
|
||||||
|
<div class="doc-description">
|
||||||
|
<span class="doc-description-intro">
|
||||||
|
{% if document.url %}Description{% else %}Content{% endif %}:
|
||||||
|
</span>
|
||||||
|
<p> {{ document.description }} </p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# <div class="doc-link"><span class="doc-link-intro">Get (document with) print label: </span>#}
|
||||||
|
{# <a href="/label.php?id=<?= $doc[" ID"] ?>">https://pile.sdbs.cz/label.php?id=<?= $doc["ID"] ?></a></div>#}
|
||||||
|
|
||||||
|
{% if document.url %}
|
||||||
|
<div class="doc-link">
|
||||||
|
<span class="doc-link-intro">Access file at:</span>
|
||||||
|
<a href="{{ document.url }}">{{ document.url }}</a></div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block meta-og %}
|
||||||
|
<title>The /-\ pile: {{ document.title }}</title>
|
||||||
|
<meta property="og:title" content="The /-\ Pile: {{ document.title }}"/>
|
||||||
|
<meta property="og:url" content="{% url "pile:document" document.id %}"/>
|
||||||
|
<meta property="og:description" content="{{ document.description }}"/>
|
||||||
|
<meta property="og:type" content="article"/>
|
||||||
|
{% endblock %}
|
22
sdbs_pile/pile/templates/front_doc_listing.html
Normal file
22
sdbs_pile/pile/templates/front_doc_listing.html
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{% extends "front_base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% if tag %}
|
||||||
|
<div class="text tag-text">
|
||||||
|
<h1>{{ tag.name }}</h1>
|
||||||
|
<p class="tag-desc">{{ tag.description }}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for document in documents %}
|
||||||
|
<div class="text doc-item">
|
||||||
|
<a class="doc-item-link" href="{{ document.url }}">🔗</a>
|
||||||
|
<a href="{% url "pile:document" document.id %}">
|
||||||
|
<div class="doc-item-text">
|
||||||
|
<h2>{{ document.title }}</h2>
|
||||||
|
<h3>{{ document.author }} {{ document.published }}</h3>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
33
sdbs_pile/pile/templates/front_intro.html
Normal file
33
sdbs_pile/pile/templates/front_intro.html
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
{% extends "front_base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="text">
|
||||||
|
<p class="intro"> This site is the sdbs pile, where we upload the stuff we consider important to the larger
|
||||||
|
conceptual and thematic landscape of what we do: "confronting apathy", inter-subjectivity, the human right
|
||||||
|
to
|
||||||
|
self-determination, counter-culture and such...</p>
|
||||||
|
<p class="intro czech">Tohle je hromádka zajímavýho materiálu co něco znamená v kontextu sdbs - budeme sem
|
||||||
|
postupně dávat ty nejdůležitější nebo nejzajímavější věci, zatim se o tom ale nikde moc nešiřte.</p>
|
||||||
|
<p class="intro sign">/-\</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text recent-additions">
|
||||||
|
<h2>Recent additions</h2>
|
||||||
|
<ul>
|
||||||
|
{% for document in recent_documents %}
|
||||||
|
<li>
|
||||||
|
<a href="{% url 'pile:document' document.id %}">
|
||||||
|
{% if document.uploaded %}
|
||||||
|
<em>({{ document.uploaded|date:"Y/m/d G:i:s" }})</em>
|
||||||
|
{% endif %}
|
||||||
|
{{ document.title }}
|
||||||
|
|
||||||
|
<div class="recent-additions-desc">
|
||||||
|
{{ document.description }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
3
sdbs_pile/pile/tests.py
Normal file
3
sdbs_pile/pile/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
10
sdbs_pile/pile/urls.py
Normal file
10
sdbs_pile/pile/urls.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
app_name = 'pile'
|
||||||
|
urlpatterns = [
|
||||||
|
path('', views.IndexView.as_view(), name='index'),
|
||||||
|
path('tag/<name_or_id>', views.TagView.as_view(), name='tag'),
|
||||||
|
path('item/<int:document_id>', views.DocumentView.as_view(), name='document'),
|
||||||
|
]
|
62
sdbs_pile/pile/views.py
Normal file
62
sdbs_pile/pile/views.py
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
# Create your views here.
|
||||||
|
from django.db.models import Count
|
||||||
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
|
from sdbs_pile.pile.models import Tag, Document
|
||||||
|
|
||||||
|
|
||||||
|
class BasePileView(TemplateView):
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
return {
|
||||||
|
'tags': sorted(sorted(Tag.objects.all(), key=lambda tag: tag.name),
|
||||||
|
key=lambda tag: tag.documents.count(), reverse=True),
|
||||||
|
'document_count': Document.objects.count(),
|
||||||
|
'untagged_count': Document.objects.annotate(tag_count=Count('tags')).filter(tag_count__gt=0).count()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class IndexView(BasePileView):
|
||||||
|
template_name = "front_intro.html"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
base_context_data = super(IndexView, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'recent_documents': Document.objects.order_by('-uploaded')[:5],
|
||||||
|
**base_context_data
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TagView(BasePileView):
|
||||||
|
template_name = "front_doc_listing.html"
|
||||||
|
|
||||||
|
def get_context_data(self, name_or_id: str):
|
||||||
|
base_context_data = super(TagView, self).get_context_data()
|
||||||
|
|
||||||
|
if name_or_id == "*":
|
||||||
|
tag = None
|
||||||
|
documents = Document.objects.all()
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
tag = Tag.objects.get(id=int(name_or_id))
|
||||||
|
except ValueError:
|
||||||
|
tag = Tag.objects.get(name=name_or_id)
|
||||||
|
documents = tag.documents.all()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'tag': tag,
|
||||||
|
'documents': documents,
|
||||||
|
**base_context_data
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentView(BasePileView):
|
||||||
|
template_name = "front_doc_detail.html"
|
||||||
|
|
||||||
|
def get_context_data(self, document_id: int):
|
||||||
|
base_context_data = super(DocumentView, self).get_context_data()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'document': Document.objects.get(pk=document_id),
|
||||||
|
**base_context_data
|
||||||
|
}
|
114
sdbs_pile/settings.py
Normal file
114
sdbs_pile/settings.py
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
"""
|
||||||
|
Django settings for sdbs_pile project.
|
||||||
|
|
||||||
|
Generated by 'django-admin startproject' using Django 3.0.4.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/3.0/topics/settings/
|
||||||
|
|
||||||
|
For the full list of settings and their values, see
|
||||||
|
https://docs.djangoproject.com/en/3.0/ref/settings/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
# Quick-start development settings - unsuitable for production
|
||||||
|
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
|
||||||
|
|
||||||
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
|
SECRET_KEY = 'x5j0*70$a&l*n_@kn=j%4_@_+ismdl-o8!z0@vyjfl0tt+nlxx'
|
||||||
|
|
||||||
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = []
|
||||||
|
|
||||||
|
# Application definition
|
||||||
|
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
|
'sdbs_pile.pile'
|
||||||
|
]
|
||||||
|
|
||||||
|
MIDDLEWARE = [
|
||||||
|
'django.middleware.security.SecurityMiddleware',
|
||||||
|
'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 = 'sdbs_pile.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',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
WSGI_APPLICATION = 'sdbs_pile.wsgi.application'
|
||||||
|
|
||||||
|
# Database
|
||||||
|
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Password validation
|
||||||
|
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
# Internationalization
|
||||||
|
# https://docs.djangoproject.com/en/3.0/topics/i18n/
|
||||||
|
|
||||||
|
LANGUAGE_CODE = 'en-us'
|
||||||
|
TIME_ZONE = 'Europe/Prague'
|
||||||
|
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
USE_L10N = True
|
||||||
|
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
# https://docs.djangoproject.com/en/3.0/howto/static-files/
|
||||||
|
|
||||||
|
STATIC_URL = '/static/'
|
22
sdbs_pile/urls.py
Normal file
22
sdbs_pile/urls.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
"""sdbs_pile URL Configuration
|
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
|
https://docs.djangoproject.com/en/3.0/topics/http/urls/
|
||||||
|
Examples:
|
||||||
|
Function views
|
||||||
|
1. Add an import: from my_app import views
|
||||||
|
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||||
|
Class-based views
|
||||||
|
1. Add an import: from other_app.views import Home
|
||||||
|
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||||
|
Including another URLconf
|
||||||
|
1. Import the include() function: from django.urls import include, path
|
||||||
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
|
"""
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path, include
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('', include('sdbs_pile.pile.urls')),
|
||||||
|
path('admin/', admin.site.urls),
|
||||||
|
]
|
16
sdbs_pile/wsgi.py
Normal file
16
sdbs_pile/wsgi.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
"""
|
||||||
|
WSGI config for sdbs_pile project.
|
||||||
|
|
||||||
|
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sdbs_pile.settings')
|
||||||
|
|
||||||
|
application = get_wsgi_application()
|
|
@ -1 +0,0 @@
|
||||||
Deny from all
|
|
|
@ -1,35 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
// All credit goes to Chad Minick:
|
|
||||||
// http://chadminick.com/articles/simple-php-template-engine.html
|
|
||||||
|
|
||||||
class Template
|
|
||||||
{
|
|
||||||
private $vars = array();
|
|
||||||
|
|
||||||
public function __get($name)
|
|
||||||
{
|
|
||||||
return $this->vars[$name];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __set($name, $value)
|
|
||||||
{
|
|
||||||
if ($name == 'view_template_file') {
|
|
||||||
throw new Exception("Cannot bind variable named 'view_template_file'");
|
|
||||||
}
|
|
||||||
$this->vars[$name] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function render($view_template_file)
|
|
||||||
{
|
|
||||||
if (array_key_exists('view_template_file', $this->vars)) {
|
|
||||||
throw new Exception("Cannot bind variable called 'view_template_file'");
|
|
||||||
}
|
|
||||||
extract($this->vars);
|
|
||||||
ob_start();
|
|
||||||
include($view_template_file);
|
|
||||||
return ob_get_clean();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,37 +0,0 @@
|
||||||
<div class="text document edit-form">
|
|
||||||
<form method="post" id="form" action="admin.php?action=edit_item<?= empty($doc) ? "" : "&item=" . $doc["ID"] ?>"
|
|
||||||
enctype="multipart/form-data">
|
|
||||||
<strong>Title:</strong> <input id="title-input" type="text" name="Title"
|
|
||||||
value="<?= empty($doc) ? "" : $doc["Title"] ?>"><br>
|
|
||||||
<strong>Author:</strong> <input type="text" name="Author" value="<?= empty($doc) ? "" : $doc["Author"] ?>"><br>
|
|
||||||
<strong>Date published:</strong> <input type="text" name="Published"
|
|
||||||
value="<?= empty($doc) ? "" : $doc["Published"] ?>"><br>
|
|
||||||
<strong>Description:</strong><br>
|
|
||||||
<textarea name="Description" cols="120" rows="20">
|
|
||||||
<?= empty($doc) ? "" : $doc["Description"] ?>
|
|
||||||
</textarea><br>
|
|
||||||
<strong>File:</strong> <input id="file-input" type="file" name="upfile" onchange="updateTitle()"><br>
|
|
||||||
<strong>URL:</strong> <input type="text" name="URL" value="<?= empty($doc) ? "" : $doc["URL"] ?>"><br>
|
|
||||||
<strong>Tags:</strong> <input type="text" name="Tags" value="<?php
|
|
||||||
if (!empty($doc)) {
|
|
||||||
$tags = [];
|
|
||||||
foreach ($doc["tags"] as $tag) {
|
|
||||||
array_push($tags, $tag["Name"]);
|
|
||||||
}
|
|
||||||
echo implode(", ", $tags);
|
|
||||||
} else if (!empty($_GET["tag"])) {
|
|
||||||
echo $tag["Name"];
|
|
||||||
}
|
|
||||||
?>"><br>
|
|
||||||
<input type="submit">
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
function updateTitle() {
|
|
||||||
const titleInput = document.getElementById("title-input");
|
|
||||||
if (titleInput.value.length === 0) {
|
|
||||||
const filename = document.getElementById("file-input").value;
|
|
||||||
titleInput.value = filename.replace(/.*[\/\\]/, '').replace(/\.[\w]{2,}$/, '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,39 +0,0 @@
|
||||||
<?php if (isset($tag)): ?>
|
|
||||||
<div class="text tag-text">
|
|
||||||
<h1><?= $tag["Name"] ?></h1>
|
|
||||||
<p class="tag-desc"><?= $tag["Description"] ?></p>
|
|
||||||
<a class="tag-edit-link" href="?action=edit_tag&tag=<?= $tag["ID"] ?>">[edit tag]</a>
|
|
||||||
<a class="tag-edit-link" href="#" onclick="confirmDelete()">[delete tag]</a>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if ($_GET["tag"] != "*" &&
|
|
||||||
$_GET["tag"] != "_"): ?>
|
|
||||||
<div class="text doc-item doc-new-item">
|
|
||||||
<a href="?action=new_item&tag=<?= $tag["ID"] ?>">
|
|
||||||
<div class="doc-item-text">
|
|
||||||
<h2>Upload a new document</h2>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php foreach ($docs as $doc): ?>
|
|
||||||
<div class="text doc-item">
|
|
||||||
<a class="doc-item-link" href="?action=remove&item=<?= $doc["ID"] ?>">[X]</a>
|
|
||||||
<a href="?action=edit_item&item=<?= $doc["ID"] ?>">
|
|
||||||
<div class="doc-item-text">
|
|
||||||
<h2><?= $doc["Title"] ?></h2>
|
|
||||||
<h3><?= $doc["Author"] . " " . $doc['date'] ?></h3>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function confirmDelete() {
|
|
||||||
if (window.confirm("Do you really wish to delete this tag?")) {
|
|
||||||
window.open("?action=delete_tag&tag=<?= $tag["ID"] ?>")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<div class="text">
|
|
||||||
<p>Confirm deletion of <strong>"<?= $doc["Title"] ?>"</strong>:</p>
|
|
||||||
<a href="admin.php?action=remove&confirm=yes&item=<?= $doc["ID"] ?>&ret=<?= $_SERVER['HTTP_REFERER']; ?>"
|
|
||||||
class="button">Remove from database</a>
|
|
||||||
</div>
|
|
|
@ -1,3 +0,0 @@
|
||||||
<div class="text">
|
|
||||||
<p class="intro">Handle with care.</p>
|
|
||||||
</div>
|
|
|
@ -1,10 +0,0 @@
|
||||||
<div class="text document edit-form">
|
|
||||||
<form method="post" id="form" action="admin.php?action=edit_tag<?= empty($tag) ? "" : "&tag=" . $tag["ID"] ?>">
|
|
||||||
<strong>Name:</strong> <input type="text" name="Name" value="<?= empty($tag) ? "" : $tag["Name"] ?>"><br>
|
|
||||||
<strong>Description:</strong><br>
|
|
||||||
<textarea name="Description" cols="120" rows="20">
|
|
||||||
<?= empty($tag) ? "" : $tag["Description"] ?>
|
|
||||||
</textarea><br>
|
|
||||||
<input type="submit">
|
|
||||||
</form>
|
|
||||||
</div>
|
|
|
@ -1,46 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
|
|
||||||
<title>pile ADMIN INTERFACE</title>
|
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="assets/admin.css">
|
|
||||||
<link rel="icon" type="image/png" href="/favicon.png">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div id="sidebar">
|
|
||||||
<div id="sidebar-head">
|
|
||||||
<h1><a href="admin.php">pile admin</a></h1>
|
|
||||||
</div>
|
|
||||||
<div id="sidebar-taglist">
|
|
||||||
<ul id="sidebar-taglist-overview">
|
|
||||||
<li id="sidebar-taglist-top"><a href="?tag=*">ALL (<?= $all_count ?>)</a></li>
|
|
||||||
<li id="sidebar-taglist-top"><a href="?tag=_">UNTAGGED (<?= $none_count ?>)</a></li>
|
|
||||||
<li id="sidebar-taglist-top"><a href="?action=new_tag">ADD TAG</a></li>
|
|
||||||
</ul>
|
|
||||||
<ul>
|
|
||||||
<?php
|
|
||||||
foreach ($tags as $tag) {
|
|
||||||
echo '<li><a href="?tag=' . $tag['id'] . "\">" . $tag['name'] . " (" . $tag['count'] . ")</a></li>";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="content">
|
|
||||||
<?php echo $content ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="login">
|
|
||||||
<form method="get">
|
|
||||||
<input type="hidden" name="action" value="logout">
|
|
||||||
<button type="submit" id="login-button">log out</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,21 +0,0 @@
|
||||||
<?php /** @noinspection PhpUndefinedVariableInspection */
|
|
||||||
if (isset($tag)): ?>
|
|
||||||
<div class="text tag-text">
|
|
||||||
<h1><?= $tag["Name"] ?></h1>
|
|
||||||
<p class="tag-desc"><?= $tag["HTMLDescription"] ?></p>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php foreach ($docs as $doc): ?>
|
|
||||||
<div class="text doc-item">
|
|
||||||
<?php if (!empty($doc["URL"])): ?>
|
|
||||||
<a class="doc-item-link" href="<?= $doc["URL"] ?>">🔗</a>
|
|
||||||
<?php endif; ?>
|
|
||||||
<a href="?item=<?= $doc["ID"] ?>">
|
|
||||||
<div class="doc-item-text">
|
|
||||||
<h2><?= $doc["Title"] ?></h2>
|
|
||||||
<h3><?= $doc["Author"] . " " . $doc['date'] ?></h3>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<?php endforeach; ?>
|
|
|
@ -1,35 +0,0 @@
|
||||||
<div class="text document">
|
|
||||||
<h1><?= $doc["Title"] ?></h1>
|
|
||||||
|
|
||||||
<?php if (!empty($doc["Author"])): ?>
|
|
||||||
<h2><?= $doc["Author"] ?></h2>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if (!empty($doc["Published"])): ?>
|
|
||||||
<h3>Published: <?= $doc["Published"] ?></h3>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if (!empty($doc["tags"])): ?>
|
|
||||||
<h3 class="doc-taglist">Tags:
|
|
||||||
<?php
|
|
||||||
foreach ($doc["tags"] as $tag) {
|
|
||||||
echo '<li><a href="?tag=' . $tag["ID"] . "\">" . $tag["Name"] . "</a></li>";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</h3>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if ($doc["HTMLDescription"]): ?>
|
|
||||||
<p class="doc-description"><span
|
|
||||||
class="doc-description-intro"><?= empty($doc["URL"]) ? "Content" : "Description" ?>
|
|
||||||
: </span><?= $doc["HTMLDescription"] ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<div class="doc-link"><span class="doc-link-intro">Get (document with) print label: </span>
|
|
||||||
<a href="/label.php?id=<?= $doc["ID"] ?>">https://pile.sdbs.cz/label.php?id=<?= $doc["ID"] ?></a></div>
|
|
||||||
|
|
||||||
<?php if (!empty($doc["URL"])): ?>
|
|
||||||
<div class="doc-link"><span class="doc-link-intro">Access file at: </span><a
|
|
||||||
href="<?= $doc["URL"] ?>"><?= urldecode($doc["URL"]) ?></a></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
|
@ -1,28 +0,0 @@
|
||||||
<div class="text">
|
|
||||||
<p class="intro"> This site is the sdbs pile, where we upload the stuff we consider important to the larger
|
|
||||||
conceptual and thematic landscape of what we do: "confronting apathy", inter-subjectivity, the human right to
|
|
||||||
self-determination, counter-culture and such...</p>
|
|
||||||
<p class="intro czech">Tohle je hromádka zajímavýho materiálu co něco znamená v kontextu sdbs - budeme sem postupně
|
|
||||||
dávat ty nejdůležitější nebo nejzajímavější věci, zatim se o tom ale nikde moc nešiřte.</p>
|
|
||||||
<p class="intro sign">/-\</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text recent-additions">
|
|
||||||
<h2>Recent additions</h2>
|
|
||||||
<ul>
|
|
||||||
<?php foreach (array_slice($recent_docs, 0, 5) as $doc): ?>
|
|
||||||
<li>
|
|
||||||
<a href="/?item=<?= $doc['ID'] ?>">
|
|
||||||
<?php if (!empty($doc['UploadedTime'])): ?>
|
|
||||||
<em>(<?= date("Y/m/d H:i:s", $doc['UploadedTime']); ?>)</em>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?= $doc['Title'] ?>
|
|
||||||
|
|
||||||
<div class="recent-additions-desc">
|
|
||||||
<?= $doc['Description'] ?>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
|
@ -1,88 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="assets/main.css">
|
|
||||||
<link rel="icon" type="image/png" href="/favicon.png">
|
|
||||||
|
|
||||||
<?php if ($selected_doc): ?>
|
|
||||||
<title>The /-\ pile: <?= $selected_doc['Title'] ?></title>
|
|
||||||
<meta property="og:title" content="The /-\ Pile: <?= $selected_doc['Title'] ?>"/>
|
|
||||||
<meta property="og:url" content="https://pile.sdbs.cz/?item=<?= $selected_doc['ID'] ?>"/>
|
|
||||||
<meta property="og:description" content="<?= $selected_doc['Description'] ?>"/>
|
|
||||||
<meta property="og:type" content="article"/>
|
|
||||||
<?php elseif ($selected_tag): ?>
|
|
||||||
<title>The /-\ pile: Filed under "<?= $selected_tag['Name'] ?>"</title>
|
|
||||||
<meta property="og:title" content="The /-\ Pile: Documents under '<?= $selected_tag['Name'] ?>'"/>
|
|
||||||
<meta property="og:url" content="https://pile.sdbs.cz/?tag=<?= $selected_tag['ID'] ?>"/>
|
|
||||||
<meta property="og:description" content="<?= $selected_tag['Description'] ?>"/>
|
|
||||||
<meta property="og:type" content="website"/>
|
|
||||||
<?php else: ?>
|
|
||||||
<title>The /-\ pile</title>
|
|
||||||
<meta property="og:title" content="The /-\ Pile"/>
|
|
||||||
<meta property="og:type" content="website"/>
|
|
||||||
<meta property="og:url" content="https://pile.sdbs.cz/"/>
|
|
||||||
<meta property="og:description"
|
|
||||||
content="This is where we upload the stuff we consider important to the larger conceptual and thematic landscape of what we do: confronting apathy, inter-subjectivity, the human right to self-determination, counter-culture and such..."/>
|
|
||||||
<?php endif; ?>
|
|
||||||
<meta property="og:image" content="https://pile.sdbs.cz/favicon.png"/>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div id="sidebar">
|
|
||||||
<div id="sidebar-head">
|
|
||||||
<h1><a href="..">The /-\ pile</a></h1>
|
|
||||||
</div>
|
|
||||||
<div id="sidebar-taglist">
|
|
||||||
<ul>
|
|
||||||
<li id="sidebar-taglist-top"><a href="?tag=*">ALL (<?= $doc_count ?>)</a></li>
|
|
||||||
<?php if ($none_count > 0): ?>
|
|
||||||
<li id="sidebar-taglist-top"><a href="?tag=_">UNTAGGED (<?= $none_count ?>)</a></li>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php
|
|
||||||
foreach ($tags as $tag) {
|
|
||||||
if ($tag['count'] > 0) {
|
|
||||||
echo '<li><a href="?tag=' . $tag['id'] . "\">" . $tag['name'] . " (" . $tag['count'] . ")</a></li>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="content">
|
|
||||||
<?php echo $content ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="login">
|
|
||||||
<?php if ($logged): ?>
|
|
||||||
<form method="get" action="admin.php">
|
|
||||||
<button type="submit" id="login-button">enter admin interface</button>
|
|
||||||
</form>
|
|
||||||
<?php else: ?>
|
|
||||||
<form method="post" action="admin.php">
|
|
||||||
<input type="text" name="username" id="login-user"></input>
|
|
||||||
<input type="password" name="password" id="login-pass"></input>
|
|
||||||
<button type="submit" id="login-button">></button>
|
|
||||||
</form>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
(function () {
|
|
||||||
window.counter = 'https://sdbs_pile.goatcounter.com/count'
|
|
||||||
|
|
||||||
var script = document.createElement('script');
|
|
||||||
script.async = 1;
|
|
||||||
script.src = '//gc.zgo.at/count.js';
|
|
||||||
var ins = document.getElementsByTagName('script')[0];
|
|
||||||
ins.parentNode.insertBefore(script, ins)
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,41 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<?php if (isset($redirect)): ?>
|
|
||||||
<meta http-equiv="refresh" content="1;URL=<?= $redirect ?>"/>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<title>The /-\ pile</title>
|
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="assets/main.css">
|
|
||||||
<link rel="icon" type="image/png" href="/favicon.png">
|
|
||||||
<style>
|
|
||||||
html, body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: table
|
|
||||||
}
|
|
||||||
|
|
||||||
body p {
|
|
||||||
font-size: 3rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
|
||||||
display: table-cell;
|
|
||||||
text-align: center;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
<?= $text ?>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,8 +0,0 @@
|
||||||
<div class="text">
|
|
||||||
<p class="intro"> This site is the sdbs pile, where we upload the stuff we consider important to the larger
|
|
||||||
conceptual and thematic landscape of what we do: "confronting apathy", inter-subjectivity, the human right to
|
|
||||||
self-determination, counter-culture and such...</p>
|
|
||||||
<p class="intro czech">Tohle je hromádka zajímavýho materiálu co něco znamená v kontextu sdbs - budeme sem postupně
|
|
||||||
dávat ty nejdůležitější nebo nejzajímavější věci, zatim se o tom ale nikde moc nešiřte.</p>
|
|
||||||
<p class="intro sign">/-\</p>
|
|
||||||
</div>
|
|
|
@ -1,136 +0,0 @@
|
||||||
<?php /** @noinspection PhpUndefinedVariableInspection */ ?>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<title>LABEL FOR <?= $doc["Title"] ?></title>
|
|
||||||
<!--suppress CssNoGenericFontName -->
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: prociono;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3 {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2 {
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: black;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.exlibris {
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label-outer {
|
|
||||||
width: 100%;
|
|
||||||
border: 5px solid black;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label-stamp-outer {
|
|
||||||
float: left;
|
|
||||||
width: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pile-logo {
|
|
||||||
width: 100%;
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label-stamp {
|
|
||||||
border: 2px solid black;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label-stamp-subtitle {
|
|
||||||
text-align: center;
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
font-size: 20px;
|
|
||||||
|
|
||||||
margin-top: -9px; /* prociono specific */
|
|
||||||
}
|
|
||||||
|
|
||||||
.label-text {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label-title {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label-otherinfo {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label-description {
|
|
||||||
text-align: justify;
|
|
||||||
margin-top: 0;
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.label-footer {
|
|
||||||
width: 100%;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.absolute-footer {
|
|
||||||
width: 100%;
|
|
||||||
position: absolute;
|
|
||||||
text-align: center;
|
|
||||||
bottom: 20px;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1 class="exlibris">ex libris /-\ pile</h1>
|
|
||||||
<div class="label-outer">
|
|
||||||
<div class="label-upper">
|
|
||||||
<div class="label-stamp-outer">
|
|
||||||
<div class="label-column label-stamp">
|
|
||||||
<img id="pile-logo" src="assets/pile_300dpi.png" alt="/-\ Pile"/>
|
|
||||||
<div class="label-stamp-subtitle">#<?= str_pad($doc["ID"], 4, "0", STR_PAD_LEFT); ?></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="label-column label-text">
|
|
||||||
<h2 class="label-title"><?= $doc["Title"] ?></h2>
|
|
||||||
<h3 class="label-otherinfo">
|
|
||||||
<?php if ($doc["Author"]): ?>
|
|
||||||
By <?= $doc["Author"] ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php if ($doc["Published"]): ?>
|
|
||||||
<div class="label-otherinfo-date">(Published: <?= $doc["Published"] ?>)</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
</h3>
|
|
||||||
<p class="label-description"><?= $doc["HTMLDescription"] ?></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="label-footer">
|
|
||||||
<?php if (count($doc["tags"]) > 0): ?>
|
|
||||||
<div class="label-footer-tags">Filed under:
|
|
||||||
<?php
|
|
||||||
for ($i = 0; $i < count($doc["tags"]); $i++) {
|
|
||||||
echo $doc["tags"][$i]["Name"];
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
<div class="label-footer-url">
|
|
||||||
Available at: <a href="https://pile.sdbs.cz/?item=<?= $doc["ID"] ?>">https://pile.sdbs.cz/?item=<?= $doc["ID"] ?></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="absolute-footer">
|
|
||||||
read or share
|
|
||||||
</div>
|
|
||||||
</body>
|
|
|
@ -1 +0,0 @@
|
||||||
Deny from all
|
|
|
@ -1,274 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once dirname(__FILE__) . '/../_vendor/autoload.php';
|
|
||||||
|
|
||||||
class PileDB
|
|
||||||
{
|
|
||||||
protected $db;
|
|
||||||
private $pd;
|
|
||||||
|
|
||||||
function __construct($dbpath = "pile.db")
|
|
||||||
{
|
|
||||||
$this->db = new SQLite3($dbpath);
|
|
||||||
$this->pd = new Parsedown();
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepare($statement)
|
|
||||||
{
|
|
||||||
return $this->db->prepare($statement);
|
|
||||||
}
|
|
||||||
|
|
||||||
function query($statement)
|
|
||||||
{
|
|
||||||
return $this->db->query($statement);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDocCount()
|
|
||||||
{
|
|
||||||
$ret_count = $this->db->query("SELECT count(ID) FROM Documents")->fetchArray(SQLITE3_NUM);
|
|
||||||
return $ret_count[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUntaggedDocCount()
|
|
||||||
{
|
|
||||||
$ret_count = $this->db->query("SELECT
|
|
||||||
count(ID)
|
|
||||||
FROM
|
|
||||||
Documents d
|
|
||||||
LEFT OUTER JOIN
|
|
||||||
DocumentstoTags dt ON dt.Document = d.ID
|
|
||||||
WHERE dt.Document IS NULL")->fetchArray(SQLITE3_NUM);
|
|
||||||
return $ret_count[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTags()
|
|
||||||
{
|
|
||||||
$tag_query = "SELECT
|
|
||||||
ID, Name, count(Document)
|
|
||||||
FROM
|
|
||||||
Tags t
|
|
||||||
LEFT OUTER JOIN
|
|
||||||
DocumentstoTags d ON t.ID = d.Tag
|
|
||||||
GROUP BY Name
|
|
||||||
ORDER BY count(Document) DESC, Name";
|
|
||||||
$tags_ret = $this->db->query($tag_query);
|
|
||||||
$tags = [];
|
|
||||||
while ($row = $tags_ret->fetchArray(SQLITE3_NUM)) {
|
|
||||||
array_push($tags, array(
|
|
||||||
'id' => $row[0],
|
|
||||||
'name' => $row[1],
|
|
||||||
'count' => $row[2]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return $tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch pile document as an associative array.
|
|
||||||
*
|
|
||||||
* @throws NotFoundException when document isn't found.
|
|
||||||
*/
|
|
||||||
public function fetchDoc($id)
|
|
||||||
{
|
|
||||||
$stmt_doc = $this->db->prepare("SELECT * FROM Documents WHERE ID = :id");
|
|
||||||
$stmt_doc->bindValue(":id", $id, SQLITE3_INTEGER);
|
|
||||||
$doc = $stmt_doc->execute()->fetchArray(SQLITE3_ASSOC);
|
|
||||||
if ($doc == false) {
|
|
||||||
throw new NotFoundException();
|
|
||||||
}
|
|
||||||
$doc["HTMLDescription"] = $this->pd->text($doc["Description"]);
|
|
||||||
|
|
||||||
$stmt_tags = $this->db->prepare("SELECT t.ID, t.Name FROM Tags t
|
|
||||||
JOIN DocumentsToTags dt ON t.ID = dt.Tag
|
|
||||||
JOIN Documents d on d.ID = dt.Document
|
|
||||||
WHERE d.ID = :id");
|
|
||||||
$stmt_tags->bindValue(":id", $id, SQLITE3_INTEGER);
|
|
||||||
$ret = $stmt_tags->execute();
|
|
||||||
$doc["tags"] = [];
|
|
||||||
while ($tag = $ret->fetchArray(SQLITE3_ASSOC)) {
|
|
||||||
array_push($doc["tags"], $tag);
|
|
||||||
}
|
|
||||||
return $doc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function listDocs()
|
|
||||||
{
|
|
||||||
if (func_num_args() > 0) {
|
|
||||||
$tag = func_get_arg(0);
|
|
||||||
if ($tag > 0) {
|
|
||||||
$stmt = $this->db->prepare("SELECT
|
|
||||||
ID, Title, Author, Published, URL
|
|
||||||
FROM
|
|
||||||
Documents d
|
|
||||||
LEFT OUTER JOIN
|
|
||||||
DocumentsToTags dt ON d.ID = dt.Document
|
|
||||||
WHERE Tag == :tag");
|
|
||||||
$stmt->bindValue(":tag", $tag, SQLITE3_INTEGER);
|
|
||||||
} else {
|
|
||||||
$stmt = $this->db->prepare("SELECT
|
|
||||||
ID, Title, Author, Published, URL
|
|
||||||
FROM
|
|
||||||
Documents d
|
|
||||||
LEFT OUTER JOIN
|
|
||||||
DocumentsToTags dt ON d.ID = dt.Document
|
|
||||||
WHERE dt.Document IS NULL");
|
|
||||||
}
|
|
||||||
$doc_ret = $stmt->execute();
|
|
||||||
} else {
|
|
||||||
$query = "SELECT ID, Title, Author, Published, URL FROM Documents";
|
|
||||||
$doc_ret = $this->db->query($query);
|
|
||||||
}
|
|
||||||
$docs = [];
|
|
||||||
while ($doc = $doc_ret->fetchArray(SQLITE3_ASSOC)) {
|
|
||||||
$doc['date'] = empty($doc["Published"]) ? "" : "(" . $doc["Published"] . ")";
|
|
||||||
array_push($docs, $doc);
|
|
||||||
}
|
|
||||||
return $docs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRecentDocs($count = 15)
|
|
||||||
{
|
|
||||||
$query = $this->db->prepare("SELECT * FROM Documents ORDER BY ID DESC LIMIT :count");
|
|
||||||
$query->bindValue("count", $count);
|
|
||||||
|
|
||||||
$query_ret = $query->execute();
|
|
||||||
$result = [];
|
|
||||||
while ($row = $query_ret->fetchArray(SQLITE3_ASSOC)) {
|
|
||||||
array_push($result, $row);
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updateDoc($id, $title, $author, $description, $published, $url, $tag_ids)
|
|
||||||
{
|
|
||||||
if (empty($id)) {
|
|
||||||
$stmt = $this->db->prepare("INSERT INTO Documents
|
|
||||||
(ID, Title, Author, Description, Published, URL, UploadedTime)
|
|
||||||
VALUES
|
|
||||||
(NULL, :title, :author, :description, :published, :url, :uploadedtime)");
|
|
||||||
$stmt->bindValue(":uploadedtime", time(), SQLITE3_INTEGER);
|
|
||||||
} else {
|
|
||||||
$stmt = $this->db->prepare("UPDATE Documents SET
|
|
||||||
Title=:title,
|
|
||||||
Author=:author,
|
|
||||||
Description=:description,
|
|
||||||
Published=:published,
|
|
||||||
URL=:url
|
|
||||||
WHERE ID = :id");
|
|
||||||
$stmt->bindValue(":id", $id, SQLITE3_INTEGER);
|
|
||||||
}
|
|
||||||
$stmt->bindValue(":title", $title, SQLITE3_TEXT);
|
|
||||||
$stmt->bindValue(":author", $author, SQLITE3_TEXT);
|
|
||||||
$stmt->bindValue(":description", $description, SQLITE3_TEXT);
|
|
||||||
$stmt->bindValue(":published", $published, SQLITE3_TEXT);
|
|
||||||
$stmt->bindValue(":url", $url, SQLITE3_TEXT);
|
|
||||||
$stmt->execute();
|
|
||||||
if (empty($id)) {
|
|
||||||
$id = $this->db->lastInsertRowid();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($id)) {
|
|
||||||
$delete_stmt = $this->db->prepare("DELETE FROM DocumentsToTags
|
|
||||||
WHERE Document = :id");
|
|
||||||
$delete_stmt->bindValue(":id", $id, SQLITE3_INTEGER);
|
|
||||||
$delete_stmt->execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($tag_ids as $tag) {
|
|
||||||
$tag_stmt = $this->db->prepare("INSERT INTO DocumentsToTags ('Document', 'Tag')
|
|
||||||
VALUES (:doc, :tag)");
|
|
||||||
$tag_stmt->bindValue("doc", $id, SQLITE3_INTEGER);
|
|
||||||
$tag_stmt->bindValue("tag", $tag, SQLITE3_INTEGER);
|
|
||||||
$tag_stmt->execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function removeDoc($id)
|
|
||||||
{
|
|
||||||
$doc_stmt = $this->db->prepare("DELETE FROM Documents
|
|
||||||
WHERE ID = :id");
|
|
||||||
$doc_stmt->bindValue("id", $id, SQLITE3_INTEGER);
|
|
||||||
$doc_stmt->execute();
|
|
||||||
|
|
||||||
$tag_stmt = $this->db->prepare("DELETE FROM DocumentsToTags
|
|
||||||
WHERE Document = :id");
|
|
||||||
$tag_stmt->bindValue("id", $id, SQLITE3_INTEGER);
|
|
||||||
$tag_stmt->execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function findTag($name)
|
|
||||||
{
|
|
||||||
$stmt = $this->db->prepare("SELECT * FROM Tags WHERE Name == :name COLLATE NOCASE");
|
|
||||||
$stmt->bindValue(":name", $name, SQLITE3_TEXT);
|
|
||||||
return $stmt->execute()->fetchArray(SQLITE3_ASSOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Fetches tag as associative array.
|
|
||||||
* @throws NotFoundException
|
|
||||||
*/
|
|
||||||
public function fetchTag($tag)
|
|
||||||
{
|
|
||||||
$stmt = $this->db->prepare("SELECT * FROM Tags WHERE ID == :tag");
|
|
||||||
$stmt->bindValue(":tag", $tag, SQLITE3_INTEGER);
|
|
||||||
$tag = $stmt->execute()->fetchArray(SQLITE3_ASSOC);
|
|
||||||
if ($tag == false) {
|
|
||||||
throw new NotFoundException();
|
|
||||||
}
|
|
||||||
$tag["HTMLDescription"] = $this->pd->text($tag["Description"]);
|
|
||||||
return $tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updateTag($id, $name, $description)
|
|
||||||
{
|
|
||||||
if (empty($id)) {
|
|
||||||
$stmt = $this->db->prepare("INSERT INTO Tags
|
|
||||||
(ID, Name, Description)
|
|
||||||
VALUES
|
|
||||||
(NULL, :name, :description)");
|
|
||||||
} else {
|
|
||||||
$stmt = $this->db->prepare("UPDATE Tags SET
|
|
||||||
Name=:name,
|
|
||||||
Description=:description,
|
|
||||||
Parent=:Parent
|
|
||||||
WHERE ID = :id");
|
|
||||||
$stmt->bindValue(":id", $id, SQLITE3_INTEGER);
|
|
||||||
}
|
|
||||||
$stmt->bindValue(":name", $name, SQLITE3_TEXT);
|
|
||||||
$stmt->bindValue(":description", $description, SQLITE3_TEXT);
|
|
||||||
return $stmt->execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function deleteTag($tag)
|
|
||||||
{
|
|
||||||
$stmt = $this->db->prepare("DELETE FROM Tags WHERE ID == :tag");
|
|
||||||
$stmt->bindValue(":tag", $tag, SQLITE3_INTEGER);
|
|
||||||
return $stmt->execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function authenticate($username, $password)
|
|
||||||
{
|
|
||||||
$stmt = $this->db->prepare("SELECT
|
|
||||||
*
|
|
||||||
FROM
|
|
||||||
Users
|
|
||||||
WHERE
|
|
||||||
Username = :username");
|
|
||||||
$stmt->bindValue(":username", $username, SQLITE3_TEXT);
|
|
||||||
$auth_ret = $stmt->execute();
|
|
||||||
$auth = $auth_ret->fetchArray(SQLITE3_ASSOC);
|
|
||||||
|
|
||||||
if (password_verify($password, $auth["Password"])) {
|
|
||||||
return $auth["ID"];
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NotFoundException extends Exception
|
|
||||||
{
|
|
||||||
// noop
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,54 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class Uploader
|
|
||||||
{
|
|
||||||
public function handle($files, $dir)
|
|
||||||
{
|
|
||||||
if (is_array($files['upfile']['error'])) {
|
|
||||||
throw new RuntimeException('Invalid parameters.');
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($files['upfile']['error']) {
|
|
||||||
case UPLOAD_ERR_OK:
|
|
||||||
break;
|
|
||||||
case UPLOAD_ERR_NO_FILE:
|
|
||||||
throw new RuntimeException('No file sent.');
|
|
||||||
case UPLOAD_ERR_INI_SIZE:
|
|
||||||
throw new RuntimeException('Exceeded INI filesize limit.');
|
|
||||||
case UPLOAD_ERR_FORM_SIZE:
|
|
||||||
throw new RuntimeException('Exceeded form filesize limit.');
|
|
||||||
default:
|
|
||||||
throw new RuntimeException('Unknown errors.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
|
||||||
if (false === $ext = array_search(
|
|
||||||
$finfo->file($files['upfile']['tmp_name']),
|
|
||||||
array(
|
|
||||||
'pdf' => 'application/pdf',
|
|
||||||
'zip' => 'application/zip',
|
|
||||||
'rar' => 'application/rar',
|
|
||||||
'txt' => 'text/plain'
|
|
||||||
),
|
|
||||||
true
|
|
||||||
)) {
|
|
||||||
throw new RuntimeException('Invalid file format.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$name = basename($files['upfile']['name']);
|
|
||||||
$name = preg_replace('/[^\x20-\x7E]/', '', $name);
|
|
||||||
if ($name != ".htaccess") {
|
|
||||||
if (!move_uploaded_file(
|
|
||||||
$files['upfile']['tmp_name'],
|
|
||||||
$dir . $name)) {
|
|
||||||
throw new RuntimeException('Failed to move uploaded file.');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException('Invalid filename.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1 +0,0 @@
|
||||||
Deny from all
|
|
162
www/admin.php
162
www/admin.php
|
@ -1,162 +0,0 @@
|
||||||
<?php
|
|
||||||
require '_templates/Template.php';
|
|
||||||
require '_util/PileDB.php';
|
|
||||||
require '_util/Uploader.php';
|
|
||||||
|
|
||||||
|
|
||||||
$db = new PileDB();
|
|
||||||
$uploader = new Uploader();
|
|
||||||
session_start();
|
|
||||||
|
|
||||||
if (isset($_SESSION['ID'])) {
|
|
||||||
$page = new Template();
|
|
||||||
|
|
||||||
if (isset($_GET["action"])) {
|
|
||||||
switch ($_GET["action"]) {
|
|
||||||
case "new_tag":
|
|
||||||
$content = $page->render("admin_tag_edit.php");
|
|
||||||
break;
|
|
||||||
case "edit_tag":
|
|
||||||
if (isset($_POST["Name"])) {
|
|
||||||
$db->updateTag(
|
|
||||||
$_GET["tag"],
|
|
||||||
$_POST["Name"],
|
|
||||||
$_POST["Description"]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!empty($_GET["tag"])) {
|
|
||||||
$page->tag = $db->fetchTag($_GET["tag"]);
|
|
||||||
}
|
|
||||||
$content = $page->render("admin_tag_edit.php");
|
|
||||||
break;
|
|
||||||
case "delete_tag":
|
|
||||||
if (!empty($_GET["tag"])) {
|
|
||||||
$db->deleteTag($_GET["tag"]);
|
|
||||||
$page->text = "Tag deleted successfully.";
|
|
||||||
$page->redirect = "/admin.php";
|
|
||||||
echo $page->render('full_text.php');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "new_item":
|
|
||||||
if (!empty($_GET["tag"])) {
|
|
||||||
$page->tag = $db->fetchTag($_GET["tag"]);
|
|
||||||
}
|
|
||||||
$content = $page->render("admin_doc_edit.php");
|
|
||||||
break;
|
|
||||||
case "edit_item":
|
|
||||||
if (isset($_POST["Title"]) || !empty($_FILES['upfile']['name'])) {
|
|
||||||
$title = $_POST["Title"];
|
|
||||||
|
|
||||||
if (!empty($_FILES['upfile']['name'])) {
|
|
||||||
try {
|
|
||||||
if (empty($title)) {
|
|
||||||
$title = pathinfo($_FILES['upfile']['name'], PATHINFO_FILENAME);
|
|
||||||
$title = str_replace("_", " ", $title);
|
|
||||||
$title = trim($title);
|
|
||||||
}
|
|
||||||
$url = "http://pile.sdbs.cz/docs/" . rawurlencode($uploader->handle($_FILES, "docs/"));
|
|
||||||
} catch (RuntimeException $ex) {
|
|
||||||
$page->text = $ex->getMessage();
|
|
||||||
echo $page->render('full_text.php');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$url = $_POST["URL"];
|
|
||||||
}
|
|
||||||
|
|
||||||
$doc_tags = [];
|
|
||||||
foreach (explode(",", $_POST["Tags"]) as $tagName) {
|
|
||||||
$tagName = trim($tagName);
|
|
||||||
$tag = $db->findTag($tagName);
|
|
||||||
if (!in_array($tag["ID"], $doc_tags)) {
|
|
||||||
array_push($doc_tags, $tag["ID"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$db->updateDoc(
|
|
||||||
$_GET["item"],
|
|
||||||
$title,
|
|
||||||
$_POST["Author"],
|
|
||||||
$_POST["Description"],
|
|
||||||
$_POST["Published"],
|
|
||||||
$url,
|
|
||||||
$doc_tags
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($_GET["item"])) {
|
|
||||||
$page->doc = $db->fetchDoc($_GET["item"]);
|
|
||||||
}
|
|
||||||
$content = $page->render("admin_doc_edit.php");
|
|
||||||
|
|
||||||
break;
|
|
||||||
case "remove":
|
|
||||||
if (!empty($_GET["confirm"]) && $_GET["confirm"] == "yes") {
|
|
||||||
$db->removeDoc($_GET["item"]);
|
|
||||||
$page->text = "Document deleted.";
|
|
||||||
$page->redirect = $_GET["ret"];
|
|
||||||
echo $page->render("full_text.php");
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
$page->doc = $db->fetchDoc($_GET["item"]);
|
|
||||||
$content = $page->render("admin_doc_remove.php");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "logout":
|
|
||||||
unset($_SESSION["ID"]);
|
|
||||||
$page->text = "See you.";
|
|
||||||
$page->redirect = "/";
|
|
||||||
echo $page->render("full_text.php");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} elseif (isset($_GET["tag"])) {
|
|
||||||
$doc_list_template = new Template();
|
|
||||||
if ($_GET["tag"] == "*") {
|
|
||||||
$docs = $db->listDocs();
|
|
||||||
} elseif ($_GET["tag"] == "_") {
|
|
||||||
$docs = $db->listDocs(-1);
|
|
||||||
} else {
|
|
||||||
$tag = $db->fetchTag($_GET["tag"]);
|
|
||||||
$docs = $db->listDocs($tag["ID"]);
|
|
||||||
$doc_list_template->tag = $tag;
|
|
||||||
}
|
|
||||||
$doc_list_template->docs = $docs;
|
|
||||||
$content = $doc_list_template->render('admin_doc_listing.php');
|
|
||||||
} else {
|
|
||||||
$intro_template = new Template();
|
|
||||||
$content = $intro_template->render('admin_intro.php');
|
|
||||||
}
|
|
||||||
|
|
||||||
$all_count = $db->getDocCount();
|
|
||||||
$none_count = $db->getUntaggedDocCount();
|
|
||||||
|
|
||||||
$tags = $db->getTags();
|
|
||||||
|
|
||||||
$page->all_count = $all_count;
|
|
||||||
$page->none_count = $none_count;
|
|
||||||
$page->tags = $tags;
|
|
||||||
$page->content = $content;
|
|
||||||
echo $page->render('admin_wrap.php');
|
|
||||||
} else {
|
|
||||||
$page = new Template();
|
|
||||||
|
|
||||||
if (isset($_POST['username']) && isset($_POST['password'])) {
|
|
||||||
$ret_id = $db->authenticate($_POST["username"], $_POST["password"]);
|
|
||||||
if ($ret_id > 0) {
|
|
||||||
$_SESSION['ID'] = $ret_id;
|
|
||||||
$page->text = "You have logged in successfully.";
|
|
||||||
$page->redirect = "admin.php";
|
|
||||||
} else {
|
|
||||||
$page->text = "Username and/or password incorrect.";
|
|
||||||
$page->redirect = "/";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$page->text = "Please log in before accessing this page.";
|
|
||||||
$page->redirect = "/";
|
|
||||||
}
|
|
||||||
|
|
||||||
echo $page->render('full_text.php');
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,244 +0,0 @@
|
||||||
@font-face {
|
|
||||||
font-family: Prociono;
|
|
||||||
src: url(Prociono.woff);
|
|
||||||
}
|
|
||||||
|
|
||||||
*, *:before, *:after {
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: Prociono;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
background: #202020;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #202020;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar {
|
|
||||||
font-family: Prociono, serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar-head {
|
|
||||||
background-color: #f2f2f2;
|
|
||||||
color: #202020;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar-head > h1 {
|
|
||||||
padding: 0.5em;
|
|
||||||
margin: 0 0 1rem 0;;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar-taglist {
|
|
||||||
background: #f2f2f2;
|
|
||||||
color: #202020;
|
|
||||||
padding: 1rem 0 1rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar-taglist > ul > li {
|
|
||||||
list-style: none;
|
|
||||||
font-size: 14pt;
|
|
||||||
margin-bottom: .5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar-taglist > ul > li:before {
|
|
||||||
content: "/ ";
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar-taglist-top:before {
|
|
||||||
content: "\\ " !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar-taglist a {
|
|
||||||
color: #202020;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar-taglist ul:not(:last-child) {
|
|
||||||
padding-bottom: .5rem;
|
|
||||||
box-shadow: 0px 24px 0px -22px #202020;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content {
|
|
||||||
font-size: 14pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text {
|
|
||||||
background: #f2f2f2;
|
|
||||||
color: #202020;
|
|
||||||
padding: 1rem;
|
|
||||||
margin: 0 0 1rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.doc-item-text {
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.doc-item h2 {
|
|
||||||
font-size: 14pt;
|
|
||||||
font-weight: normal;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.doc-item h3 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 11pt;
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.doc-item-link {
|
|
||||||
display: inline-block;
|
|
||||||
float: right;
|
|
||||||
position: relative;
|
|
||||||
top: 7px;
|
|
||||||
right: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.doc-new-item {
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.doc-new-item a {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.document h1 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 24pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
.document h2 {
|
|
||||||
margin: 2pt 0 2pt 0;
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: 16pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
.document h3 {
|
|
||||||
margin: 2pt 0 2pt 0;
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: 16pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
.doc-taglist li {
|
|
||||||
list-style: none;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.doc-taglist li a {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.doc-taglist li:after {
|
|
||||||
content: "/";
|
|
||||||
}
|
|
||||||
|
|
||||||
.doc-taglist li:last-of-type:after {
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
|
|
||||||
.doc-description-intro, .doc-link-intro {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.doc-link-intro:before {
|
|
||||||
content: "➜ ";
|
|
||||||
}
|
|
||||||
|
|
||||||
.doc-link a {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag-edit-link {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="text"] {
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 64em ) {
|
|
||||||
#sidebar {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 2rem;
|
|
||||||
width: 14rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content {
|
|
||||||
margin: 2rem 2rem 0 18rem;
|
|
||||||
padding: 0 0 2rem 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 64em ) {
|
|
||||||
#sidebar-head {
|
|
||||||
background-position: 14%;
|
|
||||||
background-size: 4rem;
|
|
||||||
height: 7rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar-head > h1 {
|
|
||||||
padding-top: 1.5rem;
|
|
||||||
font-size: 3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar-taglist {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#login {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
right: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#login input {
|
|
||||||
height: 14pt;
|
|
||||||
border: 1px solid lightgray;
|
|
||||||
}
|
|
||||||
|
|
||||||
#login button {
|
|
||||||
height: 14pt;
|
|
||||||
font-size: 8pt;
|
|
||||||
border: 1px solid lightgray;
|
|
||||||
background: #202020;
|
|
||||||
}
|
|
||||||
|
|
||||||
.czech {
|
|
||||||
font-size: 12pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sign {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 16pt;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="submit"], input[type="file"] {
|
|
||||||
font-family: Prociono, serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
-webkit-appearance: button;
|
|
||||||
-moz-appearance: button;
|
|
||||||
appearance: button;
|
|
||||||
|
|
||||||
text-decoration: none;
|
|
||||||
color: initial;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"config": {
|
|
||||||
"vendor-dir": "_vendor"
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"erusev/parsedown": "^1.7",
|
|
||||||
"mpdf/mpdf": "^8.0",
|
|
||||||
"ext-sqlite3": "*"
|
|
||||||
}
|
|
||||||
}
|
|
336
www/composer.lock
generated
336
www/composer.lock
generated
|
@ -1,336 +0,0 @@
|
||||||
{
|
|
||||||
"_readme": [
|
|
||||||
"This file locks the dependencies of your project to a known state",
|
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
|
||||||
"This file is @generated automatically"
|
|
||||||
],
|
|
||||||
"content-hash": "07bcf0ebe745edf9a2aff62e65aae616",
|
|
||||||
"packages": [
|
|
||||||
{
|
|
||||||
"name": "erusev/parsedown",
|
|
||||||
"version": "1.7.3",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/erusev/parsedown.git",
|
|
||||||
"reference": "6d893938171a817f4e9bc9e86f2da1e370b7bcd7"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/erusev/parsedown/zipball/6d893938171a817f4e9bc9e86f2da1e370b7bcd7",
|
|
||||||
"reference": "6d893938171a817f4e9bc9e86f2da1e370b7bcd7",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"ext-mbstring": "*",
|
|
||||||
"php": ">=5.3.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"phpunit/phpunit": "^4.8.35"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"psr-0": {
|
|
||||||
"Parsedown": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Emanuil Rusev",
|
|
||||||
"email": "hello@erusev.com",
|
|
||||||
"homepage": "http://erusev.com"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Parser for Markdown.",
|
|
||||||
"homepage": "http://parsedown.org",
|
|
||||||
"keywords": [
|
|
||||||
"markdown",
|
|
||||||
"parser"
|
|
||||||
],
|
|
||||||
"time": "2019-03-17T18:48:37+00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "mpdf/mpdf",
|
|
||||||
"version": "v8.0.2",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/mpdf/mpdf.git",
|
|
||||||
"reference": "ab0662606cc2396015616633946f3b8918d818a7"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/mpdf/mpdf/zipball/ab0662606cc2396015616633946f3b8918d818a7",
|
|
||||||
"reference": "ab0662606cc2396015616633946f3b8918d818a7",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"ext-gd": "*",
|
|
||||||
"ext-mbstring": "*",
|
|
||||||
"myclabs/deep-copy": "^1.7",
|
|
||||||
"paragonie/random_compat": "^1.4|^2.0|9.99.99",
|
|
||||||
"php": "^5.6 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0",
|
|
||||||
"psr/log": "^1.0",
|
|
||||||
"setasign/fpdi": "^2.1"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"mockery/mockery": "^0.9.5",
|
|
||||||
"mpdf/qrcode": "^1.0.0",
|
|
||||||
"phpunit/phpunit": "^5.0",
|
|
||||||
"squizlabs/php_codesniffer": "^2.7.0",
|
|
||||||
"tracy/tracy": "^2.4"
|
|
||||||
},
|
|
||||||
"suggest": {
|
|
||||||
"ext-bcmath": "Needed for generation of some types of barcodes",
|
|
||||||
"ext-xml": "Needed mainly for SVG manipulation",
|
|
||||||
"ext-zlib": "Needed for compression of embedded resources, such as fonts"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-development": "7.x-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Mpdf\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"GPL-2.0-only"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Matěj Humpál",
|
|
||||||
"role": "Developer, maintainer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ian Back",
|
|
||||||
"role": "Developer (retired)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "PHP library generating PDF files from UTF-8 encoded HTML",
|
|
||||||
"homepage": "https://mpdf.github.io",
|
|
||||||
"keywords": [
|
|
||||||
"pdf",
|
|
||||||
"php",
|
|
||||||
"utf-8"
|
|
||||||
],
|
|
||||||
"time": "2019-06-17T09:03:49+00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "myclabs/deep-copy",
|
|
||||||
"version": "1.9.3",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
|
||||||
"reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea",
|
|
||||||
"reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": "^7.1"
|
|
||||||
},
|
|
||||||
"replace": {
|
|
||||||
"myclabs/deep-copy": "self.version"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"doctrine/collections": "^1.0",
|
|
||||||
"doctrine/common": "^2.6",
|
|
||||||
"phpunit/phpunit": "^7.1"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"DeepCopy\\": "src/DeepCopy/"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"src/DeepCopy/deep_copy.php"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"description": "Create deep copies (clones) of your objects",
|
|
||||||
"keywords": [
|
|
||||||
"clone",
|
|
||||||
"copy",
|
|
||||||
"duplicate",
|
|
||||||
"object",
|
|
||||||
"object graph"
|
|
||||||
],
|
|
||||||
"time": "2019-08-09T12:45:53+00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "paragonie/random_compat",
|
|
||||||
"version": "v9.99.99",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/paragonie/random_compat.git",
|
|
||||||
"reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
|
|
||||||
"reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": "^7"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"phpunit/phpunit": "4.*|5.*",
|
|
||||||
"vimeo/psalm": "^1"
|
|
||||||
},
|
|
||||||
"suggest": {
|
|
||||||
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Paragon Initiative Enterprises",
|
|
||||||
"email": "security@paragonie.com",
|
|
||||||
"homepage": "https://paragonie.com"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
|
|
||||||
"keywords": [
|
|
||||||
"csprng",
|
|
||||||
"polyfill",
|
|
||||||
"pseudorandom",
|
|
||||||
"random"
|
|
||||||
],
|
|
||||||
"time": "2018-07-02T15:55:56+00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "psr/log",
|
|
||||||
"version": "1.1.0",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/php-fig/log.git",
|
|
||||||
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
|
|
||||||
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": ">=5.3.0"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "1.0.x-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Psr\\Log\\": "Psr/Log/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "PHP-FIG",
|
|
||||||
"homepage": "http://www.php-fig.org/"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Common interface for logging libraries",
|
|
||||||
"homepage": "https://github.com/php-fig/log",
|
|
||||||
"keywords": [
|
|
||||||
"log",
|
|
||||||
"psr",
|
|
||||||
"psr-3"
|
|
||||||
],
|
|
||||||
"time": "2018-11-20T15:27:04+00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "setasign/fpdi",
|
|
||||||
"version": "v2.2.0",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/Setasign/FPDI.git",
|
|
||||||
"reference": "3c266002f8044f61b17329f7cd702d44d73f0f7f"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/Setasign/FPDI/zipball/3c266002f8044f61b17329f7cd702d44d73f0f7f",
|
|
||||||
"reference": "3c266002f8044f61b17329f7cd702d44d73f0f7f",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"ext-zlib": "*",
|
|
||||||
"php": "^5.6 || ^7.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"phpunit/phpunit": "~5.7",
|
|
||||||
"setasign/fpdf": "~1.8",
|
|
||||||
"setasign/tfpdf": "1.25",
|
|
||||||
"tecnickcom/tcpdf": "~6.2"
|
|
||||||
},
|
|
||||||
"suggest": {
|
|
||||||
"setasign/fpdf": "FPDI will extend this class but as it is also possible to use TCPDF or tFPDF as an alternative. There's no fixed dependency configured.",
|
|
||||||
"setasign/fpdi-fpdf": "Use this package to automatically evaluate dependencies to FPDF.",
|
|
||||||
"setasign/fpdi-tcpdf": "Use this package to automatically evaluate dependencies to TCPDF.",
|
|
||||||
"setasign/fpdi-tfpdf": "Use this package to automatically evaluate dependencies to tFPDF."
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"setasign\\Fpdi\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Jan Slabon",
|
|
||||||
"email": "jan.slabon@setasign.com",
|
|
||||||
"homepage": "https://www.setasign.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Maximilian Kresse",
|
|
||||||
"email": "maximilian.kresse@setasign.com",
|
|
||||||
"homepage": "https://www.setasign.com"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "FPDI is a collection of PHP classes facilitating developers to read pages from existing PDF documents and use them as templates in FPDF. Because it is also possible to use FPDI with TCPDF, there are no fixed dependencies defined. Please see suggestions for packages which evaluates the dependencies automatically.",
|
|
||||||
"homepage": "https://www.setasign.com/fpdi",
|
|
||||||
"keywords": [
|
|
||||||
"fpdf",
|
|
||||||
"fpdi",
|
|
||||||
"pdf"
|
|
||||||
],
|
|
||||||
"time": "2019-01-30T14:11:19+00:00"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"packages-dev": [],
|
|
||||||
"aliases": [],
|
|
||||||
"minimum-stability": "stable",
|
|
||||||
"stability-flags": [],
|
|
||||||
"prefer-stable": false,
|
|
||||||
"prefer-lowest": false,
|
|
||||||
"platform": {
|
|
||||||
"ext-sqlite3": "*"
|
|
||||||
},
|
|
||||||
"platform-dev": []
|
|
||||||
}
|
|
BIN
www/favicon.png
BIN
www/favicon.png
Binary file not shown.
Before Width: | Height: | Size: 6 KiB |
26
www/feed.php
26
www/feed.php
|
@ -1,26 +0,0 @@
|
||||||
<?php
|
|
||||||
require '_util/PileDB.php';
|
|
||||||
$db = new PileDB();
|
|
||||||
$recent_docs = $db->getRecentDocs();
|
|
||||||
|
|
||||||
header('Content-Type: application/rss+xml');
|
|
||||||
?>
|
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
|
||||||
|
|
||||||
<channel>
|
|
||||||
<title>/-\ pile</title>
|
|
||||||
<link>https://pile.sdbs.cz</link>
|
|
||||||
<atom:link href="https://pile.sdbs.cz/feed.php" rel="self" type="application/rss+xml" />
|
|
||||||
<description>A pile of interesting documents.</description>
|
|
||||||
|
|
||||||
<?php foreach ($recent_docs as $doc): ?>
|
|
||||||
<item>
|
|
||||||
<title><?= $doc['Title'] ?></title>
|
|
||||||
<guid>https://pile.sdbs.cz/?item=<?= $doc['ID'] ?></guid>
|
|
||||||
<link>https://pile.sdbs.cz/?item=<?= $doc['ID'] ?></link>
|
|
||||||
<description><?= $doc['Description'] ?></description>
|
|
||||||
</item>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</channel>
|
|
||||||
</rss>
|
|
|
@ -1,55 +0,0 @@
|
||||||
<?php
|
|
||||||
require '_templates/Template.php';
|
|
||||||
require '_util/PileDB.php';
|
|
||||||
|
|
||||||
$db = new PileDB();
|
|
||||||
session_start();
|
|
||||||
$page = new Template();
|
|
||||||
|
|
||||||
if (isset($_GET["item"])) {
|
|
||||||
try {
|
|
||||||
$doc = $db->fetchDoc($_GET["item"]);
|
|
||||||
} catch (NotFoundException $e) {
|
|
||||||
http_response_code(404);
|
|
||||||
$page->text = "Document not found.";
|
|
||||||
$page->redirect = "/";
|
|
||||||
echo $page->render("full_text.php");
|
|
||||||
die(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
$doc_template = new Template();
|
|
||||||
$doc_template->doc = $doc;
|
|
||||||
$selected_doc = $doc;
|
|
||||||
$content = $doc_template->render('front_doc_overview.php');
|
|
||||||
} elseif (isset($_GET["tag"])) {
|
|
||||||
$doc_list_template = new Template();
|
|
||||||
if ($_GET["tag"] == "*") {
|
|
||||||
$docs = $db->listDocs();
|
|
||||||
} elseif ($_GET["tag"] == "_") {
|
|
||||||
$docs = $db->listDocs(-1);
|
|
||||||
} else {
|
|
||||||
$tag = $db->fetchTag($_GET["tag"]);
|
|
||||||
if (!$tag) {
|
|
||||||
$tag = $db->findTag($_GET["tag"]);
|
|
||||||
}
|
|
||||||
$docs = $db->listDocs($tag["ID"]);
|
|
||||||
$selected_tag = $tag;
|
|
||||||
$doc_list_template->tag = $tag;
|
|
||||||
}
|
|
||||||
$doc_list_template->docs = $docs;
|
|
||||||
$content = $doc_list_template->render('front_doc_listing.php');
|
|
||||||
} else {
|
|
||||||
$intro_template = new Template();
|
|
||||||
$intro_template->recent_docs = $db->getRecentDocs();
|
|
||||||
$content = $intro_template->render('front_intro.php');
|
|
||||||
}
|
|
||||||
|
|
||||||
$page->doc_count = $db->getDocCount();
|
|
||||||
$page->none_count = $db->getUntaggedDocCount();
|
|
||||||
$page->tags = $db->getTags();
|
|
||||||
$page->content = $content;
|
|
||||||
$page->logged = isset($_SESSION["ID"]);
|
|
||||||
$page->selected_doc = $selected_doc;
|
|
||||||
$page->selected_tag = $selected_tag;
|
|
||||||
echo $page->render('front_wrap.php');
|
|
||||||
?>
|
|
|
@ -1,65 +0,0 @@
|
||||||
<?php
|
|
||||||
require '_vendor/autoload.php';
|
|
||||||
|
|
||||||
require '_templates/Template.php';
|
|
||||||
require '_util/PileDB.php';
|
|
||||||
|
|
||||||
|
|
||||||
$db = new PileDB();
|
|
||||||
try {
|
|
||||||
$doc = $db->fetchDoc($_GET["id"]);
|
|
||||||
} catch (NotFoundException $e) {
|
|
||||||
http_response_code(404);
|
|
||||||
$page->text = "Document not found.";
|
|
||||||
$page->redirect = "/";
|
|
||||||
echo $page->render("full_text.php");
|
|
||||||
die(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
$front = new Template();
|
|
||||||
$front->doc = $doc;
|
|
||||||
|
|
||||||
$defaultConfig = (new \Mpdf\Config\ConfigVariables())->getDefaults();
|
|
||||||
$fontDirs = $defaultConfig['fontDir'];
|
|
||||||
$defaultFontConfig = (new \Mpdf\Config\FontVariables())->getDefaults();
|
|
||||||
$fontData = $defaultFontConfig['fontdata'];
|
|
||||||
try {
|
|
||||||
$mpdf = new \Mpdf\Mpdf([
|
|
||||||
'format' => 'A4',
|
|
||||||
'fontDir' => array_merge($fontDirs, [
|
|
||||||
__DIR__ . '/assets',
|
|
||||||
]),
|
|
||||||
'fontdata' => $fontData + [
|
|
||||||
'prociono' => [
|
|
||||||
'R' => 'Prociono-Regular.ttf',
|
|
||||||
]
|
|
||||||
],
|
|
||||||
'default_font' => 'prociono'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$mpdf->showImageErrors = true;
|
|
||||||
$mpdf->WriteHTML($front->render("_templates/label_template.php"));
|
|
||||||
try {
|
|
||||||
if (preg_match('#^https?://pile.sdbs.cz/.*\.(pdf|PDF)$#', $doc['URL']) === 1) {
|
|
||||||
$tempName = tempnam("/tmp/", 'pile-merge');
|
|
||||||
file_put_contents($tempName, file_get_contents($doc["URL"]));
|
|
||||||
$pageCount = $mpdf->SetSourceFile($tempName);
|
|
||||||
|
|
||||||
for ($page = 1; $page <= $pageCount; $page++) {
|
|
||||||
$mpdf->AddPage();
|
|
||||||
$template = $mpdf->ImportPage($page);
|
|
||||||
$mpdf->UseTemplate($template);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception $exception) {
|
|
||||||
// noop
|
|
||||||
} finally {
|
|
||||||
unlink($tempName);
|
|
||||||
}
|
|
||||||
|
|
||||||
$mpdf->Output();
|
|
||||||
} catch (Exception $exception) {
|
|
||||||
http_response_code(500); ?>
|
|
||||||
<h1>Something went wrong generating the label.</h1>
|
|
||||||
<pre><?= $exception->getMessage() ?></pre>
|
|
||||||
<?php } ?>
|
|
Loading…
Reference in a new issue