Compare commits
No commits in common. "61cee697e4145266284674703d311617f841b0fe" and "a28b6ce4b372c08ed7f4124938d059fbffc9f0aa" have entirely different histories.
61cee697e4
...
a28b6ce4b3
@ -1,32 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
steps:
|
|
||||||
create_docker_image:
|
|
||||||
image: woodpeckerci/plugin-docker-buildx
|
|
||||||
secrets: [ docker_username, docker_password ]
|
|
||||||
settings:
|
|
||||||
repo: moanos/sphinx-rtd
|
|
||||||
dockerfile: docs/Dockerfile
|
|
||||||
tag: latest
|
|
||||||
|
|
||||||
build:
|
|
||||||
image: moanos/sphinx-rtd
|
|
||||||
commands:
|
|
||||||
- cd docs && make html
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
image: appleboy/drone-scp
|
|
||||||
settings:
|
|
||||||
strip_components: 3
|
|
||||||
host:
|
|
||||||
from_secret: host
|
|
||||||
username:
|
|
||||||
from_secret: ssh_user
|
|
||||||
target:
|
|
||||||
from_secret: path
|
|
||||||
source: docs/_build/html/
|
|
||||||
key:
|
|
||||||
from_secret: ssh_key
|
|
||||||
|
|
||||||
|
|
||||||
|
|
1
docs/.gitignore
vendored
1
docs/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
_build/
|
|
@ -1,30 +0,0 @@
|
|||||||
*****************
|
|
||||||
API Documentation
|
|
||||||
*****************
|
|
||||||
|
|
||||||
The Notfellchen API serves the purpose of supporting 3rd-person applications and anything you can think of basically.
|
|
||||||
|
|
||||||
.. warning::
|
|
||||||
The current API is limited in it's functionality. I you miss a specific feature please contact the developer!
|
|
||||||
|
|
||||||
API Access
|
|
||||||
==========
|
|
||||||
|
|
||||||
Via browser
|
|
||||||
-----------
|
|
||||||
|
|
||||||
When a user is logged in, they can easily access the API in their browser, authenticated by their session.
|
|
||||||
The API endpoint can be found at /library/api/
|
|
||||||
http://notfellchen.org/
|
|
||||||
|
|
||||||
Via token
|
|
||||||
---------
|
|
||||||
|
|
||||||
.. warning::
|
|
||||||
This is currently not supported.
|
|
||||||
|
|
||||||
All users are able to generate a token that allows them to use the API. This can be done in the user's profile.
|
|
||||||
An application can then send this token in the request header for authorization.
|
|
||||||
|
|
||||||
.. code-block::
|
|
||||||
$ curl -X GET http://notfellchen.org/api/adoption_notice -H 'Authorization: Token 49b39856955dc6e5cc04365498d4ad30ea3aed78'
|
|
@ -1,5 +0,0 @@
|
|||||||
FROM sphinxdoc/sphinx
|
|
||||||
|
|
||||||
WORKDIR /docs
|
|
||||||
ADD requirements.txt /docs
|
|
||||||
RUN pip3 install -r requirements.txt
|
|
@ -1,19 +0,0 @@
|
|||||||
# Minimal makefile for Sphinx documentation
|
|
||||||
#
|
|
||||||
|
|
||||||
# You can set these variables from the command line.
|
|
||||||
SPHINXOPTS =
|
|
||||||
SPHINXBUILD = sphinx-build
|
|
||||||
SOURCEDIR = .
|
|
||||||
BUILDDIR = _build
|
|
||||||
|
|
||||||
# Put it first so that "make" without argument is like "make help".
|
|
||||||
help:
|
|
||||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
||||||
|
|
||||||
.PHONY: help Makefile
|
|
||||||
|
|
||||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
|
||||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
|
||||||
%: Makefile
|
|
||||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
@ -1,89 +0,0 @@
|
|||||||
# QZT Dokumentation
|
|
||||||
|
|
||||||
![Deploy Status](https://woodpecker.hyteck.de/api/badges/103/status.svg)
|
|
||||||
|
|
||||||
# Quickstart
|
|
||||||
|
|
||||||
Create & activate a virtual environment to avoid cluttering your system
|
|
||||||
|
|
||||||
```zsh
|
|
||||||
python -m venv venv
|
|
||||||
source venv/bin/activate
|
|
||||||
```
|
|
||||||
|
|
||||||
Install dependencies
|
|
||||||
|
|
||||||
```zsh
|
|
||||||
pip install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
And serve a local development version
|
|
||||||
|
|
||||||
```zsh
|
|
||||||
cd docs
|
|
||||||
sphinx-autobuild ./ ./_build/html
|
|
||||||
```
|
|
||||||
|
|
||||||
You can now access the documentation on [http://127.0.0.1:8000](http://127.0.0.1:8000). It will be rebuilt automatically upon file changes.
|
|
||||||
|
|
||||||
If you only want to build the static files once you can do `make html`.
|
|
||||||
|
|
||||||
## Docker
|
|
||||||
|
|
||||||
Build the docker image with
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker build . -t sphinx-qzt
|
|
||||||
```
|
|
||||||
|
|
||||||
and use it to build the documentation like this
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run --rm -v ./docs:/docs sphinx-qzt make html
|
|
||||||
```
|
|
||||||
|
|
||||||
# QZT Dokumentation
|
|
||||||
|
|
||||||
# Quickstart
|
|
||||||
|
|
||||||
Create & activate a virtual environment to avoid cluttering your system
|
|
||||||
|
|
||||||
```zsh
|
|
||||||
python -m venv venv
|
|
||||||
source venv/bin/activate
|
|
||||||
```
|
|
||||||
|
|
||||||
Install dependencies
|
|
||||||
|
|
||||||
```zsh
|
|
||||||
pip install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
And serve a local development version
|
|
||||||
|
|
||||||
```zsh
|
|
||||||
cd docs
|
|
||||||
sphinx-autobuild ./ ./_build/html
|
|
||||||
```
|
|
||||||
|
|
||||||
You can now access the documentation on <http://127.0.0.1:8000>. It will be rebuilt automatically upon file changes.
|
|
||||||
|
|
||||||
If you only want to build the static files once you can do `make html`.
|
|
||||||
|
|
||||||
## Docker
|
|
||||||
|
|
||||||
Build the docker image with
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker build . -t sphinx-rtd
|
|
||||||
```
|
|
||||||
|
|
||||||
and use it to build the documentation like this
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run --rm -v ./docs:/docs sphinx-rtd make html
|
|
||||||
```
|
|
||||||
|
|
||||||
# CI
|
|
||||||
|
|
||||||
Woodpecker can be used to deploy the documentation to a server
|
|
@ -1,38 +0,0 @@
|
|||||||
GDPR
|
|
||||||
====
|
|
||||||
|
|
||||||
The GDPR provides the user with different rights regarding their data and Notfellchen tries to help you fulfill these requirements.
|
|
||||||
For this application there are different scenarios that are applicable.
|
|
||||||
|
|
||||||
Transparency and Modality
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
The user must be informed in a "in a concise, transparent, intelligible and easily accessible form,
|
|
||||||
using clear and plain language". This is currently up to you, to provide an imprint with such information.
|
|
||||||
|
|
||||||
Information and Access
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
Article 15 gives the user the right to access their personal data and information about how this personal data is being
|
|
||||||
processed, specifically the purpose of the processing (Article 15(1)(a)), with whom the data is shared
|
|
||||||
(Article 15(1)(c)), and how it acquired the data (Article 15(1)(g)).
|
|
||||||
|
|
||||||
For Notfellchen this could be a short description::
|
|
||||||
|
|
||||||
Notfellchen processes your data to provide you with the functionality of the plattform, like creation of adoption notices.
|
|
||||||
Your data is not given to third parties. Your data was provided by you or added by staff/automatically if you consented to this.
|
|
||||||
It is also possible that there is data of you accessing resources of this program to prevent malicious activity and to improve the software in it's functionality.
|
|
||||||
|
|
||||||
The right to access the data can easily fulfilled with Notfellchen, a user can always request a copy of their data in their profile.
|
|
||||||
|
|
||||||
Rectification and erasure
|
|
||||||
-------------------------
|
|
||||||
Article 17 provides that the data subject has the right to request erasure of personal data related to them on any one of a number of grounds within 30 days.
|
|
||||||
This is currently not implemented by he software and has to be done by administrators manually.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. warning::
|
|
||||||
|
|
||||||
All content on this website is intended for general information only, and should not be construed as legal advice.
|
|
||||||
Please seek a lawyer.
|
|
@ -1,28 +0,0 @@
|
|||||||
# Global tags can be specified here in key="value" format.
|
|
||||||
[global_tags]
|
|
||||||
|
|
||||||
|
|
||||||
# Configuration for telegraf agent
|
|
||||||
[agent]
|
|
||||||
interval = "10s"
|
|
||||||
round_interval = true
|
|
||||||
metric_batch_size = 1000
|
|
||||||
metric_buffer_limit = 10000
|
|
||||||
collection_jitter = "0s"
|
|
||||||
flush_interval = "10s"
|
|
||||||
flush_jitter = "0s"
|
|
||||||
|
|
||||||
# Configuration for sending metrics to InfluxDB
|
|
||||||
[[outputs.influxdb]]
|
|
||||||
urls = ["http://:::8086"]
|
|
||||||
database = "telegraf"
|
|
||||||
skip_database_creation = true
|
|
||||||
username = 'telegraf'
|
|
||||||
password = 'yourpassword'
|
|
||||||
|
|
||||||
[[inputs.http]]
|
|
||||||
urls = ["https://notfellchen.org/metrics/"]
|
|
||||||
name_override = "notfellchen"
|
|
||||||
#Data from HTTP in JSON format
|
|
||||||
data_format = "json"
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
|||||||
Administration
|
|
||||||
--------------
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
:caption: Contents:
|
|
||||||
|
|
||||||
create_user.rst
|
|
||||||
lending.rst
|
|
||||||
returning.rst
|
|
||||||
opening_hours.rst
|
|
||||||
add_items.rst
|
|
||||||
monitoring.rst
|
|
@ -1,62 +0,0 @@
|
|||||||
Monitoring
|
|
||||||
==========
|
|
||||||
|
|
||||||
ILMO should, like every other software, be easy to monitor. Therefore a basic metrics are exposed to `https://notfellchen.org/metrics`.
|
|
||||||
The data is encoded in JSON format and is therefore suitable to bea read by humans and it is easy to use it as data source for further processing.
|
|
||||||
|
|
||||||
|
|
||||||
Exposed Metrics
|
|
||||||
---------------
|
|
||||||
|
|
||||||
.. code::
|
|
||||||
|
|
||||||
users: number of users (all roles combined)
|
|
||||||
staff: number of users with staff status
|
|
||||||
adoption_notices: number of adoption notices
|
|
||||||
adoption_notices_by_status: number of adoption notices by major status
|
|
||||||
adoption_notices_without_location: number of location notices that are not geocoded
|
|
||||||
|
|
||||||
Example workflow
|
|
||||||
----------------
|
|
||||||
|
|
||||||
To use the exposed metrics you will usually need a time series database and a visualization tool.
|
|
||||||
|
|
||||||
As time series database we will utilize InfluxDB, the visualization tool will be Grafana.
|
|
||||||
|
|
||||||
InfluxDB and Telegraf
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
First we install InfluxDB (e.g. with docker, be aware of the security risks!).
|
|
||||||
|
|
||||||
.. code::
|
|
||||||
|
|
||||||
# Pull the image
|
|
||||||
$ sudo docker pull influxdb
|
|
||||||
|
|
||||||
# Start influxdb
|
|
||||||
$ sudo docker run -d -p 8086:8086 -v influxdb:/var/lib/influxdb --name influxdb influxdb
|
|
||||||
|
|
||||||
# Start influxdb console
|
|
||||||
$ docker exec -it influxdb influx
|
|
||||||
Connected to http://localhost:8086 version 1.8.3
|
|
||||||
InfluxDB shell version: 1.8.3
|
|
||||||
> create database monitoring
|
|
||||||
> create user "telegraf" with password 'mypassword'
|
|
||||||
> grant all on monitoring to telegraf
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
When creating the user telegraf check the double and single quotes for username an password.
|
|
||||||
|
|
||||||
Now install telegraf and configure `etc/telegraf/telegraf.conf`. Modify the domain and your password for the InfluxDB database.
|
|
||||||
|
|
||||||
.. literalinclude:: example.telegraf.conf
|
|
||||||
:linenos:
|
|
||||||
:language: python
|
|
||||||
|
|
||||||
Graphana
|
|
||||||
^^^^^^^^
|
|
||||||
|
|
||||||
Now we can simply use the InfluxDB as data source in Grafana and configure until you have
|
|
||||||
beautiful plots!
|
|
||||||
|
|
||||||
.. image:: monitoring_grafana.png
|
|
Binary file not shown.
Before Width: | Height: | Size: 116 KiB |
@ -1,10 +0,0 @@
|
|||||||
Opening hours
|
|
||||||
=============
|
|
||||||
|
|
||||||
The opening hours can be changed by selecting the page :guilabel:`Opening hours` in the navigation menu.
|
|
||||||
You can not change an entry, simply delete it and create a new one.
|
|
||||||
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
It is advised to fill empty time cells with a "-".
|
|
@ -1,8 +0,0 @@
|
|||||||
Returning
|
|
||||||
=========
|
|
||||||
|
|
||||||
To return an item either visit the page :guilabel:`All loans` and search
|
|
||||||
for the loan there or you search for the item via :guilabel:`Search`.
|
|
||||||
|
|
||||||
If you found the loan, you can simply click on the button :guilabel:`Return` and
|
|
||||||
you are finished.
|
|
177
docs/conf.py
177
docs/conf.py
@ -1,177 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# Configuration file for the Sphinx documentation builder.
|
|
||||||
#
|
|
||||||
# This file does only contain a selection of the most common options. For a
|
|
||||||
# full list see the documentation:
|
|
||||||
# http://www.sphinx-doc.org/en/master/config
|
|
||||||
|
|
||||||
# -- Path setup --------------------------------------------------------------
|
|
||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
|
||||||
#
|
|
||||||
# import os
|
|
||||||
# import sys
|
|
||||||
# sys.path.insert(0, os.path.abspath('.'))
|
|
||||||
|
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
|
||||||
|
|
||||||
project = 'Notfellchen'
|
|
||||||
copyright = 'Julian-Samuel Gebühr'
|
|
||||||
author = 'Julian-Samuel Gebühr'
|
|
||||||
|
|
||||||
# The short X.Y version
|
|
||||||
version = ''
|
|
||||||
# The full version, including alpha/beta/rc tags
|
|
||||||
release = '0.2.0'
|
|
||||||
|
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
|
||||||
|
|
||||||
# If your documentation needs a minimal Sphinx version, state it here.
|
|
||||||
#
|
|
||||||
# needs_sphinx = '1.0'
|
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
|
||||||
# ones.
|
|
||||||
extensions = [
|
|
||||||
'sphinx.ext.ifconfig',
|
|
||||||
]
|
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
|
||||||
templates_path = ['_templates']
|
|
||||||
|
|
||||||
# The suffix(es) of source filenames.
|
|
||||||
# You can specify multiple suffix as a list of string:
|
|
||||||
#
|
|
||||||
# source_suffix = ['.rst', '.md']
|
|
||||||
source_suffix = '.rst'
|
|
||||||
|
|
||||||
# The master toctree document.
|
|
||||||
master_doc = 'index'
|
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
|
||||||
# for a list of supported languages.
|
|
||||||
#
|
|
||||||
# This is also used if you do content translation via gettext catalogs.
|
|
||||||
# Usually you set "language" from the command line for these cases.
|
|
||||||
language = "en"
|
|
||||||
|
|
||||||
# List of patterns, relative to source directory, that match files and
|
|
||||||
# directories to ignore when looking for source files.
|
|
||||||
# This pattern also affects html_static_path and html_extra_path.
|
|
||||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
|
||||||
pygments_style = None
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTML output -------------------------------------------------
|
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
|
||||||
# a list of builtin themes.
|
|
||||||
#
|
|
||||||
html_theme = 'sphinx_rtd_theme'
|
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
|
||||||
# further. For a list of options available for each theme, see the
|
|
||||||
# documentation.
|
|
||||||
#
|
|
||||||
# html_theme_options = {}
|
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
|
||||||
html_static_path = ['_static']
|
|
||||||
|
|
||||||
# Custom sidebar templates, must be a dictionary that maps document names
|
|
||||||
# to template names.
|
|
||||||
#
|
|
||||||
# The default sidebars (for documents that don't match any pattern) are
|
|
||||||
# defined by theme itself. Builtin themes are using these templates by
|
|
||||||
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
|
||||||
# 'searchbox.html']``.
|
|
||||||
#
|
|
||||||
# html_sidebars = {}
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTMLHelp output ---------------------------------------------
|
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
|
||||||
htmlhelp_basename = 'notfellchen'
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for LaTeX output ------------------------------------------------
|
|
||||||
|
|
||||||
latex_elements = {
|
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
|
||||||
#
|
|
||||||
# 'papersize': 'letterpaper',
|
|
||||||
|
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
|
||||||
#
|
|
||||||
# 'pointsize': '10pt',
|
|
||||||
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
|
||||||
#
|
|
||||||
# 'preamble': '',
|
|
||||||
|
|
||||||
# Latex figure (float) alignment
|
|
||||||
#
|
|
||||||
# 'figure_align': 'htbp',
|
|
||||||
}
|
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
|
||||||
# (source start file, target name, title,
|
|
||||||
# author, documentclass [howto, manual, or own class]).
|
|
||||||
latex_documents = [
|
|
||||||
(master_doc, 'notfellchen.tex', 'Notfellchen Dokumentation',
|
|
||||||
'Julian-Samuel Gebühr', 'manual'),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for manual page output ------------------------------------------
|
|
||||||
|
|
||||||
# One entry per manual page. List of tuples
|
|
||||||
# (source start file, name, description, authors, manual section).
|
|
||||||
man_pages = [
|
|
||||||
(master_doc, 'notfellchen', 'Notfellchen Dokumentation',
|
|
||||||
[author], 1)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for Texinfo output ----------------------------------------------
|
|
||||||
|
|
||||||
# Grouping the document tree into Texinfo files. List of tuples
|
|
||||||
# (source start file, target name, title, author,
|
|
||||||
# dir menu entry, description, category)
|
|
||||||
texinfo_documents = [
|
|
||||||
(master_doc, 'Notfellchen', 'Notfellchen Documentation',
|
|
||||||
author, 'Notfellchen', 'App für die Vermittlung von Tieren aus Tierschutz.',
|
|
||||||
'Miscellaneous'),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for Epub output -------------------------------------------------
|
|
||||||
|
|
||||||
# Bibliographic Dublin Core info.
|
|
||||||
epub_title = project
|
|
||||||
|
|
||||||
# The unique identifier of the text. This can be a ISBN number
|
|
||||||
# or the project homepage.
|
|
||||||
#
|
|
||||||
# epub_identifier = ''
|
|
||||||
|
|
||||||
# A unique identification for the text.
|
|
||||||
#
|
|
||||||
# epub_uid = ''
|
|
||||||
|
|
||||||
# A list of files that should not be packed into the epub file.
|
|
||||||
epub_exclude_files = ['search.html']
|
|
||||||
|
|
||||||
|
|
||||||
# -- Extension configuration -------------------------------------------------
|
|
@ -1,210 +0,0 @@
|
|||||||
Backup & Restore
|
|
||||||
****************
|
|
||||||
|
|
||||||
If you do no heavy modification of the code you should be fine with backing up :file:`/etc/notfellchen/` and the database.
|
|
||||||
Assuming you used a PostgreSQL database the following solution might help you with backups and restores.
|
|
||||||
|
|
||||||
Backup
|
|
||||||
++++++
|
|
||||||
|
|
||||||
The following code is a modification of `this script <https://wiki.postgresql.org/wiki/Automated_Backup_on_Linux>`_
|
|
||||||
licensed under the :ref:`postgresql_license`.
|
|
||||||
|
|
||||||
You will first need to create a backup configuration at :file:`/var/notfellchen/pg_backup.config`.
|
|
||||||
|
|
||||||
.. code-block::
|
|
||||||
|
|
||||||
##############################
|
|
||||||
## POSTGRESQL BACKUP CONFIG ##
|
|
||||||
##############################
|
|
||||||
|
|
||||||
# Optional system user to run backups as. If the user the script is running as doesn't match this
|
|
||||||
# the script terminates. Leave blank to skip check.
|
|
||||||
BACKUP_USER=notfellchen
|
|
||||||
|
|
||||||
# Optional hostname to adhere to pg_hba policies. Will default to "localhost" if none specified.
|
|
||||||
HOSTNAME=localhost
|
|
||||||
|
|
||||||
# Optional username to connect to database as. Will default to "postgres" if none specified.
|
|
||||||
USERNAME=notfellchen
|
|
||||||
|
|
||||||
# This dir will be created if it doesn't exist. This must be writable by the user the script is
|
|
||||||
# running as.
|
|
||||||
BACKUP_DIR=/var/notfellchen/backups/postgresql
|
|
||||||
|
|
||||||
# Enter database to backup
|
|
||||||
DATABSE=notfellchen
|
|
||||||
|
|
||||||
|
|
||||||
#### SETTINGS FOR ROTATED BACKUPS ####
|
|
||||||
|
|
||||||
# Which day to take the weekly backup from (1-7 = Monday-Sunday)
|
|
||||||
DAY_OF_WEEK_TO_KEEP=7
|
|
||||||
|
|
||||||
# Number of days to keep daily backups
|
|
||||||
DAYS_TO_KEEP=7
|
|
||||||
|
|
||||||
# How many weeks to keep weekly backups
|
|
||||||
WEEKS_TO_KEEP=5
|
|
||||||
|
|
||||||
######################################
|
|
||||||
|
|
||||||
And then add the script that will do the actual backup at :file:`/var/notfellchen/backup_rotate.sh`
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
###########################
|
|
||||||
####### LOAD CONFIG #######
|
|
||||||
###########################
|
|
||||||
|
|
||||||
while [ $# -gt 0 ]; do
|
|
||||||
case $1 in
|
|
||||||
-c)
|
|
||||||
CONFIG_FILE_PATH="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
${ECHO} "Unknown Option \"$1\"" 1>&2
|
|
||||||
exit 2
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -z $CONFIG_FILE_PATH ] ; then
|
|
||||||
SCRIPTPATH=$(cd ${0%/*} && pwd -P)
|
|
||||||
CONFIG_FILE_PATH="${SCRIPTPATH}/pg_backup.config"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -r ${CONFIG_FILE_PATH} ] ; then
|
|
||||||
echo "Could not load config file from ${CONFIG_FILE_PATH}" 1>&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
source "${CONFIG_FILE_PATH}"
|
|
||||||
|
|
||||||
###########################
|
|
||||||
#### PRE-BACKUP CHECKS ####
|
|
||||||
###########################
|
|
||||||
|
|
||||||
# Make sure we're running as the required backup user
|
|
||||||
if [ "$BACKUP_USER" != "" -a "$(id -un)" != "$BACKUP_USER" ] ; then
|
|
||||||
echo "This script must be run as $BACKUP_USER. Exiting." 1>&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
###########################
|
|
||||||
### INITIALISE DEFAULTS ###
|
|
||||||
###########################
|
|
||||||
|
|
||||||
if [ ! $HOSTNAME ]; then
|
|
||||||
HOSTNAME="localhost"
|
|
||||||
fi;
|
|
||||||
|
|
||||||
if [ ! $USERNAME ]; then
|
|
||||||
USERNAME="postgres"
|
|
||||||
fi;
|
|
||||||
|
|
||||||
|
|
||||||
###########################
|
|
||||||
#### START THE BACKUPS ####
|
|
||||||
###########################
|
|
||||||
|
|
||||||
function perform_backups()
|
|
||||||
{
|
|
||||||
SUFFIX=$1
|
|
||||||
FINAL_BACKUP_DIR=$BACKUP_DIR"`date +\%Y-\%m-\%d`$SUFFIX/"
|
|
||||||
|
|
||||||
echo "Making backup directory in $FINAL_BACKUP_DIR"
|
|
||||||
|
|
||||||
if ! mkdir -p $FINAL_BACKUP_DIR; then
|
|
||||||
echo "Cannot create backup directory in $FINAL_BACKUP_DIR. Go and fix it!" 1>&2
|
|
||||||
exit 1;
|
|
||||||
fi;
|
|
||||||
|
|
||||||
#######################
|
|
||||||
### GLOBALS BACKUPS ###
|
|
||||||
#######################
|
|
||||||
|
|
||||||
echo -e "\n\nPerforming backup"
|
|
||||||
echo -e "--------------------------------------------\n"
|
|
||||||
|
|
||||||
echo "Backup"
|
|
||||||
|
|
||||||
set -o pipefail
|
|
||||||
if ! pg_dump $DATABASE | gzip > $FINAL_BACKUP_DIR"$DATABASE".sql.gz.in_progress; then
|
|
||||||
echo "[!!ERROR!!] Failed to produce globals backup" 1>&2
|
|
||||||
else
|
|
||||||
mv $FINAL_BACKUP_DIR"$DATABASE".sql.gz.in_progress $FINAL_BACKUP_DIR"$DATABSE".sql.gz
|
|
||||||
fi
|
|
||||||
set +o pipefail
|
|
||||||
|
|
||||||
echo -e "\nAll database backups complete!"
|
|
||||||
}
|
|
||||||
|
|
||||||
# MONTHLY BACKUPS
|
|
||||||
|
|
||||||
DAY_OF_MONTH=`date +%d`
|
|
||||||
|
|
||||||
if [ $DAY_OF_MONTH -eq 1 ];
|
|
||||||
then
|
|
||||||
# Delete all expired monthly directories
|
|
||||||
find $BACKUP_DIR -maxdepth 1 -name "*-monthly" -exec rm -rf '{}' ';'
|
|
||||||
|
|
||||||
perform_backups "-monthly"
|
|
||||||
|
|
||||||
exit 0;
|
|
||||||
fi
|
|
||||||
|
|
||||||
# WEEKLY BACKUPS
|
|
||||||
|
|
||||||
DAY_OF_WEEK=`date +%u` #1-7 (Monday-Sunday)
|
|
||||||
EXPIRED_DAYS=`expr $((($WEEKS_TO_KEEP * 7) + 1))`
|
|
||||||
|
|
||||||
if [ $DAY_OF_WEEK = $DAY_OF_WEEK_TO_KEEP ];
|
|
||||||
then
|
|
||||||
# Delete all expired weekly directories
|
|
||||||
find $BACKUP_DIR -maxdepth 1 -mtime +$EXPIRED_DAYS -name "*-weekly" -exec rm -rf '{}' ';'
|
|
||||||
|
|
||||||
perform_backups "-weekly"
|
|
||||||
|
|
||||||
exit 0;
|
|
||||||
fi
|
|
||||||
|
|
||||||
# DAILY BACKUPS
|
|
||||||
|
|
||||||
# Delete daily backups 7 days old or more
|
|
||||||
find $BACKUP_DIR -maxdepth 1 -mtime +$DAYS_TO_KEEP -name "*-daily" -exec rm -rf '{}' ';'
|
|
||||||
|
|
||||||
perform_backups "-daily"
|
|
||||||
|
|
||||||
|
|
||||||
You should make the script executable test it and automate the execution with :program:`crontab`
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ chmod +x backup_rotate.sh
|
|
||||||
$ ./backup_rotate.sh
|
|
||||||
$ crontab -e
|
|
||||||
# enter the following to backup every day at 3am
|
|
||||||
0 3 * * * /var/notfellchen/backup_rotate.sh
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Restore
|
|
||||||
+++++++
|
|
||||||
|
|
||||||
If you for any reason want to restore a backup you can use the following:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ sudo systemctl stop notfellchen
|
|
||||||
$ pg_dump notfellchen > notfellchen_YYYY_MM_DD-hh_mm.psql # Make a backup for later analysis
|
|
||||||
$ dropdb notfellchen
|
|
||||||
$ cd /path/to/backup
|
|
||||||
$ gzip -d notfellchen.sql.gz
|
|
||||||
$ sudo -u postgres createdb -O notfellchen notfellchen
|
|
||||||
$ psql notfellchen < notfellchen.sql
|
|
||||||
$ systemctl restart notfellchen
|
|
@ -1,39 +0,0 @@
|
|||||||
Contributing
|
|
||||||
------------
|
|
||||||
|
|
||||||
Report a bug
|
|
||||||
^^^^^^^^^^^^
|
|
||||||
|
|
||||||
To report a bug, file an issue on `Github
|
|
||||||
<https://codeberg.org/moanos/notfellchen/issues>`_
|
|
||||||
|
|
||||||
Try to include the following information:
|
|
||||||
|
|
||||||
- The information needed to reproduce the problem
|
|
||||||
- What you would expect to happen
|
|
||||||
- What did actually happen
|
|
||||||
- Error messages
|
|
||||||
|
|
||||||
You are also invited to include:
|
|
||||||
|
|
||||||
- Screenshots
|
|
||||||
- Which browser you are using
|
|
||||||
- The URL of the site
|
|
||||||
- How urgent it is
|
|
||||||
- Any additional information you consider useful
|
|
||||||
|
|
||||||
Get involved!
|
|
||||||
^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
To contribute simply clone the directory, make your changes and file a
|
|
||||||
pull request.
|
|
||||||
|
|
||||||
If you want to know what can be done, have a look at the current `Github
|
|
||||||
<https://codeberg.org/moanos/notfellchen/issues>`_.
|
|
||||||
|
|
||||||
Get in touch!
|
|
||||||
^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
If you have questions, want to contribute or want to message me regarding something else
|
|
||||||
you can find contact information at https://hyteck.de/about/ or directly write
|
|
||||||
an `E-Mail <mailto:info@notfellchen.org>`_
|
|
@ -1,261 +0,0 @@
|
|||||||
.. highlight:: none
|
|
||||||
|
|
||||||
**********
|
|
||||||
Deployment
|
|
||||||
**********
|
|
||||||
|
|
||||||
There are different ways to deploy ILMO. We support an ansible+docker based deployment and manual installation.
|
|
||||||
|
|
||||||
Ansible deployment
|
|
||||||
==================
|
|
||||||
|
|
||||||
ILMO can be deployed with the `ilmo-ansible-role <https://github.com/moan0s/ansible-role-ilmo>`_ that is based on the
|
|
||||||
official ILMO docker image. This role will only install ilmo itself. If you want a complete setup that includes a
|
|
||||||
database and a webserver with minimal configuration you can use the
|
|
||||||
`mash-playbook <https://github.com/mother-of-all-self-hosting/mash-playbook>`_ by following `it's documentation
|
|
||||||
on ILMO <https://github.com/mother-of-all-self-hosting/mash-playbook/blob/main/docs/services/ilmo.md>`_.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Manual Deployment
|
|
||||||
=================
|
|
||||||
|
|
||||||
|
|
||||||
This guide describes the installation of a installation of ILMO from source. It is inspired by this great guide from
|
|
||||||
pretix_.
|
|
||||||
|
|
||||||
.. warning:: Even though this guide tries to make it as straightforward to run ILMO, it still requires some Linux experience to
|
|
||||||
get it right. If you're not feeling comfortable managing a Linux server, check out a managed service_.
|
|
||||||
|
|
||||||
This guide is tested on **Ubuntu20.04** but it should work very similar on other modern systemd based distributions.
|
|
||||||
|
|
||||||
Requirements
|
|
||||||
------------
|
|
||||||
|
|
||||||
Please set up the following systems beforehand, it will not be explained here in detail (but see these links for external
|
|
||||||
installation guides):
|
|
||||||
|
|
||||||
* A SMTP server to send out mails, e.g. `Postfix`_ on your machine or some third-party server you have credentials for
|
|
||||||
* A HTTP reverse proxy, e.g. `nginx`_ or Traefik to allow HTTPS connections
|
|
||||||
* A `PostgreSQL`_ database server
|
|
||||||
|
|
||||||
Also recommended is, that you use a firewall, although this is not a ILMO-specific recommendation. If you're new to
|
|
||||||
Linux and firewalls, it is recommended that you start with `ufw`_.
|
|
||||||
|
|
||||||
.. note:: Please, do not run ILMO without HTTPS encryption. You'll handle user data and thanks to `Let's Encrypt`_
|
|
||||||
SSL certificates can be obtained for free these days.
|
|
||||||
|
|
||||||
Unix user
|
|
||||||
---------
|
|
||||||
|
|
||||||
As we do not want to run ilmo as root, we first create a new unprivileged user::
|
|
||||||
|
|
||||||
# adduser ilmo --disabled-password --home /var/ilmo
|
|
||||||
|
|
||||||
In this guide, all code lines prepended with a ``#`` symbol are commands that you need to execute on your server as
|
|
||||||
``root`` user (e.g. using ``sudo``); all lines prepended with a ``$`` symbol should be run by the unprivileged user.
|
|
||||||
|
|
||||||
Database
|
|
||||||
--------
|
|
||||||
|
|
||||||
Having the database server installed, we still need a database and a database user. We can create these with any kind
|
|
||||||
of database managing tool or directly on our database's shell. Please make sure that UTF8 is used as encoding for the
|
|
||||||
best compatibility. You can check this with the following command::
|
|
||||||
|
|
||||||
# sudo -u postgres psql -c 'SHOW SERVER_ENCODING'
|
|
||||||
|
|
||||||
For PostgreSQL database creation, we would do::
|
|
||||||
|
|
||||||
# sudo -u postgres createuser ilmo
|
|
||||||
# sudo -u postgres createdb -O ilmo ilmo
|
|
||||||
# su ilmo
|
|
||||||
$ psql
|
|
||||||
> ALTER USER ilmo PASSWORD 'strong_password';
|
|
||||||
|
|
||||||
Package dependencies
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
To build and run ilmo, you will need the following debian packages::
|
|
||||||
|
|
||||||
# apt-get install git build-essential python-dev python3-venv python3 python3-pip \
|
|
||||||
python3-dev
|
|
||||||
|
|
||||||
Config file
|
|
||||||
-----------
|
|
||||||
|
|
||||||
We now create a config directory and config file for ilmo::
|
|
||||||
|
|
||||||
# mkdir /etc/ilmo
|
|
||||||
# touch /etc/ilmo/ilmo.cfg
|
|
||||||
# chown -R ilmo:ilmo /etc/ilmo/
|
|
||||||
# chmod 0600 /etc/ilmo/ilmo.cfg
|
|
||||||
|
|
||||||
Fill the configuration file ``/etc/ilmo/ilmo.cfg`` with the following content (adjusted to your environment)::
|
|
||||||
|
|
||||||
[ilmo]
|
|
||||||
instance_name=My library
|
|
||||||
url=https://ilmo.example.com
|
|
||||||
|
|
||||||
[database]
|
|
||||||
backend=postgresql
|
|
||||||
name=ilmo
|
|
||||||
user=ilmo
|
|
||||||
|
|
||||||
[locations]
|
|
||||||
static=/var/ilmo/static
|
|
||||||
|
|
||||||
[mail]
|
|
||||||
; See config file documentation for more options
|
|
||||||
; from=ilmo@example.com
|
|
||||||
; host=127.0.0.1
|
|
||||||
; user=ilmo
|
|
||||||
; password=foobar
|
|
||||||
; port=587
|
|
||||||
|
|
||||||
[security]
|
|
||||||
; See https://securitytxt.org/ for reference
|
|
||||||
;Contact=
|
|
||||||
;Expires=
|
|
||||||
;Encryption=
|
|
||||||
;Preferred-Languages=
|
|
||||||
;Scope=
|
|
||||||
;Policy=
|
|
||||||
|
|
||||||
Install ilmo as package
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
Now we will install ilmo itself. The following steps are to be executed as the ``ilmo`` user. Before we
|
|
||||||
actually install ilmo, we will create a virtual environment to isolate the python packages from your global
|
|
||||||
python installation::
|
|
||||||
|
|
||||||
$ python3 -m venv /var/ilmo/venv
|
|
||||||
$ source /var/ilmo/venv/bin/activate
|
|
||||||
(venv)$ pip3 install -U pip setuptools wheel
|
|
||||||
|
|
||||||
We now clone and install ilmo, its direct dependencies and gunicorn::
|
|
||||||
|
|
||||||
(venv)$ git clone https://github.com/moan0s/ILMO2
|
|
||||||
(venv)$ cd ILMO2/src/
|
|
||||||
(venv)$ pip3 install -r requirements.txt
|
|
||||||
(venv)$ pip3 install -e .
|
|
||||||
|
|
||||||
Note that you need Python 3.6 or newer. You can find out your Python version using ``python -V``.
|
|
||||||
|
|
||||||
Finally, we compile static files and create the database structure::
|
|
||||||
|
|
||||||
(venv)$ ./manage.py collectstatic
|
|
||||||
(venv)$ ./manage.py migrate
|
|
||||||
(venv)$ django-admin compilemessages --ignore venv
|
|
||||||
|
|
||||||
|
|
||||||
Start ilmo as a service
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
You should start ilmo using systemd to automatically start it after a reboot. Create a file
|
|
||||||
named ``/etc/systemd/system/ilmo-web.service`` with the following content::
|
|
||||||
|
|
||||||
[Unit]
|
|
||||||
Description=ilmo web service
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
User=ilmo
|
|
||||||
Group=ilmo
|
|
||||||
Environment="VIRTUAL_ENV=/var/ilmo/venv"
|
|
||||||
Environment="PATH=/var/ilmo/venv/bin:/usr/local/bin:/usr/bin:/bin"
|
|
||||||
ExecStart=/var/ilmo/venv/bin/gunicorn ilmo.wsgi \
|
|
||||||
--name ilmo --workers 5 \
|
|
||||||
--max-requests 1200 --max-requests-jitter 50 \
|
|
||||||
--log-level=info --bind=127.0.0.1:8345
|
|
||||||
WorkingDirectory=/var/ilmo
|
|
||||||
Restart=on-failure
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
|
|
||||||
You can now run the following commands to enable and start the services::
|
|
||||||
|
|
||||||
# systemctl daemon-reload
|
|
||||||
# systemctl enable ilmo-web
|
|
||||||
# systemctl start ilmo-web
|
|
||||||
|
|
||||||
|
|
||||||
SSL
|
|
||||||
---
|
|
||||||
|
|
||||||
The following snippet is an example on how to configure a nginx proxy for ilmo::
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
listen [::]:80;
|
|
||||||
|
|
||||||
if ($scheme = http) {
|
|
||||||
return 301 https://$server_name$request_uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
listen 443 ssl;
|
|
||||||
listen [::]:443 ssl;
|
|
||||||
ssl_certificate /etc/letsencrypt/live/ilmo.example.com/cert.pem;
|
|
||||||
ssl_certificate_key /etc/letsencrypt/live/ilmo.example.com/privkey.pem;
|
|
||||||
ssl_protocols TLSv1.2 TLSv1.3;
|
|
||||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
|
||||||
|
|
||||||
|
|
||||||
# Set header
|
|
||||||
add_header X-Clacks-Overhead "GNU Terry Pratchett";
|
|
||||||
add_header Permissions-Policy interest-cohort=(); #Anti FLoC
|
|
||||||
add_header Referrer-Policy same-origin;
|
|
||||||
add_header X-Content-Type-Options nosniff;
|
|
||||||
|
|
||||||
server_name ilmo.example.com;
|
|
||||||
location / {
|
|
||||||
proxy_pass http://localhost:8345;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto https;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /static/ {
|
|
||||||
alias /var/ilmo/static/;
|
|
||||||
access_log off;
|
|
||||||
expires 365d;
|
|
||||||
add_header Cache-Control "public";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
We recommend reading about setting `strong encryption settings`_ for your web server.
|
|
||||||
|
|
||||||
Next steps
|
|
||||||
----------
|
|
||||||
|
|
||||||
Yay, you are done! You should now be able to reach ilmo at https://ilmo.example.com/
|
|
||||||
|
|
||||||
Updates
|
|
||||||
-------
|
|
||||||
|
|
||||||
.. warning:: While we try hard not to break things, **please perform a backup before every upgrade**.
|
|
||||||
|
|
||||||
To upgrade to a new ilmo release, pull the latest code changes and run the following commands::
|
|
||||||
|
|
||||||
$ source /var/ilmo/venv/bin/activate
|
|
||||||
(venv)$ git pull
|
|
||||||
(venv)$ pg_dump ilmo > ilmo.psql
|
|
||||||
(venv)$ python manage.py migrate
|
|
||||||
(venv)$ django-admin compilemessages --ignore venv
|
|
||||||
|
|
||||||
# systemctl restart ilmo-web
|
|
||||||
|
|
||||||
|
|
||||||
.. _Postfix: https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-postfix-as-a-send-only-smtp-server-on-ubuntu-16-04
|
|
||||||
.. _nginx: https://botleg.com/stories/https-with-lets-encrypt-and-nginx/
|
|
||||||
.. _Let's Encrypt: https://letsencrypt.org/
|
|
||||||
.. _MySQL: https://dev.mysql.com/doc/refman/5.7/en/linux-installation-apt-repo.html
|
|
||||||
.. _PostgreSQL: https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-20-04
|
|
||||||
.. _redis: https://blog.programster.org/debian-8-install-redis-server/
|
|
||||||
.. _ufw: https://en.wikipedia.org/wiki/Uncomplicated_Firewall
|
|
||||||
.. _strong encryption settings: https://mozilla.github.io/server-side-tls/ssl-config-generator/
|
|
||||||
.. _service: hyteck.de/services
|
|
||||||
.. _pretix: https://docs.pretix.eu/en/latest/admin/installation/manual_smallscale.html
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
|||||||
********************************************
|
|
||||||
Installation, customization and contributing
|
|
||||||
********************************************
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
:caption: Contents:
|
|
||||||
|
|
||||||
deployment.rst
|
|
||||||
contributing.rst
|
|
||||||
release.rst
|
|
||||||
backup.rst
|
|
@ -1,14 +0,0 @@
|
|||||||
.. _postgresql_license:
|
|
||||||
|
|
||||||
PostgreSQL License
|
|
||||||
******************
|
|
||||||
|
|
||||||
.. code-block::
|
|
||||||
|
|
||||||
PostgreSQL Database Management System (formerly known as Postgres, then as Postgres95)
|
|
||||||
Portions Copyright (c) 1996-2008, The PostgreSQL Global Development Group
|
|
||||||
Portions Copyright (c) 1994, The Regents of the University of California
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies.
|
|
||||||
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
@ -1,41 +0,0 @@
|
|||||||
Release
|
|
||||||
-------------
|
|
||||||
|
|
||||||
What qualifies as release?
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
A new release should be announced when a significant number functions, bugfixes or other improvements to the software
|
|
||||||
is made. Usually this indicates a minor release.
|
|
||||||
Major releases are yet to be determined.
|
|
||||||
|
|
||||||
What should be done before a release?
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Tested basic functions
|
|
||||||
######################
|
|
||||||
|
|
||||||
Run :command:`pytest`
|
|
||||||
|
|
||||||
Test upgrade on a copy of a production database
|
|
||||||
###############################################
|
|
||||||
|
|
||||||
.. WARNING::
|
|
||||||
You have to prevent e-mails from being sent, otherwise users could receive duplicate e-mails!
|
|
||||||
|
|
||||||
* Ensure correct migration if necessary
|
|
||||||
* Views correct?
|
|
||||||
|
|
||||||
Release
|
|
||||||
^^^^^^^
|
|
||||||
|
|
||||||
After testing everything you are good to go. Open the file :file:`src/setup.py` with a text editor
|
|
||||||
you can adjust the version number:
|
|
||||||
|
|
||||||
Do a final commit on this change, and tag the commit as release with appropriate version number.
|
|
||||||
|
|
||||||
.. code::
|
|
||||||
|
|
||||||
git tag -a v1.0.0 -m "Releasing version v1.0.0"
|
|
||||||
git push origin v1.0.0
|
|
||||||
|
|
||||||
Make sure the tag is visible on Codeberg and celebrate 🥳
|
|
@ -1,18 +0,0 @@
|
|||||||
Translation
|
|
||||||
===========
|
|
||||||
Translate HTML-files
|
|
||||||
____________________
|
|
||||||
First you have to add the text "{% load i18n %}" in every html file at the top.
|
|
||||||
|
|
||||||
Write the string in your html file between these two tags: {% translate "String" %}
|
|
||||||
|
|
||||||
Translate python-files
|
|
||||||
______________________
|
|
||||||
The underscore markes the string for translation. e.g. _("String")
|
|
||||||
|
|
||||||
|
|
||||||
Workflow
|
|
||||||
_________
|
|
||||||
- Generate the messages with the command: "django-admin makemessages -l de --ignore venv" de stands in this example for german
|
|
||||||
- Translate the strings in the file src/local/de/LC_MESSAGES/django.po
|
|
||||||
- Convert the strings for django with the command: "django-admin compilemessages --ignore venv"
|
|
@ -1,21 +0,0 @@
|
|||||||
###################################
|
|
||||||
Notfellchen Plattform Dokumentation
|
|
||||||
###################################
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
:caption: Contents:
|
|
||||||
|
|
||||||
user/index.rst
|
|
||||||
admin/index.rst
|
|
||||||
dev/index.rst
|
|
||||||
API/index.rst
|
|
||||||
|
|
||||||
.. image:: rtfm.png
|
|
||||||
:name: RTFM by Elektroll
|
|
||||||
:scale: 50 %
|
|
||||||
:alt: Soviet style image of workers holding a sign with a gear and a screwdriver. Below is says "Read the manual"
|
|
||||||
:align: center
|
|
||||||
|
|
||||||
|
|
||||||
Read the manual, Image by `Mike Powell (CC-BY) <https://elektroll.art/>`_.
|
|
@ -1,35 +0,0 @@
|
|||||||
@ECHO OFF
|
|
||||||
|
|
||||||
pushd %~dp0
|
|
||||||
|
|
||||||
REM Command file for Sphinx documentation
|
|
||||||
|
|
||||||
if "%SPHINXBUILD%" == "" (
|
|
||||||
set SPHINXBUILD=sphinx-build
|
|
||||||
)
|
|
||||||
set SOURCEDIR=.
|
|
||||||
set BUILDDIR=_build
|
|
||||||
|
|
||||||
if "%1" == "" goto help
|
|
||||||
|
|
||||||
%SPHINXBUILD% >NUL 2>NUL
|
|
||||||
if errorlevel 9009 (
|
|
||||||
echo.
|
|
||||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
|
||||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
|
||||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
|
||||||
echo.may add the Sphinx directory to PATH.
|
|
||||||
echo.
|
|
||||||
echo.If you don't have Sphinx installed, grab it from
|
|
||||||
echo.http://sphinx-doc.org/
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
|
|
||||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
|
||||||
goto end
|
|
||||||
|
|
||||||
:help
|
|
||||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
|
||||||
|
|
||||||
:end
|
|
||||||
popd
|
|
@ -1,3 +0,0 @@
|
|||||||
sphinx
|
|
||||||
sphinx-rtd-theme
|
|
||||||
sphinx-autobuild
|
|
BIN
docs/rtfm.png
BIN
docs/rtfm.png
Binary file not shown.
Before Width: | Height: | Size: 815 KiB |
@ -1,9 +0,0 @@
|
|||||||
Benachrichtigungen
|
|
||||||
==================
|
|
||||||
|
|
||||||
|
|
||||||
E-Mail
|
|
||||||
++++++
|
|
||||||
|
|
||||||
Mit während deiner :doc:`registrierung` gibst du eine E-Mail Addresse an.
|
|
||||||
Wir senden dir Benachrichtigungen an diese E-Mail. Du kannst das in deinen Profileinstellungen anpassen.
|
|
@ -1,11 +0,0 @@
|
|||||||
***********
|
|
||||||
Users guide
|
|
||||||
***********
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
:caption: Contents:
|
|
||||||
|
|
||||||
registrierung.rst
|
|
||||||
benachrichtigungen.rst
|
|
||||||
login.rst
|
|
||||||
email.rst
|
|
@ -1,5 +0,0 @@
|
|||||||
Registration
|
|
||||||
================================
|
|
||||||
|
|
||||||
To register you have to visit the library. An librarian will then set up an account for you.
|
|
||||||
You will need to provide an valid E-Mail Address and a password.
|
|
@ -1,3 +0,0 @@
|
|||||||
Vermittlungen
|
|
||||||
=============
|
|
||||||
|
|
@ -38,13 +38,12 @@ dependencies = [
|
|||||||
"psycopg2-binary",
|
"psycopg2-binary",
|
||||||
"django-crispy-forms",
|
"django-crispy-forms",
|
||||||
"crispy-bootstrap4",
|
"crispy-bootstrap4",
|
||||||
"djangorestframework"
|
|
||||||
]
|
]
|
||||||
dynamic = ["version", "readme"]
|
dynamic = ["version", "readme"]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
homepage = "https://notfellchen.org"
|
homepage = "https://hyteck.de"
|
||||||
repository = "https://codeberg.org/moanos/notfellchen/"
|
repository = "https://github.com/moan0s/notfellchen/"
|
||||||
|
|
||||||
[tool.setuptools.packages.find]
|
[tool.setuptools.packages.find]
|
||||||
where = ["src"]
|
where = ["src"]
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
from ..models import AdoptionNotice
|
|
||||||
from rest_framework import serializers
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AdoptionNoticeSerializer(serializers.HyperlinkedModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = AdoptionNotice
|
|
||||||
fields = ['created_at', 'last_checked', "searching_since", "name", "description", "further_information", "group_only"]
|
|
@ -1,8 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from .views import (
|
|
||||||
AdoptionNoticeApiView
|
|
||||||
)
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('adoption_notice', AdoptionNoticeApiView.as_view()),
|
|
||||||
]
|
|
@ -1,37 +0,0 @@
|
|||||||
from django.contrib.auth.models import User
|
|
||||||
from rest_framework.views import APIView
|
|
||||||
from rest_framework.response import Response
|
|
||||||
from rest_framework import status
|
|
||||||
from rest_framework import permissions
|
|
||||||
from ..models import AdoptionNotice
|
|
||||||
from .serializers import AdoptionNoticeSerializer
|
|
||||||
|
|
||||||
|
|
||||||
class AdoptionNoticeApiView(APIView):
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
serializer_context = {
|
|
||||||
'request': request,
|
|
||||||
}
|
|
||||||
adoption_notices = AdoptionNotice.objects.all()
|
|
||||||
serializer = AdoptionNoticeSerializer(adoption_notices, many=True, context=serializer_context)
|
|
||||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
|
||||||
data = {
|
|
||||||
'name': request.data.get('name'),
|
|
||||||
"searching_since": request.data.get('searching_since'),
|
|
||||||
"description": request.data.get('description'),
|
|
||||||
"organization": request.data.get('organization'),
|
|
||||||
"further_information": request.data.get('further_information'),
|
|
||||||
"location_string": request.data.get('location_string'),
|
|
||||||
"group_only": request.data.get('group_only'),
|
|
||||||
"owner": request.data.get('owner')
|
|
||||||
}
|
|
||||||
serializer = AdoptionNoticeSerializer(data=data)
|
|
||||||
if serializer.is_valid():
|
|
||||||
serializer.save()
|
|
||||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
|
||||||
|
|
||||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
@ -32,7 +32,7 @@ class AdoptionNoticeForm(forms.ModelForm):
|
|||||||
submit = Submit('save-and-add-another-animal', _('Speichern'))
|
submit = Submit('save-and-add-another-animal', _('Speichern'))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
submit = Submit('submit', _('Speichern'))
|
submit = Submit('submit', _('Sepichern'))
|
||||||
|
|
||||||
self.helper.layout = Layout(
|
self.helper.layout = Layout(
|
||||||
Fieldset(
|
Fieldset(
|
||||||
@ -142,7 +142,6 @@ class CommentForm(forms.ModelForm):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.helper = FormHelper()
|
self.helper = FormHelper()
|
||||||
self.helper.form_action = "comment"
|
|
||||||
self.helper.form_class = 'form-comments'
|
self.helper.form_class = 'form-comments'
|
||||||
self.helper.add_input(Submit('submit', _('Kommentieren'), css_class="btn2"))
|
self.helper.add_input(Submit('submit', _('Kommentieren'), css_class="btn2"))
|
||||||
|
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
# Generated by Django 5.1.1 on 2024-09-30 12:24
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('fellchensammlung', '0005_rescueorganization_allows_using_materials_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='adoptionnotice',
|
|
||||||
name='last_checked',
|
|
||||||
field=models.DateField(default=datetime.datetime.now, verbose_name='Zuletzt überprüft am'),
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,19 +0,0 @@
|
|||||||
# Generated by Django 5.1.1 on 2024-09-30 13:10
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('fellchensammlung', '0006_adoptionnotice_last_checked'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='adoptionnotice',
|
|
||||||
name='last_checked',
|
|
||||||
field=models.DateTimeField(default=datetime.datetime.now, verbose_name='Zuletzt überprüft am'),
|
|
||||||
),
|
|
||||||
]
|
|
@ -174,7 +174,6 @@ class AdoptionNotice(models.Model):
|
|||||||
return f"{self.name}"
|
return f"{self.name}"
|
||||||
|
|
||||||
created_at = models.DateField(verbose_name=_('Erstellt am'), default=datetime.now)
|
created_at = models.DateField(verbose_name=_('Erstellt am'), default=datetime.now)
|
||||||
last_checked = models.DateTimeField(verbose_name=_('Zuletzt überprüft am'), default=datetime.now)
|
|
||||||
searching_since = models.DateField(verbose_name=_('Sucht nach einem Zuhause seit'))
|
searching_since = models.DateField(verbose_name=_('Sucht nach einem Zuhause seit'))
|
||||||
name = models.CharField(max_length=200)
|
name = models.CharField(max_length=200)
|
||||||
description = models.TextField(null=True, blank=True, verbose_name=_('Beschreibung'))
|
description = models.TextField(null=True, blank=True, verbose_name=_('Beschreibung'))
|
||||||
@ -210,15 +209,13 @@ class AdoptionNotice(models.Model):
|
|||||||
return self.description[:200] + f" ... [weiterlesen]({self.get_absolute_url()})"
|
return self.description[:200] + f" ... [weiterlesen]({self.get_absolute_url()})"
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
"""Returns the url to access a detailed page for the adoption notice."""
|
"""Returns the url to access a detailed page for the animal."""
|
||||||
return reverse('adoption-notice-detail', args=[str(self.id)])
|
return reverse('adoption-notice-detail', args=[str(self.id)])
|
||||||
|
|
||||||
def get_report_url(self):
|
def get_report_url(self):
|
||||||
"""Returns the url to report an adoption notice."""
|
|
||||||
return reverse('report-adoption-notice', args=[str(self.id)])
|
return reverse('report-adoption-notice', args=[str(self.id)])
|
||||||
|
|
||||||
def get_subscriptions(self):
|
def get_subscriptions(self):
|
||||||
# returns all subscriptions to that adoption notice
|
|
||||||
return Subscriptions.objects.filter(adoption_notice=self)
|
return Subscriptions.objects.filter(adoption_notice=self)
|
||||||
|
|
||||||
def get_photos(self):
|
def get_photos(self):
|
||||||
@ -277,14 +274,6 @@ class AdoptionNotice(models.Model):
|
|||||||
return False
|
return False
|
||||||
return self.adoptionnoticestatus.is_active
|
return self.adoptionnoticestatus.is_active
|
||||||
|
|
||||||
def set_checked(self):
|
|
||||||
self.last_checked = datetime.now()
|
|
||||||
self.save()
|
|
||||||
|
|
||||||
def set_closed(self):
|
|
||||||
self.last_checked = datetime.now()
|
|
||||||
self.adoptionnoticestatus.set_closed()
|
|
||||||
|
|
||||||
|
|
||||||
class AdoptionNoticeStatus(models.Model):
|
class AdoptionNoticeStatus(models.Model):
|
||||||
"""
|
"""
|
||||||
@ -346,11 +335,6 @@ class AdoptionNoticeStatus(models.Model):
|
|||||||
def get_minor_choices(major_status):
|
def get_minor_choices(major_status):
|
||||||
return AdoptionNoticeStatus.MINOR_STATUS_CHOICES[major_status]
|
return AdoptionNoticeStatus.MINOR_STATUS_CHOICES[major_status]
|
||||||
|
|
||||||
def set_closed(self):
|
|
||||||
self.major_status = self.MAJOR_STATUS_CHOICES[self.CLOSED]
|
|
||||||
self.minor_status = self.MINOR_STATUS_CHOICES[self.CLOSED]["other"]
|
|
||||||
self.save()
|
|
||||||
|
|
||||||
|
|
||||||
class Animal(models.Model):
|
class Animal(models.Model):
|
||||||
MALE_NEUTERED = "M_N"
|
MALE_NEUTERED = "M_N"
|
||||||
|
@ -4,23 +4,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="detail-adoption-notice-header">
|
<div class="detail-adoption-notice-header">
|
||||||
<h1 class="detail-adoption-notice-header">{{ adoption_notice.name }}
|
<h1 class="detail-adoption-notice-header">{{ adoption_notice.name }}</h1>
|
||||||
{% if not is_subscribed %}
|
|
||||||
<form class="notification-card-mark-read" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="action" value="subscribe">
|
|
||||||
<input type="hidden" name="adoption_notice_id" value="{{ adoption_notice.pk }}">
|
|
||||||
<button class="btn2" type="submit" id="submit"><i class="fa-solid fa-bell"></i></button>
|
|
||||||
</form>
|
|
||||||
{% else %}
|
|
||||||
<form class="notification-card-mark-read" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="action" value="unsubscribe">
|
|
||||||
<input type="hidden" name="adoption_notice_id" value="{{ adoption_notice.pk }}">
|
|
||||||
<button class="btn2" type="submit" id="submit"><i class="fa-solid fa-bell-slash"></i></button>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
</h1>
|
|
||||||
{% if has_edit_permission %}
|
{% if has_edit_permission %}
|
||||||
<a class="btn2"
|
<a class="btn2"
|
||||||
href="{% url 'adoption-notice-add-photo' adoption_notice_id=adoption_notice.pk %}">{% translate 'Foto hinzufügen' %}</a>
|
href="{% url 'adoption-notice-add-photo' adoption_notice_id=adoption_notice.pk %}">{% translate 'Foto hinzufügen' %}</a>
|
||||||
@ -33,7 +17,6 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>{% translate "Ort" %}</th>
|
<th>{% translate "Ort" %}</th>
|
||||||
<th>{% translate "Suchen seit" %}</th>
|
<th>{% translate "Suchen seit" %}</th>
|
||||||
<th>{% translate "Zuletzt aktualisiert" %}</th>
|
|
||||||
<th>{% translate "Weitere Informationen" %}</th>
|
<th>{% translate "Weitere Informationen" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -46,7 +29,6 @@
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>{{ adoption_notice.searching_since }}</td>
|
<td>{{ adoption_notice.searching_since }}</td>
|
||||||
<td>{{ adoption_notice.last_checked | date:'d. F Y' }}</td>
|
|
||||||
{% if adoption_notice.further_information %}
|
{% if adoption_notice.further_information %}
|
||||||
<td>{{ adoption_notice.link_to_more_information | safe }}</td>
|
<td>{{ adoption_notice.link_to_more_information | safe }}</td>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
{% extends "fellchensammlung/base_generic.html" %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% block content %}
|
|
||||||
<h1>{% translate "Aktualitätscheck" %}</h1>
|
|
||||||
<p>{% translate "Überprüfe ob Vermittlungen noch aktuell sind" %}</p>
|
|
||||||
{% for adoption_notice in adoption_notices %}
|
|
||||||
<div class="card">
|
|
||||||
<h1>
|
|
||||||
<a href="{{ adoption_notice.get_absolute_url }}">{{ adoption_notice.name }}</a>
|
|
||||||
</h1>
|
|
||||||
{% if adoption_notice.further_information %}
|
|
||||||
<p>{% translate "Externe Quelle" %}: {{ adoption_notice.link_to_more_information | safe }}</p>
|
|
||||||
{% endif %}
|
|
||||||
<div>
|
|
||||||
<form method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden"
|
|
||||||
name="adoption_notice_id"
|
|
||||||
value="{{ adoption_notice.pk }}">
|
|
||||||
<input type="hidden" name="action" value="checked_active">
|
|
||||||
<button class="btn" type="submit">{% translate "Vermittlung noch aktuell" %}</button>
|
|
||||||
</form>
|
|
||||||
<form method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden"
|
|
||||||
name="adoption_notice_id"
|
|
||||||
value="{{ adoption_notice.pk }}">
|
|
||||||
<input type="hidden" name="action" value="checked_inactive">
|
|
||||||
<button class="btn" type="submit">{% translate "Vermittlung inaktiv" %}</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endblock %}
|
|
@ -34,9 +34,9 @@ urlpatterns = [
|
|||||||
|
|
||||||
path("ueber-uns/", views.about, name="about"),
|
path("ueber-uns/", views.about, name="about"),
|
||||||
|
|
||||||
################
|
#############
|
||||||
## Moderation ##
|
## Reports ##
|
||||||
################
|
#############
|
||||||
path("vermittlung/<int:adoption_notice_id>/report", views.report_adoption, name="report-adoption-notice"),
|
path("vermittlung/<int:adoption_notice_id>/report", views.report_adoption, name="report-adoption-notice"),
|
||||||
|
|
||||||
path("kommentar/<int:comment_id>/report", views.report_comment, name="report-comment"),
|
path("kommentar/<int:comment_id>/report", views.report_comment, name="report-comment"),
|
||||||
@ -44,8 +44,6 @@ urlpatterns = [
|
|||||||
path("meldung/<uuid:report_id>/sucess", views.report_detail_success, name="report-detail-success"),
|
path("meldung/<uuid:report_id>/sucess", views.report_detail_success, name="report-detail-success"),
|
||||||
path("modqueue/", views.modqueue, name="modqueue"),
|
path("modqueue/", views.modqueue, name="modqueue"),
|
||||||
|
|
||||||
path("updatequeue/", views.updatequeue, name="updatequeue"),
|
|
||||||
|
|
||||||
###########
|
###########
|
||||||
## USERS ##
|
## USERS ##
|
||||||
###########
|
###########
|
||||||
@ -66,18 +64,6 @@ urlpatterns = [
|
|||||||
###########
|
###########
|
||||||
## ADMIN ##
|
## ADMIN ##
|
||||||
###########
|
###########
|
||||||
path('instance-health-check', views.instance_health_check, name="instance-health-check"),
|
path('instance-health-check', views.instance_health_check, name="instance-health-check")
|
||||||
|
|
||||||
#############
|
|
||||||
## Metrics ##
|
|
||||||
#############
|
|
||||||
# ex: /metrics
|
|
||||||
path('metrics/', views.metrics, name="metrics"),
|
|
||||||
|
|
||||||
#########
|
|
||||||
## API ##
|
|
||||||
#########
|
|
||||||
path('api/', include('fellchensammlung.api.urls')),
|
|
||||||
|
|
||||||
|
|
||||||
]
|
]
|
||||||
|
@ -75,17 +75,9 @@ def change_language(request):
|
|||||||
|
|
||||||
def adoption_notice_detail(request, adoption_notice_id):
|
def adoption_notice_detail(request, adoption_notice_id):
|
||||||
adoption_notice = AdoptionNotice.objects.get(id=adoption_notice_id)
|
adoption_notice = AdoptionNotice.objects.get(id=adoption_notice_id)
|
||||||
if request.user.is_authenticated:
|
|
||||||
try:
|
|
||||||
subscription = Subscriptions.objects.get(owner=request.user, adoption_notice=adoption_notice)
|
|
||||||
is_subscribed = True
|
|
||||||
except Subscriptions.DoesNotExist:
|
|
||||||
is_subscribed = False
|
|
||||||
has_edit_permission = user_is_owner_or_trust_level(request.user, adoption_notice)
|
has_edit_permission = user_is_owner_or_trust_level(request.user, adoption_notice)
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
action = request.POST.get("action")
|
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
if action == "comment":
|
|
||||||
comment_form = CommentForm(request.POST)
|
comment_form = CommentForm(request.POST)
|
||||||
|
|
||||||
if comment_form.is_valid():
|
if comment_form.is_valid():
|
||||||
@ -108,20 +100,12 @@ def adoption_notice_detail(request, adoption_notice_id):
|
|||||||
text=f"{request.user}: {comment_instance.text}",
|
text=f"{request.user}: {comment_instance.text}",
|
||||||
comment=comment_instance)
|
comment=comment_instance)
|
||||||
notification.save()
|
notification.save()
|
||||||
else:
|
|
||||||
comment_form = CommentForm(instance=adoption_notice)
|
|
||||||
if action == "subscribe":
|
|
||||||
Subscriptions.objects.create(owner=request.user, adoption_notice=adoption_notice)
|
|
||||||
is_subscribed = True
|
|
||||||
if action == "unsubscribe":
|
|
||||||
subscription.delete()
|
|
||||||
is_subscribed = False
|
|
||||||
else:
|
else:
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
else:
|
else:
|
||||||
comment_form = CommentForm(instance=adoption_notice)
|
comment_form = CommentForm(instance=adoption_notice)
|
||||||
context = {"adoption_notice": adoption_notice,"comment_form": comment_form, "user": request.user,
|
context = {"adoption_notice": adoption_notice, "comment_form": comment_form, "user": request.user,
|
||||||
"has_edit_permission": has_edit_permission, "is_subscribed": is_subscribed}
|
"has_edit_permission": has_edit_permission}
|
||||||
return render(request, 'fellchensammlung/details/detail_adoption_notice.html', context=context)
|
return render(request, 'fellchensammlung/details/detail_adoption_notice.html', context=context)
|
||||||
|
|
||||||
|
|
||||||
@ -423,28 +407,6 @@ def modqueue(request):
|
|||||||
context = {"reports": open_reports}
|
context = {"reports": open_reports}
|
||||||
return render(request, 'fellchensammlung/modqueue.html', context=context)
|
return render(request, 'fellchensammlung/modqueue.html', context=context)
|
||||||
|
|
||||||
@login_required
|
|
||||||
def updatequeue(request):
|
|
||||||
if request.method == "POST":
|
|
||||||
print(request.POST.get("adoption_notice_id"))
|
|
||||||
adoption_notice = AdoptionNotice.objects.get(id=request.POST.get("adoption_notice_id"))
|
|
||||||
action = request.POST.get("action")
|
|
||||||
print(f"Action: {action}")
|
|
||||||
if action == "checked_inactive":
|
|
||||||
adoption_notice.set_closed()
|
|
||||||
elif action == "checked_active":
|
|
||||||
print("set checked")
|
|
||||||
adoption_notice.set_checked()
|
|
||||||
|
|
||||||
if user_is_trust_level_or_above(request.user, User.MODERATOR):
|
|
||||||
last_checked_adoption_list = AdoptionNotice.objects.order_by("last_checked")
|
|
||||||
else:
|
|
||||||
last_checked_adoption_list = AdoptionNotice.objects.filter(owner=request.user).order_by("last_checked")
|
|
||||||
adoption_notices = [adoption for adoption in last_checked_adoption_list if adoption.is_active]
|
|
||||||
|
|
||||||
context = {"adoption_notices": adoption_notices}
|
|
||||||
return render(request, 'fellchensammlung/updatequeue.html', context=context)
|
|
||||||
|
|
||||||
|
|
||||||
def map(request):
|
def map(request):
|
||||||
adoption_notices = AdoptionNotice.objects.all() #TODO: Filter to active
|
adoption_notices = AdoptionNotice.objects.all() #TODO: Filter to active
|
||||||
|
@ -160,7 +160,6 @@ INSTALLED_APPS = [
|
|||||||
'fontawesomefree',
|
'fontawesomefree',
|
||||||
'crispy_forms',
|
'crispy_forms',
|
||||||
"crispy_bootstrap4",
|
"crispy_bootstrap4",
|
||||||
"rest_framework",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
Loading…
Reference in New Issue
Block a user