Compare commits
	
		
			3 commits
		
	
	
		
			master
			...
			export_sez
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
							 | 
						64bd360716 | ||
| 
							 | 
						350041c587 | ||
| 
							 | 
						3a8d5b2207 | 
					 702 changed files with 103435 additions and 65473 deletions
				
			
		| 
						 | 
				
			
			@ -1,24 +0,0 @@
 | 
			
		|||
# Univerzální popis našich konvencí pro nastavení editorů.
 | 
			
		||||
# Vizte https://editorconfig.org pro detaily
 | 
			
		||||
 | 
			
		||||
root = true
 | 
			
		||||
 | 
			
		||||
[*]
 | 
			
		||||
charset = utf-8
 | 
			
		||||
# Unixové řádky
 | 
			
		||||
end_of_line = lf
 | 
			
		||||
insert_final_newline = true
 | 
			
		||||
 | 
			
		||||
[*.{py,css}]
 | 
			
		||||
indent_style = tab
 | 
			
		||||
# Nenařizujeme konkrétní šířku tabulátoru
 | 
			
		||||
indent_size = unset
 | 
			
		||||
 | 
			
		||||
# Automaticky generované migrace dodržují PEP-8, nemá smysl s tím moc bojovat.
 | 
			
		||||
[*/migrations/*.py]
 | 
			
		||||
indent_style = space
 | 
			
		||||
indent_size = 4
 | 
			
		||||
 | 
			
		||||
[*.html]
 | 
			
		||||
indent_style = space
 | 
			
		||||
indent_size = 2
 | 
			
		||||
							
								
								
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -31,15 +31,5 @@ TODO
 | 
			
		|||
# reversion kvůli historii objektů v reversion
 | 
			
		||||
**/reversion
 | 
			
		||||
 | 
			
		||||
# dokumentace
 | 
			
		||||
docs/_build
 | 
			
		||||
docs/modules
 | 
			
		||||
 | 
			
		||||
# logy týracího skriptu (./checklinks.sh)
 | 
			
		||||
/wget.log.*
 | 
			
		||||
 | 
			
		||||
# pro lidi, co programují v nástrojích od JetBrains
 | 
			
		||||
.idea
 | 
			
		||||
 | 
			
		||||
# Mac users
 | 
			
		||||
.DS_Store
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										158
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										158
									
								
								Makefile
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,9 +1,153 @@
 | 
			
		|||
# Existence tohohle Makefile je tu jen proto, aby fungovala svalová paměť. Pokud můžete, použijte rovnou `make/…`
 | 
			
		||||
%:
 | 
			
		||||
	# Používání make jako příkazu je zastaralé, prosím používej radši skripty ze složky make. Spouštím následující příkaz:
 | 
			
		||||
	make/$*
 | 
			
		||||
PYTHON ?= python3
 | 
			
		||||
VENV ?= ${PYTHON} -m venv
 | 
			
		||||
# Všechny flagy, které se s venvem/virtualenvem/... mají volat patří sem. Volá se "${VENV} cesta"
 | 
			
		||||
VENV_PATH ?= env
 | 
			
		||||
# Musí být definovaná, i kdyby to měla být "."
 | 
			
		||||
 | 
			
		||||
default:
 | 
			
		||||
	@cat make/README.md
 | 
			
		||||
.PHONY: all venv_check clean install install_web install_venv clean_venv clean_schema run test deploy_test deploy_prod sync_test_media sync_test_db sync_test sync_local_media sync_local_db sync_local
 | 
			
		||||
 | 
			
		||||
.PHONY: default
 | 
			
		||||
# activate by mělo být předpokladem ke všemu, co volá webový python (i.e. python nasazený do ${VENV}u kvůli webu, např. manage.py)
 | 
			
		||||
all:
 | 
			
		||||
	@# Just echo:
 | 
			
		||||
	# Install je trochu magický:
 | 
			
		||||
	# Spusť následující posloupnost příkazů:
 | 
			
		||||
	#	make install_venv
 | 
			
		||||
	#	. ${VENV_PATH}/bin/activate
 | 
			
		||||
	#	make install_web
 | 
			
		||||
	#
 | 
			
		||||
	# Pokud install_web říká Error: pg_config executable not found. nainstaluj si libpq-dev
 | 
			
		||||
	# Pokud chybová hláška obsahuje #include <Python.h>, nainstaluj si python3-dev
 | 
			
		||||
	#
 | 
			
		||||
	# Až skončíš s vývojem webu, spusť "deactivate". Tím zmizí '(${VENV_PATH})' ze začátku promptu.
 | 
			
		||||
 | 
			
		||||
venv_check:
 | 
			
		||||
	@# Pokud org nemá zapnutý venv, poradíme mu, aby si ho zapnul a spadneme. Jinak nic.
 | 
			
		||||
	@expr $$PATH : ".*:*$(shell pwd)/${VENV_PATH}/bin" > /dev/null && exit 0 || echo 'Není zapnutý venv, spusť ". ${VENV_PATH}/bin/activate".\nPokud není venv nainstalovaný, spusť "make install_venv"' && false
 | 
			
		||||
 | 
			
		||||
clean: clean_venv clean_schema
 | 
			
		||||
 | 
			
		||||
install: install_web
 | 
			
		||||
 | 
			
		||||
install_web: venv_check
 | 
			
		||||
	@# venv může být příšerně starý, takže nejdříve upgradujeme venvové věci
 | 
			
		||||
	pip install --upgrade pip
 | 
			
		||||
	pip install --upgrade setuptools
 | 
			
		||||
	# Instalace závislostí webu
 | 
			
		||||
	pip install -r requirements.txt --upgrade
 | 
			
		||||
	# Po vygenerování testdat spusť  ./manage.py loaddata data/*, ať máš menu a další modely
 | 
			
		||||
	# Pro synchronizaci flatpages spusť make sync_prod_flatpages
 | 
			
		||||
 | 
			
		||||
install_venv:
 | 
			
		||||
	${VENV} ${VENV_PATH}
 | 
			
		||||
 | 
			
		||||
clean_venv:
 | 
			
		||||
	# Možná není 100% foolproof...
 | 
			
		||||
	@test ! ${VENV_PATH} = . || ! echo "Smaž si prosím venv sám, nebudu mazat celý web"
 | 
			
		||||
	rm -rfv ${VENV_PATH}
 | 
			
		||||
	rm -f pip-selfcheck.json
 | 
			
		||||
clean_schema:
 | 
			
		||||
	rm -f schema_seminar.pdf schema_all.pdf
 | 
			
		||||
 | 
			
		||||
run: venv_check
 | 
			
		||||
	./manage.py runserver
 | 
			
		||||
 | 
			
		||||
test: venv_check
 | 
			
		||||
	./manage.py test -v2 seminar mamweb
 | 
			
		||||
 | 
			
		||||
# DB schemata
 | 
			
		||||
 | 
			
		||||
schema: schema_seminar.pdf schema_all.pdf
 | 
			
		||||
 | 
			
		||||
schema_seminar.pdf: venv_check
 | 
			
		||||
	./manage.py graph_models seminar | dot -Tpdf > schema_seminar.pdf
 | 
			
		||||
 | 
			
		||||
schema_all.pdf: venv_check
 | 
			
		||||
	./manage.py graph_models -a -g | dot -Tpdf > schema_all.pdf
 | 
			
		||||
 | 
			
		||||
# Deploy to current *mamweb-test* directory
 | 
			
		||||
deploy_test: venv_check
 | 
			
		||||
	@if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi
 | 
			
		||||
	@if [ `readlink -f .` != "/aux/akce/mam/www/mamweb-test" ]; then echo "Only possible in directory mamweb-test"; exit 1; fi
 | 
			
		||||
	@echo "Installing version from origin/test ..."
 | 
			
		||||
	git pull origin test
 | 
			
		||||
	git clean -f
 | 
			
		||||
	make install
 | 
			
		||||
	./manage.py migrate 
 | 
			
		||||
	./manage.py collectstatic --noinput
 | 
			
		||||
	(chown -R :mam . || true )
 | 
			
		||||
	(chmod -R g+rX,go-w . || true )
 | 
			
		||||
	@echo Restarting systemd unit
 | 
			
		||||
	systemctl --user restart mamweb-test.service
 | 
			
		||||
	@echo Done.
 | 
			
		||||
 | 
			
		||||
# Deploy to current *mamweb-prod* directory
 | 
			
		||||
deploy_prod: venv_check
 | 
			
		||||
	@if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi
 | 
			
		||||
	@if [ `readlink -f .` != "/aux/akce/mam/www/mamweb-prod" ]; then echo "Only possible in directory mamweb-prod"; exit 1; fi
 | 
			
		||||
	@echo "Backing up production DB ..."
 | 
			
		||||
	( cd -P .. && ./backup_prod_db.sh )
 | 
			
		||||
	@echo "Installing version from origin/master ..."
 | 
			
		||||
	git pull origin master
 | 
			
		||||
	git clean -f
 | 
			
		||||
	make install
 | 
			
		||||
	./manage.py migrate 
 | 
			
		||||
	./manage.py collectstatic --noinput
 | 
			
		||||
	(chown -R :mam . || true )
 | 
			
		||||
	(chmod -R g+rX,go-w . || true )
 | 
			
		||||
	@echo Restarting systemd user unit for MaM web
 | 
			
		||||
	systemctl --user restart mamweb-prod.service
 | 
			
		||||
	@echo Done.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
sync_prod_flatpages: venv_check 
 | 
			
		||||
	@echo Downloading current version of flatpages from mamweb-prod.
 | 
			
		||||
	ssh mam-web@gimli.ms.mff.cuni.cz \
 | 
			
		||||
	"cd /akce/mam/www/mamweb-prod; . env/bin/activate; ./manage.py dumpdata flatpages --indent=2 > flat.json; ./fix_json.py flat.json flat_fixed.json"
 | 
			
		||||
	rsync -ave ssh mam-web@gimli.ms.mff.cuni.cz:/akce/mam/www/mamweb-prod/flat_fixed.json data/flat.json
 | 
			
		||||
	@echo "Applying downloaded flatpages."
 | 
			
		||||
	./manage.py loaddata data/flat.json
 | 
			
		||||
	@echo "Done."
 | 
			
		||||
 | 
			
		||||
# Sync test media directory with production
 | 
			
		||||
sync_test_media:
 | 
			
		||||
	@if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi
 | 
			
		||||
	@if [ `readlink -f .` != "/aux/akce/mam/www/mamweb-test" ]; then echo "Only possible in /akce/mam/www/mamweb-test"; exit 1; fi
 | 
			
		||||
	rsync -av --delete /akce/mam/www/mamweb-prod/media/ ./media
 | 
			
		||||
 | 
			
		||||
# Sync (with drop) test database with production database
 | 
			
		||||
sync_test_db_aggressive:
 | 
			
		||||
	@if [ ${USER} != "mam-web" ]; then echo "Only possible by user mam-web"; exit 1; fi
 | 
			
		||||
	pg_dump mam_test > dump-test-`date +"%Y%m%d_%H%M"`.sql
 | 
			
		||||
	pg_dump -Fc mam_prod > dump-prod.sql
 | 
			
		||||
	@# I am not sure which shell is used, so I am calling bash to make sure
 | 
			
		||||
	psql mam_test -c 'DROP OWNED BY "mam-web";'
 | 
			
		||||
	pg_restore -c --if-exists -d mam_test dump-prod.sql
 | 
			
		||||
	rm dump-prod.sql
 | 
			
		||||
	psql mam_test -c "UPDATE django_site SET name='MaMweb (test)', domain='mam-test.ks.matfyz.cz' WHERE id=1"
 | 
			
		||||
	@echo Done.
 | 
			
		||||
 | 
			
		||||
# Sync test with production
 | 
			
		||||
# HACK ALERT: using aggressive variant, due to the schemas being too different.
 | 
			
		||||
sync_test: sync_test_media sync_test_db_aggressive
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Sync media directory with atrey. Useful for local development with production database
 | 
			
		||||
# Does not sync Galerie and CACHE (too huge). 
 | 
			
		||||
sync_local_media:
 | 
			
		||||
	rsync -ave ssh --exclude Galerie --exclude CACHE\
 | 
			
		||||
		mam-web@gimli.ms.mff.cuni.cz:/akce/mam/www/mamweb-prod/media/ ./media/
 | 
			
		||||
# Downloads and restores production database to local database. PostgreSQL only. 
 | 
			
		||||
sync_local_db:
 | 
			
		||||
	scp mam-web@gimli.ms.mff.cuni.cz:`ssh mam-web@gimli.ms.mff.cuni.cz 'ls -v /akce/mam/www/backups/mam_prod-*\.pgdump.xz | tail -n 1'` \
 | 
			
		||||
		./last.pgdump.xz
 | 
			
		||||
	xz -fd last.pgdump.xz
 | 
			
		||||
	pg_restore -c -d mam-prod  last.pgdump
 | 
			
		||||
 | 
			
		||||
# Sync database and media. See above lines
 | 
			
		||||
sync_local: sync_local_media sync_local_db
 | 
			
		||||
 | 
			
		||||
# Push local compiled Vue to gimli test site
 | 
			
		||||
push_compiled_vue_to_test:
 | 
			
		||||
	scp vue_frontend/webpack-stats.json mam-web@gimli:/akce/mam/www/mamweb-test/vue_frontend/
 | 
			
		||||
	rsync -ave ssh seminar/static/seminar/vue mam-web@gimli:/akce/mam/www/mamweb-test/seminar/static/seminar/
 | 
			
		||||
	ssh mam-web@gimli.ms.mff.cuni.cz 'cd /akce/mam/www/mamweb-test/ && . env/bin/activate && ./manage.py collectstatic --noinput'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										112
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								README.md
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,58 +1,74 @@
 | 
			
		|||
Web M&M
 | 
			
		||||
======
 | 
			
		||||
Basic commands for web development
 | 
			
		||||
==================================
 | 
			
		||||
 | 
			
		||||
Tohle je repozitář s kódem M&Mího webu. Pokud zde hledáte web samotný nebo
 | 
			
		||||
informace o semináři, najdete je na <https://mam.matfyz.cz> (a upřímně nechápu,
 | 
			
		||||
jak jste se dostali k tomuhle textu :-D)
 | 
			
		||||
After you clone this repository, run `make`. It will download, locally install
 | 
			
		||||
and setup virtualenv and pip, and then locally install all required packages
 | 
			
		||||
from `requirements.txt`.
 | 
			
		||||
 | 
			
		||||
Pokud jste tu zůstali, tak vás beztak zajímá vývoj webu (a jestli ne, tak
 | 
			
		||||
budeme rádi, když začne :-)).
 | 
			
		||||
When working with the code, always use the binaries in `./bin/`, such as
 | 
			
		||||
`bin/pip`, `bin/python`, ... never the global python, pip, ...
 | 
			
		||||
Use `make` and `./manage.py` for most things.
 | 
			
		||||
 | 
			
		||||
Co je M&Mweb uvnitř
 | 
			
		||||
------
 | 
			
		||||
Celý náš web je napsaný v [Pythonu](https://www.python.org) ve frameworku
 | 
			
		||||
[Django](https://www.djangoproject.com/). Web běží na serveru zvaném Gimli,
 | 
			
		||||
jako databázi používá PostgreSQL (pro lokální vývoj naopak SQLite) a všechen
 | 
			
		||||
náš kód je uložený v [Gitu](https://git-scm.com/) na [téhle
 | 
			
		||||
gitee](https://gitea.ks.matfyz.cz/). Pro dokumentaci používáme
 | 
			
		||||
[Sphinx](https://www.sphinx-doc.org).
 | 
			
		||||
Use git :-)
 | 
			
		||||
 | 
			
		||||
<!--TODO: Z odstavce výše by ideálně měla být zachována jen první věta a zbytek
 | 
			
		||||
by měl být někde v docs s podrobnějším popisem…-->
 | 
			
		||||
Quickstart
 | 
			
		||||
----------
 | 
			
		||||
Run the following commands:
 | 
			
		||||
	make install_venv
 | 
			
		||||
	. env/bin/activate
 | 
			
		||||
	make install_web
 | 
			
		||||
 | 
			
		||||
Jak si web pořídit
 | 
			
		||||
------
 | 
			
		||||
Prosím přečti si podrobnější návod v <docs/vyvoj.rst> (tady by bylo zbytečné
 | 
			
		||||
ho duplikovat).
 | 
			
		||||
After finishing development, run "deactivate".
 | 
			
		||||
 | 
			
		||||
Jak web vyvíjet
 | 
			
		||||
----
 | 
			
		||||
<!--TODO: Napsat obšírněji, asi zase do docs/-->
 | 
			
		||||
Make commands
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
Na webu je mnoho věcí k dělání, některé ani nevyžadují kódění (třeba uhánění
 | 
			
		||||
orgů, aby si psali medailonky, aktualizace fotek, …), některé se naopak týkají
 | 
			
		||||
infrastruktury pod kódem (Gitea, Gimli, …). Je proto těžké mít na to úplně
 | 
			
		||||
obecný návod, tak tady je zhruba návod na úpravy kódu a pokud se něco z toho
 | 
			
		||||
nedá aplikovat, tak to prostě zkus nějak udělat jinak, po svém. (Omlouvám se
 | 
			
		||||
neinformatikům, ale líp to teď nesepíšu :-))
 | 
			
		||||
* `make install` (or `make`) - locally install and setup virtualpy, install
 | 
			
		||||
  required packages. Ran again installs missing packages. Run after changing
 | 
			
		||||
  `requirements.txt`.
 | 
			
		||||
 | 
			
		||||
1. Nejprve si stáhni repozitář a rozběhni si lokální web u sebe (viz <docs/vyvoj.rst>).
 | 
			
		||||
1. Najdi si problém v Kanboardu (klikni na „Issues“ na Gitee) a/nebo se domluv
 | 
			
		||||
   s webaři, na čem bys tak mohl/a pracovat.
 | 
			
		||||
1. Najdi místo, kde se to dá opravit a zkus to tam opravit. Uznávám, že tenhle
 | 
			
		||||
   bod je otravně obecný, pokud tápeš, zkus se zeptat zkušenějších webařů nebo
 | 
			
		||||
   podívat do dokumentace.
 | 
			
		||||
1. Vyzkoušej, že ti to lokálně funguje tak, jak má.
 | 
			
		||||
1. Zvládneš-li a máš-li čas, zkus to i zdokumentovat a/nebo napsat testy (TODO: chybí návod)
 | 
			
		||||
1. Po dohodě s webaři to vyzkoušej na testwebu
 | 
			
		||||
1. Pošli pull-request a případně zkus reagovat na komentáře
 | 
			
		||||
1. Až se změna začlení do hlavní větve (`master`) a nasadí se web na produkci,
 | 
			
		||||
   můžeš mít radost, že se web bude používat lépe Tobě i ostatním orgům :-)
 | 
			
		||||
* `make clean` - remove local python packages.
 | 
			
		||||
 | 
			
		||||
* `make veryclean` - remove local packages and virtualpy enviroment and
 | 
			
		||||
  binaries.
 | 
			
		||||
 | 
			
		||||
* `make run` - runs "./manage.py runserver_plus"
 | 
			
		||||
 | 
			
		||||
* `make push_test` - pushes the last commited version to test location.
 | 
			
		||||
  Only git-commited changes are pushed! Rest is re-generated from scratch.
 | 
			
		||||
  At test server, the media data and database are kept the same.
 | 
			
		||||
  Everything else not in .gitignore is deleted/overwritten on the test server.
 | 
			
		||||
 | 
			
		||||
* `make schema` - generates graph of seminar and all schemas as PDF. Supercool!
 | 
			
		||||
 | 
			
		||||
* `make sync_prod_flatpages` - downloads and applies static/flat pages from mamweb-prod
 | 
			
		||||
 | 
			
		||||
./manage.py commands
 | 
			
		||||
--------------------
 | 
			
		||||
 | 
			
		||||
* `./manage.py migrate` - update the database schema, initialise the database.
 | 
			
		||||
  You need to run this in the beginning.
 | 
			
		||||
 | 
			
		||||
* `./manage.py runserver_plus` - run a debugging server for the web. Slightly
 | 
			
		||||
  enhanced compared to `./manage.py runserver`.
 | 
			
		||||
  Open [127.0.0.1:8000](127.0.0.1:8000).
 | 
			
		||||
 | 
			
		||||
* `./manage.py testdata` - create pseudo-random seminar data and admin/admin
 | 
			
		||||
  user.
 | 
			
		||||
 | 
			
		||||
* `./manage.py test` - run the tests.
 | 
			
		||||
 | 
			
		||||
* `./manage.py shell` - run commands, list elemements of database, check syntax
 | 
			
		||||
  by importing files, etc.
 | 
			
		||||
 | 
			
		||||
Configurations
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
* `mamweb/settings_common.py` contains most configuration options.
 | 
			
		||||
* `mamweb/settings.py` is used only for local development.
 | 
			
		||||
* `mamweb/settings_test.py` is used for testing on atrey.
 | 
			
		||||
* `mamweb/settings_prod.py` is used in production deployment.
 | 
			
		||||
 | 
			
		||||
These are automatically switched by `make`.
 | 
			
		||||
 | 
			
		||||
### Proč pull-requesty?
 | 
			
		||||
<!--FIXME: Tohle ale už úplně patří do docs a ne sem, jen je zatím nemám prozkoumané…-->
 | 
			
		||||
 | 
			
		||||
Účelů pull-requestů je několik. Jednak doufáme, že pomůže webařům se orientovat
 | 
			
		||||
v kódu, jednak tím umožňujeme dělat experimenty a dávat si zpětnou vazbu. V
 | 
			
		||||
neposlední řadě pomáhají držet aspoň trochu konzistentní kód, což má pomoci
 | 
			
		||||
pohodě při programování… (A asi jsem na něco zapomněl :-))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								_git_hooks/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								_git_hooks/README.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
git hooks
 | 
			
		||||
=========
 | 
			
		||||
 | 
			
		||||
Kontrola stylu pythoních zdrojáků pomocí flake8. Kontrolujeme jen změny,
 | 
			
		||||
abychom nenutili lidi dělat nesouvisející úpravy, které by rozbíjely historii
 | 
			
		||||
(git blame).
 | 
			
		||||
 | 
			
		||||
pre-commit
 | 
			
		||||
----------
 | 
			
		||||
* kontrola změn před commitnutím
 | 
			
		||||
* instalace: lokálně zkopírovat do .git/hooks (musí být spustitelný)
 | 
			
		||||
 | 
			
		||||
update
 | 
			
		||||
------
 | 
			
		||||
* kontrola změn přicházejících s pushem
 | 
			
		||||
* instalace: na atreyi zkopírovat do /akce/MaM/MaMweb/mamweb.git/hooks
 | 
			
		||||
							
								
								
									
										30
									
								
								_git_hooks/pre-commit
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										30
									
								
								_git_hooks/pre-commit
									
									
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
#!/bin/sh
 | 
			
		||||
#
 | 
			
		||||
# Git hook script to verify what is about to be committed.
 | 
			
		||||
# Checks that the changes don't introduce new flake8 errors.
 | 
			
		||||
 | 
			
		||||
TMPDIFF=`tempfile`
 | 
			
		||||
FLAKE8="`git rev-parse --show-toplevel`/bin/flake8"
 | 
			
		||||
 | 
			
		||||
status=0
 | 
			
		||||
 | 
			
		||||
# select only changed python files which are not migrations
 | 
			
		||||
changed=`git diff --cached --name-only | grep 'py$' | grep -v 'migrations/[0-9]'`
 | 
			
		||||
if [ -z $changed ] ; then
 | 
			
		||||
    # Nothing to check. Note the exit is necessary -- we would not pass any
 | 
			
		||||
    # paths to git diff below and it would output the diff unfiltered.
 | 
			
		||||
    exit 0
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
git diff --unified=1 --cached HEAD -- $changed > $TMPDIFF
 | 
			
		||||
 | 
			
		||||
# only do the check when there are some changes to be commited
 | 
			
		||||
# otherwise flake8 would hang waiting for input
 | 
			
		||||
if [ -s $TMPDIFF ] ; then
 | 
			
		||||
    cat $TMPDIFF | $FLAKE8 --diff
 | 
			
		||||
    status=$?
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
rm -f $TMPDIFF
 | 
			
		||||
 | 
			
		||||
exit $status
 | 
			
		||||
							
								
								
									
										61
									
								
								_git_hooks/update
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										61
									
								
								_git_hooks/update
									
									
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,61 @@
 | 
			
		|||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
# git update hook to check that pushed changes don't introduce new flake8
 | 
			
		||||
# errors
 | 
			
		||||
 | 
			
		||||
# --- Command line
 | 
			
		||||
refname="$1"
 | 
			
		||||
oldrev="$2"
 | 
			
		||||
newrev="$3"
 | 
			
		||||
 | 
			
		||||
# --- Safety check
 | 
			
		||||
if [ -z "$GIT_DIR" ]; then
 | 
			
		||||
	echo "Don't run this script from the command line." >&2
 | 
			
		||||
	echo " (if you want, you could supply GIT_DIR then run" >&2
 | 
			
		||||
	echo "  $0 <ref> <oldrev> <newrev>)" >&2
 | 
			
		||||
	exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
 | 
			
		||||
	echo "usage: $0 <ref> <oldrev> <newrev>" >&2
 | 
			
		||||
	exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
TMPDIR=`mktemp -d`
 | 
			
		||||
TMPDIFF=`tempfile`
 | 
			
		||||
 | 
			
		||||
[ $refname != "refs/heads/master" -a $refname != "refs/heads/stable" ] && exit 0
 | 
			
		||||
 | 
			
		||||
# select only changed python files which are not migrations
 | 
			
		||||
changed=`git diff --name-only $oldrev $newrev | grep 'py$' | grep -v 'migrations/[0-9]'`
 | 
			
		||||
if [ -z $changed ] ; then
 | 
			
		||||
    # Nothing to check. Note the exit is necessary -- we would not pass any
 | 
			
		||||
    # paths to git diff below and it would output the diff unfiltered.
 | 
			
		||||
    exit 0
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
git diff --unified=1 $oldrev $newrev -- $changed >${TMPDIFF}
 | 
			
		||||
 | 
			
		||||
# there is no working tree in bare git repository, so we recreate it for flake8
 | 
			
		||||
git archive $newrev | tar -x -C ${TMPDIR}
 | 
			
		||||
 | 
			
		||||
cd ${TMPDIR}
 | 
			
		||||
# report only errors on lines in diff
 | 
			
		||||
# (if threre was flake8 installed on atrey, we could just call flake8)
 | 
			
		||||
/akce/MaM/WWW/mamweb-test/bin/flake8 --diff <${TMPDIFF}
 | 
			
		||||
status=$?
 | 
			
		||||
if [ $status != 0 ] ; then
 | 
			
		||||
    echo
 | 
			
		||||
    echo -n "Změny, které se snažíte pushnout, obsahují kód v pythonu "
 | 
			
		||||
    echo -n "nevyhovující flake8 (viz výše). Opravte je a zkuste to znovu. "
 | 
			
		||||
    echo -n "Nezapomeňte, že můžete editovat historii (git commit --amend, "
 | 
			
		||||
    echo -n "git rebase -i). Pokud byste chybu příště raději odhalili už při "
 | 
			
		||||
    echo "commitu, zkopírujte si pre-commit hook z _git_hooks do .git/hooks."
 | 
			
		||||
    echo
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
rm -rf ${TMPDIR}
 | 
			
		||||
rm -f ${TMPDIFF}
 | 
			
		||||
 | 
			
		||||
exit $status
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
from django.apps import AppConfig
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AesopConfig(AppConfig):
 | 
			
		||||
    name = 'aesop'
 | 
			
		||||
    verbose_name = 'Export do AESOPa'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
from django.http import HttpResponse
 | 
			
		||||
from django.utils.encoding import force_str
 | 
			
		||||
from django.utils.encoding import force_text
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class OvvpFile:
 | 
			
		||||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ class OvvpFile:
 | 
			
		|||
		yield '\t'.join(self.columns) + '\n'
 | 
			
		||||
		# rows
 | 
			
		||||
		for r in self.rows:
 | 
			
		||||
			yield '\t'.join([force_str(r[c]) for c in self.columns]) + '\n'
 | 
			
		||||
			yield '\t'.join([force_text(r[c]) for c in self.columns]) + '\n'
 | 
			
		||||
 | 
			
		||||
	def to_string(self):
 | 
			
		||||
		return ''.join(self.to_lines())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,16 +5,16 @@ urlpatterns = [
 | 
			
		|||
	path(
 | 
			
		||||
		'aesop-export/mam-rocnik-<int:prvni_rok>.csv',
 | 
			
		||||
		views.ExportRocnikView.as_view(),
 | 
			
		||||
		name='aesop_export_rocnik'
 | 
			
		||||
		name='seminar_export_rocnik'
 | 
			
		||||
	),
 | 
			
		||||
	path(
 | 
			
		||||
		'aesop-export/mam-sous-<str:datum_zacatku>.csv',
 | 
			
		||||
		views.ExportSousView.as_view(),
 | 
			
		||||
		name='aesop_export_sous'
 | 
			
		||||
		name='seminar_export_sous'
 | 
			
		||||
	),
 | 
			
		||||
	path(
 | 
			
		||||
		'aesop-export/index.csv',
 | 
			
		||||
		views.ExportIndexView.as_view(),
 | 
			
		||||
		name='aesop_export_index'
 | 
			
		||||
		name='seminar_export_index'
 | 
			
		||||
	),
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
import datetime
 | 
			
		||||
 | 
			
		||||
from django.utils.encoding import force_str
 | 
			
		||||
from django.utils.encoding import force_text
 | 
			
		||||
 | 
			
		||||
from aesop.ovvpfile import OvvpFile
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ def default_ovvpfile(event, rocnik):
 | 
			
		|||
    of = OvvpFile()
 | 
			
		||||
    of.headers['version'] = '1'
 | 
			
		||||
    of.headers['event'] = event
 | 
			
		||||
    of.headers['year'] = force_str(rocnik.prvni_rok)
 | 
			
		||||
    of.headers['year'] = force_text(rocnik.prvni_rok)
 | 
			
		||||
    of.headers['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
 | 
			
		||||
    of.headers['id-scope'] = 'mam'
 | 
			
		||||
    of.headers['id-generation'] = '1'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,22 +3,21 @@ from django.shortcuts import get_object_or_404
 | 
			
		|||
from django.http import HttpResponse
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
from django.views import generic
 | 
			
		||||
from django.utils.encoding import force_str
 | 
			
		||||
from django.utils.encoding import force_text
 | 
			
		||||
 | 
			
		||||
from .utils import default_ovvpfile
 | 
			
		||||
from soustredeni.models import Soustredeni
 | 
			
		||||
from tvorba.models import Rocnik
 | 
			
		||||
from seminar.models import Rocnik, Soustredeni
 | 
			
		||||
from vysledkovky import utils
 | 
			
		||||
from tvorba.utils import aktivniResitele
 | 
			
		||||
from seminar.utils import aktivniResitele
 | 
			
		||||
 | 
			
		||||
class ExportIndexView(generic.View):
 | 
			
		||||
	def get(self, request):
 | 
			
		||||
		ls = []
 | 
			
		||||
		for r in Rocnik.objects.filter(exportovat = True):
 | 
			
		||||
	    		url = reverse('aesop_export_rocnik', kwargs={'prvni_rok': r.prvni_rok})
 | 
			
		||||
	    		url = reverse('seminar_export_rocnik', kwargs={'prvni_rok': r.prvni_rok})
 | 
			
		||||
	    		ls.append(url.split('/')[-1])
 | 
			
		||||
		for s in Soustredeni.objects.filter(exportovat = True):
 | 
			
		||||
			url = reverse('aesop_export_sous', kwargs={'datum_zacatku': s.datum_zacatku.isoformat()})
 | 
			
		||||
			url = reverse('seminar_export_sous', kwargs={'datum_zacatku': s.datum_zacatku.isoformat()})
 | 
			
		||||
			ls.append(url.split('/')[-1])
 | 
			
		||||
 | 
			
		||||
		return HttpResponse('\n'.join(ls) + '\n', content_type='text/plain; charset=utf-8')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,4 +3,3 @@ from django.apps import AppConfig
 | 
			
		|||
 | 
			
		||||
class ApiConfig(AppConfig):
 | 
			
		||||
    name = 'api'
 | 
			
		||||
    verbose_name = 'Různá webová API'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
from django.test import TestCase, tag
 | 
			
		||||
from django.test import TestCase
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
from personalni.models import Skola
 | 
			
		||||
from personalni.utils import sync_skoly
 | 
			
		||||
import seminar.models as m
 | 
			
		||||
import seminar.views as v
 | 
			
		||||
from seminar.utils import sync_skoly
 | 
			
		||||
 | 
			
		||||
@tag('stejny-model-na-produkci')
 | 
			
		||||
class OrgSkolyAutocompleteTestCase(TestCase):
 | 
			
		||||
	@classmethod
 | 
			
		||||
	def setUpClass(cls):
 | 
			
		||||
| 
						 | 
				
			
			@ -11,20 +11,19 @@ class OrgSkolyAutocompleteTestCase(TestCase):
 | 
			
		|||
		sync_skoly('https://mam.mff.cuni.cz/')
 | 
			
		||||
		# Správné školy podle toho, co orgové poslali: (prefix, ID školy)
 | 
			
		||||
		# NOTE: Pozor, jedná se o databázové indexy. Pokud se to někdy rozbije, bude potřeba je přepsat nebo předělat na IZO
 | 
			
		||||
		# TODO: Opravit zakomentované školy.
 | 
			
		||||
		cls.spravna_data = [
 | 
			
		||||
				('gymnázium kolín', 53),
 | 
			
		||||
				('kolín', 53),
 | 
			
		||||
				#('gasoš', 96),
 | 
			
		||||
				('gasoš', 96),
 | 
			
		||||
				('Rokycany', 96),
 | 
			
		||||
				#('gasoš Rokycany', 96),
 | 
			
		||||
				#('SPŠE Pardubice', 815),
 | 
			
		||||
				('gasoš Rokycany', 96),
 | 
			
		||||
				('SPŠE Pardubice', 815),
 | 
			
		||||
				('Jaroše', 164),
 | 
			
		||||
				#("Gymnázium, Brno, tř. Kpt. Jaroše", 164),
 | 
			
		||||
				("Gymnázium, Brno, tř. Kpt. Jaroše", 164),
 | 
			
		||||
				("Jírovcova", 157),
 | 
			
		||||
				('České Budějovice', 157),
 | 
			
		||||
				("Gymnázium, České Budějovice, Jírovcova 8", 157),
 | 
			
		||||
				#("první soukromé", 2),
 | 
			
		||||
				("první soukromé", 2),
 | 
			
		||||
				("Gymnázium Elgartova", 147),
 | 
			
		||||
				("Jihlava", 45),
 | 
			
		||||
				('Milevsko', 223),
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +47,7 @@ class OrgSkolyAutocompleteTestCase(TestCase):
 | 
			
		|||
		"""Testuje, že pro každého orga je jeho škola ve výsledném QuerySetu"""
 | 
			
		||||
		for pfx, id in self.spravna_data:
 | 
			
		||||
			with self.subTest(prefix=pfx, spravne_id=id):
 | 
			
		||||
				spravna_skola = Skola.objects.get(id=id)
 | 
			
		||||
				spravna_skola = m.Skola.objects.get(id=id)
 | 
			
		||||
				# Zeptáme se view, co si myslí
 | 
			
		||||
				resp = self.client.get(reverse('autocomplete_skola')+'?q='+pfx).json()
 | 
			
		||||
				ids = [int(x['id']) for x in resp['results']]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
from django.urls import path
 | 
			
		||||
from . import views
 | 
			
		||||
from personalni.utils import org_required
 | 
			
		||||
from seminar.utils import org_required
 | 
			
		||||
 | 
			
		||||
urlpatterns = [
 | 
			
		||||
	# Export škol
 | 
			
		||||
| 
						 | 
				
			
			@ -10,12 +10,10 @@ urlpatterns = [
 | 
			
		|||
	# Autocomplete
 | 
			
		||||
	path('api/autocomplete/skola/', views.SkolaAutocomplete.as_view(), name='autocomplete_skola'),
 | 
			
		||||
	path('api/autocomplete/resitel/', org_required(views.ResitelAutocomplete.as_view()), name='autocomplete_resitel'),
 | 
			
		||||
	path('api/autocomplete/resitel_public/', views.PublicResitelAutocomplete.as_view(), name='autocomplete_resitel_public'),
 | 
			
		||||
	path('api/autocomplete/problem/odevzdatelny', views.OdevzdatelnyProblemAutocomplete.as_view(), name='autocomplete_problem_odevzdatelny'),
 | 
			
		||||
	path('api/autocomplete/problem/vsechny', views.ProblemAutocomplete.as_view(), name='autocomplete_problem'),
 | 
			
		||||
 | 
			
		||||
	# Ceka na autocomplete v3
 | 
			
		||||
	# path('autocomplete/organizatori/',
 | 
			
		||||
	# org_member_required(views.OrganizatorAutocomplete.as_view()),
 | 
			
		||||
	# name='autocomplete_organizator')
 | 
			
		||||
	# name='seminar_autocomplete_organizator')
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,21 +1,15 @@
 | 
			
		|||
"""
 | 
			
		||||
	Views k :mod:`dal.autocomplete` pro vyhledávání objektů nějaké třídy v databázi.
 | 
			
		||||
"""
 | 
			
		||||
from dal import autocomplete
 | 
			
		||||
from django.shortcuts import get_object_or_404
 | 
			
		||||
from django.db.models import Q
 | 
			
		||||
 | 
			
		||||
from personalni.models import Skola, Resitel
 | 
			
		||||
from tvorba.models import Problem
 | 
			
		||||
from various.models import Nastaveni
 | 
			
		||||
import seminar.models as m
 | 
			
		||||
from .helpers import LoginRequiredAjaxMixin
 | 
			
		||||
 | 
			
		||||
# TODO filosofie - zkratky, jak v databázi, tak ve vyhledávání (SPŠE, GASOŠ, Kpt., soukr)
 | 
			
		||||
class SkolaAutocomplete(autocomplete.Select2QuerySetView):
 | 
			
		||||
	""" View k :mod:`dal.autocomplete` pro vyhledávání škol hlavně při registraci. """
 | 
			
		||||
	def get_queryset(self):
 | 
			
		||||
		# Don't forget to filter out results depending on the visitor !
 | 
			
		||||
		qs = Skola.objects.all()
 | 
			
		||||
        	# Don't forget to filter out results depending on the visitor !
 | 
			
		||||
		qs = m.Skola.objects.all()
 | 
			
		||||
		if self.q:
 | 
			
		||||
			words = self.q.split(' ') #TODO re split podle bileho znaku
 | 
			
		||||
			partq = Q()
 | 
			
		||||
| 
						 | 
				
			
			@ -31,70 +25,36 @@ class SkolaAutocomplete(autocomplete.Select2QuerySetView):
 | 
			
		|||
		return qs
 | 
			
		||||
 | 
			
		||||
class ResitelAutocomplete(LoginRequiredAjaxMixin,autocomplete.Select2QuerySetView):
 | 
			
		||||
	""" View k :mod:`dal.autocomplete` pro vyhledávání řešitelů především v odevzdávátku. """
 | 
			
		||||
	def get_queryset(self):
 | 
			
		||||
		qs = Resitel.objects.all()
 | 
			
		||||
		qs = m.Resitel.objects.all()
 | 
			
		||||
		if self.q:
 | 
			
		||||
			parts = self.q.split()
 | 
			
		||||
			query = Q()
 | 
			
		||||
			for part in parts:
 | 
			
		||||
				query &= (
 | 
			
		||||
					Q(osoba__jmeno__istartswith=part)|
 | 
			
		||||
					Q(osoba__prijmeni__istartswith=part)|
 | 
			
		||||
					Q(osoba__prezdivka__istartswith=part)
 | 
			
		||||
					Q(osoba__jmeno__istartswith=self.q)|
 | 
			
		||||
					Q(osoba__prijmeni__istartswith=self.q)|
 | 
			
		||||
					Q(osoba__prezdivka__istartswith=self.q)
 | 
			
		||||
				)
 | 
			
		||||
			qs = qs.filter(query)
 | 
			
		||||
		return qs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PublicResitelAutocomplete(LoginRequiredAjaxMixin, autocomplete.Select2QuerySetView):
 | 
			
		||||
	"""
 | 
			
		||||
		View k :mod:`dal.autocomplete` pro vyhledávání řešitelů podle přezdívky
 | 
			
		||||
		především v odevzdávátku.
 | 
			
		||||
	"""
 | 
			
		||||
	def get_queryset(self):
 | 
			
		||||
		letos = Nastaveni.get_solo().aktualni_rocnik
 | 
			
		||||
		qs = Resitel.objects.filter(
 | 
			
		||||
			rok_maturity__gte=letos.druhy_rok()
 | 
			
		||||
		).filter(
 | 
			
		||||
			prezdivka_resitele__isnull=False
 | 
			
		||||
		).exclude(
 | 
			
		||||
			prezdivka_resitele=""
 | 
			
		||||
		).filter(
 | 
			
		||||
			prezdivka_resitele__icontains=self.q
 | 
			
		||||
		).all()
 | 
			
		||||
		return qs
 | 
			
		||||
 | 
			
		||||
	def get_result_label(self, result):
 | 
			
		||||
		return result.prezdivka_resitele
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class OdevzdatelnyProblemAutocomplete(autocomplete.Select2QuerySetView):
 | 
			
		||||
	""" View k :mod:`dal.autocomplete` pro vyhledávání problémů především v odevzdávátku. """
 | 
			
		||||
	def get_queryset(self):
 | 
			
		||||
		qs = Problem.objects.filter(stav=Problem.STAV_ZADANY)
 | 
			
		||||
		if self.q:
 | 
			
		||||
			qs = qs.filter(
 | 
			
		||||
					Q(nazev__icontains=self.q))
 | 
			
		||||
 | 
			
		||||
		nadproblem_id = int(self.forwarded.get("nadproblem_id", -1))
 | 
			
		||||
		if nadproblem_id != -1:
 | 
			
		||||
			# Seřadíme tak, aby ty s nadproblem==None byly dole (větší motivace tam naklikat konkrétní úlohy) a pak nějak rozumně.
 | 
			
		||||
			# Tohle je řazení pro odevzdávátko, kde je definován nadproblém, proto je to v tomto ifu. (Jinde si to netroufám řadit)
 | 
			
		||||
			qs = qs.order_by("nadproblem", "kod", "nazev")
 | 
			
		||||
			qs = list(filter(lambda problem: problem.hlavni_problem.id == nadproblem_id, qs))
 | 
			
		||||
		return qs
 | 
			
		||||
 | 
			
		||||
class ProblemAutocomplete(autocomplete.Select2QuerySetView):
 | 
			
		||||
	""" View k :mod:`dal.autocomplete` pro vyhledávání problémů především v odevzdávátku. """
 | 
			
		||||
	def get_queryset(self):
 | 
			
		||||
		# FIXME i starší úlohy
 | 
			
		||||
		nastaveni = get_object_or_404(Nastaveni)
 | 
			
		||||
		nastaveni = get_object_or_404(m.Nastaveni)
 | 
			
		||||
		rocnik = nastaveni.aktualni_rocnik
 | 
			
		||||
		temaQ = Q(Tema___rocnik = rocnik)
 | 
			
		||||
		ulohaQ = Q(Uloha___cislo_zadani__rocnik=rocnik)
 | 
			
		||||
		clanekQ = Q(Clanek___cislo__rocnik=rocnik)
 | 
			
		||||
		qs = Problem.objects.filter(temaQ | ulohaQ | clanekQ).order_by("-stav", "nazev")
 | 
			
		||||
		# Od tohoto místa dál jsem zkoušel spoustu variací podle https://django-polymorphic.readthedocs.io/en/stable/advanced.html
 | 
			
		||||
		temaQ = Q(Tema___rocnik = rocnik, stav=m.Problem.STAV_ZADANY)
 | 
			
		||||
		ulohaQ = Q(Uloha___cislo_zadani__rocnik = rocnik, stav=m.Problem.STAV_ZADANY)
 | 
			
		||||
		clanekQ = Q(Clanek___cislo__rocnik = rocnik, stav=m.Problem.STAV_ZADANY)
 | 
			
		||||
		qs = m.Problem.objects.filter(temaQ | ulohaQ | clanekQ)
 | 
			
		||||
		#print(temata, ulohy, clanky)
 | 
			
		||||
		#ulohy.union(temata, all=True)
 | 
			
		||||
		#print(ulohy)
 | 
			
		||||
		#ulohy.union(clanky, all=True)
 | 
			
		||||
		#print(ulohy)
 | 
			
		||||
		#qs = ulohy
 | 
			
		||||
		print(qs)
 | 
			
		||||
		if self.q:
 | 
			
		||||
			qs = qs.filter(
 | 
			
		||||
					Q(nazev__icontains=self.q))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,7 @@
 | 
			
		|||
import personalni.models as m
 | 
			
		||||
import seminar.models as m
 | 
			
		||||
from django.core import serializers as ser
 | 
			
		||||
from django.http import HttpResponse
 | 
			
		||||
def exportSkolView(request):
 | 
			
		||||
	"""
 | 
			
		||||
		„view“, který vrací json se seznamem škol, u kterých je uvedeno: 'id', 'izo', 'nazev', 'kratky_nazev', 'ulice', 'mesto', 'psc', 'stat', 'je_zs', 'je_ss'
 | 
			
		||||
	"""
 | 
			
		||||
	# Některé fieldy nechceme: Kontaktní osoby, AESOP ID, org poznámky.
 | 
			
		||||
	fields = ('id', 'izo', 'nazev', 'kratky_nazev', 'ulice', 'mesto', 'psc', 'stat', 'je_zs', 'je_ss')
 | 
			
		||||
	# TODO: Použít JSONL, aby protistrana mohla číst po řádkách a nesežralo to tunu paměti úplně hned
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,9 +2,6 @@ from django.http import JsonResponse
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
class LoginRequiredAjaxMixin(object):
 | 
			
		||||
	"""
 | 
			
		||||
		Objekt přidávající povinnost být přihlášený k zobrazení daného view.
 | 
			
		||||
	"""
 | 
			
		||||
	def dispatch(self, request, *args, **kwargs):
 | 
			
		||||
		#if request.is_ajax() and not request.user.is_authenticated: # Pokud to otevřu jako stránku, tak se omezení neuplatní, takže to asi nechceme
 | 
			
		||||
		if not request.user.is_authenticated:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										655
									
								
								data/groups.json
									
									
									
									
									
								
							
							
						
						
									
										655
									
								
								data/groups.json
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,655 +0,0 @@
 | 
			
		|||
[
 | 
			
		||||
	{
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"name": "org",
 | 
			
		||||
			"permissions": [
 | 
			
		||||
				[
 | 
			
		||||
					"org",
 | 
			
		||||
					"auth",
 | 
			
		||||
					"user"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_flatpage",
 | 
			
		||||
					"flatpages",
 | 
			
		||||
					"flatpage"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_flatpage",
 | 
			
		||||
					"flatpages",
 | 
			
		||||
					"flatpage"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_flatpage",
 | 
			
		||||
					"flatpages",
 | 
			
		||||
					"flatpage"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_flatpage",
 | 
			
		||||
					"flatpages",
 | 
			
		||||
					"flatpage"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_galerie",
 | 
			
		||||
					"galerie",
 | 
			
		||||
					"galerie"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_galerie",
 | 
			
		||||
					"galerie",
 | 
			
		||||
					"galerie"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_galerie",
 | 
			
		||||
					"galerie",
 | 
			
		||||
					"galerie"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_galerie",
 | 
			
		||||
					"galerie",
 | 
			
		||||
					"galerie"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_obrazek",
 | 
			
		||||
					"galerie",
 | 
			
		||||
					"obrazek"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_obrazek",
 | 
			
		||||
					"galerie",
 | 
			
		||||
					"obrazek"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_obrazek",
 | 
			
		||||
					"galerie",
 | 
			
		||||
					"obrazek"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_obrazek",
 | 
			
		||||
					"galerie",
 | 
			
		||||
					"obrazek"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_fotkaheader",
 | 
			
		||||
					"header_fotky",
 | 
			
		||||
					"fotkaheader"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_fotkaheader",
 | 
			
		||||
					"header_fotky",
 | 
			
		||||
					"fotkaheader"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_fotkaheader",
 | 
			
		||||
					"header_fotky",
 | 
			
		||||
					"fotkaheader"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_fotkaurlvazba",
 | 
			
		||||
					"header_fotky",
 | 
			
		||||
					"fotkaurlvazba"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_fotkaurlvazba",
 | 
			
		||||
					"header_fotky",
 | 
			
		||||
					"fotkaurlvazba"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_fotkaurlvazba",
 | 
			
		||||
					"header_fotky",
 | 
			
		||||
					"fotkaurlvazba"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_komentar",
 | 
			
		||||
					"korektury",
 | 
			
		||||
					"komentar"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_komentar",
 | 
			
		||||
					"korektury",
 | 
			
		||||
					"komentar"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_komentar",
 | 
			
		||||
					"korektury",
 | 
			
		||||
					"komentar"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_komentar",
 | 
			
		||||
					"korektury",
 | 
			
		||||
					"komentar"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_korekturovanepdf",
 | 
			
		||||
					"korektury",
 | 
			
		||||
					"korekturovanepdf"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_korekturovanepdf",
 | 
			
		||||
					"korektury",
 | 
			
		||||
					"korekturovanepdf"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_korekturovanepdf",
 | 
			
		||||
					"korektury",
 | 
			
		||||
					"korekturovanepdf"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_korekturovanepdf",
 | 
			
		||||
					"korektury",
 | 
			
		||||
					"korekturovanepdf"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_oprava",
 | 
			
		||||
					"korektury",
 | 
			
		||||
					"oprava"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_oprava",
 | 
			
		||||
					"korektury",
 | 
			
		||||
					"oprava"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_oprava",
 | 
			
		||||
					"korektury",
 | 
			
		||||
					"oprava"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_oprava",
 | 
			
		||||
					"korektury",
 | 
			
		||||
					"oprava"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_novinky",
 | 
			
		||||
					"novinky",
 | 
			
		||||
					"novinky"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_novinky",
 | 
			
		||||
					"novinky",
 | 
			
		||||
					"novinky"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_novinky",
 | 
			
		||||
					"novinky",
 | 
			
		||||
					"novinky"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_novinky",
 | 
			
		||||
					"novinky",
 | 
			
		||||
					"novinky"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_organizator",
 | 
			
		||||
					"personalni",
 | 
			
		||||
					"organizator"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_organizator",
 | 
			
		||||
					"personalni",
 | 
			
		||||
					"organizator"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_osoba",
 | 
			
		||||
					"personalni",
 | 
			
		||||
					"osoba"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_osoba",
 | 
			
		||||
					"personalni",
 | 
			
		||||
					"osoba"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_prijemce",
 | 
			
		||||
					"personalni",
 | 
			
		||||
					"prijemce"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_prijemce",
 | 
			
		||||
					"personalni",
 | 
			
		||||
					"prijemce"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_prijemce",
 | 
			
		||||
					"personalni",
 | 
			
		||||
					"prijemce"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_prijemce",
 | 
			
		||||
					"personalni",
 | 
			
		||||
					"prijemce"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_resitel",
 | 
			
		||||
					"personalni",
 | 
			
		||||
					"resitel"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_resitel",
 | 
			
		||||
					"personalni",
 | 
			
		||||
					"resitel"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_skola",
 | 
			
		||||
					"personalni",
 | 
			
		||||
					"skola"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_skola",
 | 
			
		||||
					"personalni",
 | 
			
		||||
					"skola"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_skola",
 | 
			
		||||
					"personalni",
 | 
			
		||||
					"skola"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_skola",
 | 
			
		||||
					"personalni",
 | 
			
		||||
					"skola"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_hlasovani",
 | 
			
		||||
					"prednasky",
 | 
			
		||||
					"hlasovani"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_hlasovanioznalostech",
 | 
			
		||||
					"prednasky",
 | 
			
		||||
					"hlasovanioznalostech"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_prednaska",
 | 
			
		||||
					"prednasky",
 | 
			
		||||
					"prednaska"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_prednaska",
 | 
			
		||||
					"prednasky",
 | 
			
		||||
					"prednaska"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_prednaska",
 | 
			
		||||
					"prednasky",
 | 
			
		||||
					"prednaska"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_prednaska",
 | 
			
		||||
					"prednasky",
 | 
			
		||||
					"prednaska"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_seznam",
 | 
			
		||||
					"prednasky",
 | 
			
		||||
					"seznam"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_seznam",
 | 
			
		||||
					"prednasky",
 | 
			
		||||
					"seznam"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_seznam",
 | 
			
		||||
					"prednasky",
 | 
			
		||||
					"seznam"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_seznam",
 | 
			
		||||
					"prednasky",
 | 
			
		||||
					"seznam"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_znalost",
 | 
			
		||||
					"prednasky",
 | 
			
		||||
					"znalost"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_znalost",
 | 
			
		||||
					"prednasky",
 | 
			
		||||
					"znalost"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_znalost",
 | 
			
		||||
					"prednasky",
 | 
			
		||||
					"znalost"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_znalost",
 | 
			
		||||
					"prednasky",
 | 
			
		||||
					"znalost"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_konfera",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"konfera"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_konfera",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"konfera"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_konfera",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"konfera"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_konfera",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"konfera"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_konfery_ucastnici",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"konfery_ucastnici"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_konfery_ucastnici",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"konfery_ucastnici"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_konfery_ucastnici",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"konfery_ucastnici"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_konfery_ucastnici",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"konfery_ucastnici"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_soustredeni",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"soustredeni"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_soustredeni",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"soustredeni"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_soustredeni",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"soustredeni"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_soustredeni",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"soustredeni"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_soustredeni_organizatori",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"soustredeni_organizatori"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_soustredeni_organizatori",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"soustredeni_organizatori"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_soustredeni_organizatori",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"soustredeni_organizatori"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_soustredeni_organizatori",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"soustredeni_organizatori"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_soustredeni_ucastnici",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"soustredeni_ucastnici"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_soustredeni_ucastnici",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"soustredeni_ucastnici"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_soustredeni_ucastnici",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"soustredeni_ucastnici"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_soustredeni_ucastnici",
 | 
			
		||||
					"soustredeni",
 | 
			
		||||
					"soustredeni_ucastnici"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_tag",
 | 
			
		||||
					"taggit",
 | 
			
		||||
					"tag"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_tag",
 | 
			
		||||
					"taggit",
 | 
			
		||||
					"tag"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_tag",
 | 
			
		||||
					"taggit",
 | 
			
		||||
					"tag"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_tag",
 | 
			
		||||
					"taggit",
 | 
			
		||||
					"tag"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_taggeditem",
 | 
			
		||||
					"taggit",
 | 
			
		||||
					"taggeditem"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_taggeditem",
 | 
			
		||||
					"taggit",
 | 
			
		||||
					"taggeditem"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_taggeditem",
 | 
			
		||||
					"taggit",
 | 
			
		||||
					"taggeditem"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_taggeditem",
 | 
			
		||||
					"taggit",
 | 
			
		||||
					"taggeditem"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_cislo",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"cislo"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_cislo",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"cislo"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_cislo",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"cislo"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_cislo",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"cislo"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_clanek",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"clanek"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_clanek",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"clanek"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_clanek",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"clanek"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_clanek",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"clanek"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_deadline",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"deadline"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_deadline",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"deadline"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_deadline",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"deadline"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_pohadka",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"pohadka"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_pohadka",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"pohadka"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_pohadka",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"pohadka"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_pohadka",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"pohadka"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_problem",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"problem"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_problem",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"problem"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_problem",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"problem"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_problem",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"problem"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_rocnik",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"rocnik"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_rocnik",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"rocnik"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_rocnik",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"rocnik"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_rocnik",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"rocnik"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_tema",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"tema"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_tema",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"tema"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_tema",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"tema"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_tema",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"tema"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_uloha",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"uloha"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_uloha",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"uloha"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_uloha",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"uloha"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_uloha",
 | 
			
		||||
					"tvorba",
 | 
			
		||||
					"uloha"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"add_nastaveni",
 | 
			
		||||
					"various",
 | 
			
		||||
					"nastaveni"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"change_nastaveni",
 | 
			
		||||
					"various",
 | 
			
		||||
					"nastaveni"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"delete_nastaveni",
 | 
			
		||||
					"various",
 | 
			
		||||
					"nastaveni"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"view_nastaveni",
 | 
			
		||||
					"various",
 | 
			
		||||
					"nastaveni"
 | 
			
		||||
				]
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		"model": "auth.group",
 | 
			
		||||
		"pk": 1
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"name": "resitel",
 | 
			
		||||
			"permissions": [
 | 
			
		||||
				[
 | 
			
		||||
					"resitel",
 | 
			
		||||
					"auth",
 | 
			
		||||
					"user"
 | 
			
		||||
				]
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		"model": "auth.group",
 | 
			
		||||
		"pk": 2
 | 
			
		||||
	}
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			@ -73,7 +73,7 @@
 | 
			
		|||
			"sort_order": 3,
 | 
			
		||||
			"title": "Aktuální<br/> ročník",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "tvorba_aktualni_zadani",
 | 
			
		||||
			"url": "seminar_aktualni_zadani",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
| 
						 | 
				
			
			@ -121,7 +121,7 @@
 | 
			
		|||
			"sort_order": 5,
 | 
			
		||||
			"title": "Archiv",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "tvorba_archiv_rocniky",
 | 
			
		||||
			"url": "seminar_archiv_rocniky",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
| 
						 | 
				
			
			@ -289,7 +289,7 @@
 | 
			
		|||
			"sort_order": 43,
 | 
			
		||||
			"title": "Výsledková listina",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "tvorba_aktualni_vysledky",
 | 
			
		||||
			"url": "seminar_aktualni_vysledky",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
| 
						 | 
				
			
			@ -361,7 +361,7 @@
 | 
			
		|||
			"sort_order": 20,
 | 
			
		||||
			"title": "Proběhlo",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "soustredeni_seznam",
 | 
			
		||||
			"url": "seminar_seznam_soustredeni",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
| 
						 | 
				
			
			@ -409,7 +409,7 @@
 | 
			
		|||
			"sort_order": 23,
 | 
			
		||||
			"title": "Osobní údaje",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "personalni_resitel_edit",
 | 
			
		||||
			"url": "seminar_resitel_edit",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
| 
						 | 
				
			
			@ -437,9 +437,9 @@
 | 
			
		|||
			"insitetree": true,
 | 
			
		||||
			"parent": 21,
 | 
			
		||||
			"sort_order": 36,
 | 
			
		||||
			"title": "Nahrát řešení",
 | 
			
		||||
			"title": "Poslat řešení",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "odevzdavatko_nahraj_reseni",
 | 
			
		||||
			"url": "seminar_nahraj_reseni",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
| 
						 | 
				
			
			@ -463,7 +463,7 @@
 | 
			
		|||
			"sort_order": 35,
 | 
			
		||||
			"title": "Témata",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "tvorba_archiv_temata",
 | 
			
		||||
			"url": "seminar_archiv_temata",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
| 
						 | 
				
			
			@ -476,9 +476,9 @@
 | 
			
		|||
			"access_perm_type": 1,
 | 
			
		||||
			"access_permissions": [
 | 
			
		||||
				[
 | 
			
		||||
					"org",
 | 
			
		||||
					"auth",
 | 
			
		||||
					"user"
 | 
			
		||||
					"change_hodnoceni",
 | 
			
		||||
					"seminar",
 | 
			
		||||
					"hodnoceni"
 | 
			
		||||
				]
 | 
			
		||||
			],
 | 
			
		||||
			"access_restricted": true,
 | 
			
		||||
| 
						 | 
				
			
			@ -589,7 +589,7 @@
 | 
			
		|||
			"sort_order": 15,
 | 
			
		||||
			"title": "Aktuální číslo",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "tvorba_aktualni_zadani",
 | 
			
		||||
			"url": "seminar_aktualni_zadani",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
| 
						 | 
				
			
			@ -613,7 +613,7 @@
 | 
			
		|||
			"sort_order": 24,
 | 
			
		||||
			"title": "Čísla",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "tvorba_archiv_rocniky",
 | 
			
		||||
			"url": "seminar_archiv_rocniky",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
| 
						 | 
				
			
			@ -719,9 +719,9 @@
 | 
			
		|||
			"insitetree": true,
 | 
			
		||||
			"parent": 21,
 | 
			
		||||
			"sort_order": 36,
 | 
			
		||||
			"title": "Vložit řešení",
 | 
			
		||||
			"title": "Nahrát řešení",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "odevzdavatko_vloz_reseni",
 | 
			
		||||
			"url": "seminar_vloz_reseni",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
| 
						 | 
				
			
			@ -804,7 +804,7 @@
 | 
			
		|||
			"sort_order": 37,
 | 
			
		||||
			"title": "Moje řešení",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "odevzdavatko_resitel_odevzdana_reseni",
 | 
			
		||||
			"url": "seminar_resitel_odevzdana_reseni",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
| 
						 | 
				
			
			@ -828,7 +828,7 @@
 | 
			
		|||
			"sort_order": 33,
 | 
			
		||||
			"title": "Aktuální ročník",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "tvorba_aktualni_rocnik",
 | 
			
		||||
			"url": "seminar_aktualni_rocnik",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
| 
						 | 
				
			
			@ -900,7 +900,7 @@
 | 
			
		|||
			"sort_order": 46,
 | 
			
		||||
			"title": "Ročník {{rocnik.rocnik}}",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "tvorba_rocnik rocnik.rocnik",
 | 
			
		||||
			"url": "seminar_rocnik rocnik.rocnik",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
| 
						 | 
				
			
			@ -924,7 +924,7 @@
 | 
			
		|||
			"sort_order": 47,
 | 
			
		||||
			"title": "Číslo {{ cislo.rocnik.rocnik }}.{{ cislo.poradi }}",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "tvorba_cislo cislo.rocnik.rocnik cislo.poradi",
 | 
			
		||||
			"url": "seminar_cislo cislo.rocnik.rocnik cislo.poradi",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
| 
						 | 
				
			
			@ -1007,18 +1007,7 @@
 | 
			
		|||
			"access_guest": false,
 | 
			
		||||
			"access_loggedin": false,
 | 
			
		||||
			"access_perm_type": 1,
 | 
			
		||||
			"access_permissions": [
 | 
			
		||||
				[
 | 
			
		||||
					"org",
 | 
			
		||||
					"auth",
 | 
			
		||||
					"user"
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					"resitel",
 | 
			
		||||
					"auth",
 | 
			
		||||
					"user"
 | 
			
		||||
				]
 | 
			
		||||
			],
 | 
			
		||||
			"access_permissions": [],
 | 
			
		||||
			"access_restricted": true,
 | 
			
		||||
			"alias": null,
 | 
			
		||||
			"description": "",
 | 
			
		||||
| 
						 | 
				
			
			@ -1036,83 +1025,5 @@
 | 
			
		|||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
		"pk": 51
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"access_guest": false,
 | 
			
		||||
			"access_loggedin": false,
 | 
			
		||||
			"access_perm_type": 1,
 | 
			
		||||
			"access_permissions": [
 | 
			
		||||
				[
 | 
			
		||||
					"resitel",
 | 
			
		||||
					"auth",
 | 
			
		||||
					"user"
 | 
			
		||||
				]
 | 
			
		||||
			],
 | 
			
		||||
			"access_restricted": true,
 | 
			
		||||
			"alias": null,
 | 
			
		||||
			"description": "",
 | 
			
		||||
			"hidden": false,
 | 
			
		||||
			"hint": "",
 | 
			
		||||
			"inbreadcrumbs": true,
 | 
			
		||||
			"inmenu": true,
 | 
			
		||||
			"insitetree": true,
 | 
			
		||||
			"parent": 23,
 | 
			
		||||
			"sort_order": 52,
 | 
			
		||||
			"title": "Nahrát řešení k nadproblému {{nadproblem_id}}",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "odevzdavatko_nahraj_reseni nadproblem_id",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
		"pk": 52
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"access_guest": false,
 | 
			
		||||
			"access_loggedin": false,
 | 
			
		||||
			"access_perm_type": 1,
 | 
			
		||||
			"access_permissions": [],
 | 
			
		||||
			"access_restricted": false,
 | 
			
		||||
			"alias": null,
 | 
			
		||||
			"description": "",
 | 
			
		||||
			"hidden": false,
 | 
			
		||||
			"hint": "",
 | 
			
		||||
			"inbreadcrumbs": true,
 | 
			
		||||
			"inmenu": true,
 | 
			
		||||
			"insitetree": true,
 | 
			
		||||
			"parent": 28,
 | 
			
		||||
			"sort_order": 53,
 | 
			
		||||
			"title": "Přidat PDF",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "/admin/korektury/korekturovanepdf/add/",
 | 
			
		||||
			"urlaspattern": false
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
		"pk": 53
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"access_guest": false,
 | 
			
		||||
			"access_loggedin": false,
 | 
			
		||||
			"access_perm_type": 1,
 | 
			
		||||
			"access_permissions": [],
 | 
			
		||||
			"access_restricted": false,
 | 
			
		||||
			"alias": null,
 | 
			
		||||
			"description": "",
 | 
			
		||||
			"hidden": false,
 | 
			
		||||
			"hint": "",
 | 
			
		||||
			"inbreadcrumbs": true,
 | 
			
		||||
			"inmenu": true,
 | 
			
		||||
			"insitetree": true,
 | 
			
		||||
			"parent": 20,
 | 
			
		||||
			"sort_order": 54,
 | 
			
		||||
			"title": "Export do abstraktů sousu {{ soustredeni.id }}",
 | 
			
		||||
			"tree": 1,
 | 
			
		||||
			"url": "soustredeni_abstrakty soustredeni.id",
 | 
			
		||||
			"urlaspattern": true
 | 
			
		||||
		},
 | 
			
		||||
		"model": "sitetree.treeitem",
 | 
			
		||||
		"pk": 54
 | 
			
		||||
	}
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										637
									
								
								deploy_v2/admin_org_prava.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										637
									
								
								deploy_v2/admin_org_prava.json
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,637 @@
 | 
			
		|||
[
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "org",
 | 
			
		||||
		"ct_app_label": "auth",
 | 
			
		||||
		"ct_model": "user"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_flatpage",
 | 
			
		||||
		"ct_app_label": "flatpages",
 | 
			
		||||
		"ct_model": "flatpage"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_flatpage",
 | 
			
		||||
		"ct_app_label": "flatpages",
 | 
			
		||||
		"ct_model": "flatpage"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_flatpage",
 | 
			
		||||
		"ct_app_label": "flatpages",
 | 
			
		||||
		"ct_model": "flatpage"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_flatpage",
 | 
			
		||||
		"ct_app_label": "flatpages",
 | 
			
		||||
		"ct_model": "flatpage"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_galerie",
 | 
			
		||||
		"ct_app_label": "galerie",
 | 
			
		||||
		"ct_model": "galerie"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_galerie",
 | 
			
		||||
		"ct_app_label": "galerie",
 | 
			
		||||
		"ct_model": "galerie"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_galerie",
 | 
			
		||||
		"ct_app_label": "galerie",
 | 
			
		||||
		"ct_model": "galerie"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_galerie",
 | 
			
		||||
		"ct_app_label": "galerie",
 | 
			
		||||
		"ct_model": "galerie"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_obrazek",
 | 
			
		||||
		"ct_app_label": "galerie",
 | 
			
		||||
		"ct_model": "obrazek"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_obrazek",
 | 
			
		||||
		"ct_app_label": "galerie",
 | 
			
		||||
		"ct_model": "obrazek"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_obrazek",
 | 
			
		||||
		"ct_app_label": "galerie",
 | 
			
		||||
		"ct_model": "obrazek"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_obrazek",
 | 
			
		||||
		"ct_app_label": "galerie",
 | 
			
		||||
		"ct_model": "obrazek"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_komentar",
 | 
			
		||||
		"ct_app_label": "korektury",
 | 
			
		||||
		"ct_model": "komentar"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_komentar",
 | 
			
		||||
		"ct_app_label": "korektury",
 | 
			
		||||
		"ct_model": "komentar"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_komentar",
 | 
			
		||||
		"ct_app_label": "korektury",
 | 
			
		||||
		"ct_model": "komentar"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_komentar",
 | 
			
		||||
		"ct_app_label": "korektury",
 | 
			
		||||
		"ct_model": "komentar"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_korekturovanepdf",
 | 
			
		||||
		"ct_app_label": "korektury",
 | 
			
		||||
		"ct_model": "korekturovanepdf"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_korekturovanepdf",
 | 
			
		||||
		"ct_app_label": "korektury",
 | 
			
		||||
		"ct_model": "korekturovanepdf"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_korekturovanepdf",
 | 
			
		||||
		"ct_app_label": "korektury",
 | 
			
		||||
		"ct_model": "korekturovanepdf"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_korekturovanepdf",
 | 
			
		||||
		"ct_app_label": "korektury",
 | 
			
		||||
		"ct_model": "korekturovanepdf"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_oprava",
 | 
			
		||||
		"ct_app_label": "korektury",
 | 
			
		||||
		"ct_model": "oprava"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_oprava",
 | 
			
		||||
		"ct_app_label": "korektury",
 | 
			
		||||
		"ct_model": "oprava"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_oprava",
 | 
			
		||||
		"ct_app_label": "korektury",
 | 
			
		||||
		"ct_model": "oprava"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_oprava",
 | 
			
		||||
		"ct_app_label": "korektury",
 | 
			
		||||
		"ct_model": "oprava"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_hlasovani",
 | 
			
		||||
		"ct_app_label": "prednasky",
 | 
			
		||||
		"ct_model": "hlasovani"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_hlasovani",
 | 
			
		||||
		"ct_app_label": "prednasky",
 | 
			
		||||
		"ct_model": "hlasovani"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_hlasovani",
 | 
			
		||||
		"ct_app_label": "prednasky",
 | 
			
		||||
		"ct_model": "hlasovani"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_hlasovani",
 | 
			
		||||
		"ct_app_label": "prednasky",
 | 
			
		||||
		"ct_model": "hlasovani"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_prednaska",
 | 
			
		||||
		"ct_app_label": "prednasky",
 | 
			
		||||
		"ct_model": "prednaska"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_prednaska",
 | 
			
		||||
		"ct_app_label": "prednasky",
 | 
			
		||||
		"ct_model": "prednaska"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_prednaska",
 | 
			
		||||
		"ct_app_label": "prednasky",
 | 
			
		||||
		"ct_model": "prednaska"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_prednaska",
 | 
			
		||||
		"ct_app_label": "prednasky",
 | 
			
		||||
		"ct_model": "prednaska"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_seznam",
 | 
			
		||||
		"ct_app_label": "prednasky",
 | 
			
		||||
		"ct_model": "seznam"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_seznam",
 | 
			
		||||
		"ct_app_label": "prednasky",
 | 
			
		||||
		"ct_model": "seznam"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_seznam",
 | 
			
		||||
		"ct_app_label": "prednasky",
 | 
			
		||||
		"ct_model": "seznam"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_seznam",
 | 
			
		||||
		"ct_app_label": "prednasky",
 | 
			
		||||
		"ct_model": "seznam"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_cislo",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "cislo"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_cislo",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "cislo"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_cislo",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "cislo"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_cislo",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "cislo"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_clanek",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "clanek"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_clanek",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "clanek"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_clanek",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "clanek"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_clanek",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "clanek"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_konfera",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "konfera"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_konfera",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "konfera"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_konfera",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "konfera"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_konfera",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "konfera"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_konfery_ucastnici",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "konfery_ucastnici"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_konfery_ucastnici",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "konfery_ucastnici"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_konfery_ucastnici",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "konfery_ucastnici"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_konfery_ucastnici",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "konfery_ucastnici"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_nastaveni",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "nastaveni"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_nastaveni",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "nastaveni"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_nastaveni",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "nastaveni"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_nastaveni",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "nastaveni"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_novinky",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "novinky"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_novinky",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "novinky"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_novinky",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "novinky"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_novinky",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "novinky"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_organizator",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "organizator"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_organizator",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "organizator"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_organizator",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "organizator"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_organizator",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "organizator"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_osoba",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "osoba"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_osoba",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "osoba"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_osoba",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "osoba"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_osoba",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "osoba"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_pohadka",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "pohadka"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_pohadka",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "pohadka"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_pohadka",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "pohadka"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_pohadka",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "pohadka"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_prijemce",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "prijemce"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_prijemce",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "prijemce"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_prijemce",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "prijemce"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_prijemce",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "prijemce"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_problem",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "problem"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_problem",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "problem"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_problem",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "problem"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_problem",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "problem"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_resitel",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "resitel"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_resitel",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "resitel"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_resitel",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "resitel"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_resitel",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "resitel"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_rocnik",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "rocnik"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_rocnik",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "rocnik"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_rocnik",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "rocnik"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_rocnik",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "rocnik"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_skola",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "skola"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_skola",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "skola"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_skola",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "skola"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_skola",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "skola"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_soustredeni",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "soustredeni"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_soustredeni",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "soustredeni"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_soustredeni",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "soustredeni"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_soustredeni",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "soustredeni"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_soustredeni_organizatori",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "soustredeni_organizatori"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_soustredeni_organizatori",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "soustredeni_organizatori"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_soustredeni_organizatori",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "soustredeni_organizatori"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_soustredeni_organizatori",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "soustredeni_organizatori"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_soustredeni_ucastnici",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "soustredeni_ucastnici"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_soustredeni_ucastnici",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "soustredeni_ucastnici"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_soustredeni_ucastnici",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "soustredeni_ucastnici"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_soustredeni_ucastnici",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "soustredeni_ucastnici"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_tema",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "tema"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_tema",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "tema"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_tema",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "tema"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_tema",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "tema"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_uloha",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "uloha"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_uloha",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "uloha"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_uloha",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "uloha"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_uloha",
 | 
			
		||||
		"ct_app_label": "seminar",
 | 
			
		||||
		"ct_model": "uloha"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_tag",
 | 
			
		||||
		"ct_app_label": "taggit",
 | 
			
		||||
		"ct_model": "tag"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_tag",
 | 
			
		||||
		"ct_app_label": "taggit",
 | 
			
		||||
		"ct_model": "tag"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_tag",
 | 
			
		||||
		"ct_app_label": "taggit",
 | 
			
		||||
		"ct_model": "tag"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_tag",
 | 
			
		||||
		"ct_app_label": "taggit",
 | 
			
		||||
		"ct_model": "tag"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_taggeditem",
 | 
			
		||||
		"ct_app_label": "taggit",
 | 
			
		||||
		"ct_model": "taggeditem"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_taggeditem",
 | 
			
		||||
		"ct_app_label": "taggit",
 | 
			
		||||
		"ct_model": "taggeditem"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "delete_taggeditem",
 | 
			
		||||
		"ct_app_label": "taggit",
 | 
			
		||||
		"ct_model": "taggeditem"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_taggeditem",
 | 
			
		||||
		"ct_app_label": "taggit",
 | 
			
		||||
		"ct_model": "taggeditem"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_fotkaheader",
 | 
			
		||||
		"ct_app_label": "header_fotky",
 | 
			
		||||
		"ct_model": "fotkaheader"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_fotkaheader",
 | 
			
		||||
		"ct_app_label": "header_fotky",
 | 
			
		||||
		"ct_model": "fotkaheader"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_fotkaheader",
 | 
			
		||||
		"ct_app_label": "header_fotky",
 | 
			
		||||
		"ct_model": "fotkaheader"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "add_fotkaurlvazba",
 | 
			
		||||
		"ct_app_label": "header_fotky",
 | 
			
		||||
		"ct_model": "fotkaurlvazba"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "change_fotkaurlvazba",
 | 
			
		||||
		"ct_app_label": "header_fotky",
 | 
			
		||||
		"ct_model": "fotkaurlvazba"
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"codename": "view_fotkaurlvazba",
 | 
			
		||||
		"ct_app_label": "header_fotky",
 | 
			
		||||
		"ct_model": "fotkaurlvazba"
 | 
			
		||||
	}
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +13,7 @@ make install_venv
 | 
			
		|||
make install
 | 
			
		||||
deploy_v2/pre_migration.py
 | 
			
		||||
make deploy_test
 | 
			
		||||
./manage.py load_org_permissions admin_org_prava.json
 | 
			
		||||
./manage.py loaddata data/*
 | 
			
		||||
systemctl --user start mamweb-test.service
 | 
			
		||||
./manage.py generate_thumbnails
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,21 +0,0 @@
 | 
			
		|||
# Minimal makefile for Sphinx documentation
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
# You can set these variables from the command line, and also
 | 
			
		||||
# from the environment for the first two.
 | 
			
		||||
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
 | 
			
		||||
	sphinx-apidoc --module-first -o modules .. ../*/migrations --templatedir _templates -f
 | 
			
		||||
	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
 | 
			
		||||
							
								
								
									
										8
									
								
								docs/_templates/module.rst_t
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								docs/_templates/module.rst_t
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,8 +0,0 @@
 | 
			
		|||
{%- if show_headings %}
 | 
			
		||||
{{- [basename, ".py"] | join('') | e | heading }}
 | 
			
		||||
 | 
			
		||||
{% endif -%}
 | 
			
		||||
.. automodule:: {{ qualname }}
 | 
			
		||||
{%- for option in automodule_options %}
 | 
			
		||||
   :{{ option }}:
 | 
			
		||||
{%- endfor %}
 | 
			
		||||
							
								
								
									
										57
									
								
								docs/_templates/package.rst_t
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										57
									
								
								docs/_templates/package.rst_t
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,57 +0,0 @@
 | 
			
		|||
{%- macro automodule(modname, options) -%}
 | 
			
		||||
.. automodule:: {{ modname }}
 | 
			
		||||
{%- for option in options %}
 | 
			
		||||
   :{{ option }}:
 | 
			
		||||
{%- endfor %}
 | 
			
		||||
{%- endmacro %}
 | 
			
		||||
 | 
			
		||||
{%- macro toctree(docnames) -%}
 | 
			
		||||
.. toctree::
 | 
			
		||||
   :maxdepth: {{ maxdepth }}
 | 
			
		||||
{% for docname in docnames %}
 | 
			
		||||
   {{ docname }}
 | 
			
		||||
{%- endfor %}
 | 
			
		||||
{%- endmacro %}
 | 
			
		||||
 | 
			
		||||
{%- if is_namespace %}
 | 
			
		||||
{{- pkgname | e | heading }}
 | 
			
		||||
{% else %}
 | 
			
		||||
{{- pkgname | e | heading }}
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
{%- if is_namespace %}
 | 
			
		||||
.. py:module:: {{ pkgname }}
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
{%- if modulefirst and not is_namespace %}
 | 
			
		||||
{{ automodule(pkgname, automodule_options) }}
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
{%- if subpackages %}
 | 
			
		||||
{# Subpackages #}
 | 
			
		||||
{# ----------- #}
 | 
			
		||||
 | 
			
		||||
{{ toctree(subpackages) }}
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
{%- if submodules %}
 | 
			
		||||
{# Submodules #}
 | 
			
		||||
{# ---------- #}
 | 
			
		||||
{% if separatemodules %}
 | 
			
		||||
{{ toctree(submodules) }}
 | 
			
		||||
{% else %}
 | 
			
		||||
{%- for submodule in submodules %}
 | 
			
		||||
{% if show_headings %}
 | 
			
		||||
{{- submodule | e | heading(2) }}
 | 
			
		||||
{% endif %}
 | 
			
		||||
{{ automodule(submodule, automodule_options) }}
 | 
			
		||||
{% endfor %}
 | 
			
		||||
{%- endif %}
 | 
			
		||||
{%- endif %}
 | 
			
		||||
 | 
			
		||||
{%- if not modulefirst and not is_namespace %}
 | 
			
		||||
Module contents
 | 
			
		||||
---------------
 | 
			
		||||
 | 
			
		||||
{{ automodule(pkgname, automodule_options) }}
 | 
			
		||||
{% endif %}
 | 
			
		||||
							
								
								
									
										7
									
								
								docs/_templates/toc.rst_t
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								docs/_templates/toc.rst_t
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,7 +0,0 @@
 | 
			
		|||
{{ "Seznam aplikací" | heading }}
 | 
			
		||||
 | 
			
		||||
.. toctree::
 | 
			
		||||
   :maxdepth: {{ maxdepth }}
 | 
			
		||||
{% for docname in docnames %}
 | 
			
		||||
   {{ docname }}
 | 
			
		||||
{%- endfor %}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +0,0 @@
 | 
			
		|||
Aprílové nápad
 | 
			
		||||
==============
 | 
			
		||||
 | 
			
		||||
* aprílový easter-egg pro řešitele - vytvořit nějakou vtipnou testovací databázi a nasadit ji místo produkce
 | 
			
		||||
* změnit veškerý text na oranžovo
 | 
			
		||||
							
								
								
									
										103
									
								
								docs/conf.py
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								docs/conf.py
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,103 +0,0 @@
 | 
			
		|||
# Configuration file for the Sphinx documentation builder.
 | 
			
		||||
#
 | 
			
		||||
# This file only contains a selection of the most common options. For a full
 | 
			
		||||
# list see the documentation:
 | 
			
		||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
 | 
			
		||||
 | 
			
		||||
# -- 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
 | 
			
		||||
import django
 | 
			
		||||
from django.utils.version import get_docs_version
 | 
			
		||||
sys.path.insert(0, os.path.abspath('..'))
 | 
			
		||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'mamweb.settings'
 | 
			
		||||
django.setup()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# -- Project information -----------------------------------------------------
 | 
			
		||||
 | 
			
		||||
project = 'Web M&M'
 | 
			
		||||
copyright = '2022, Orgové'
 | 
			
		||||
author = 'Orgové'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# -- General configuration ---------------------------------------------------
 | 
			
		||||
 | 
			
		||||
# 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.autodoc',
 | 
			
		||||
    'sphinx.ext.viewcode',
 | 
			
		||||
    'sphinx.ext.intersphinx',
 | 
			
		||||
    'sphinx.ext.autosectionlabel',
 | 
			
		||||
    'myst_parser',
 | 
			
		||||
	'sphinxcontrib_django',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# Add any paths that contain templates here, relative to this directory.
 | 
			
		||||
templates_path = ['_templates']
 | 
			
		||||
 | 
			
		||||
# 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 = 'cs'
 | 
			
		||||
 | 
			
		||||
# 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']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# -- Options for HTML output -------------------------------------------------
 | 
			
		||||
 | 
			
		||||
# The theme to use for HTML and HTML Help pages.  See the documentation for
 | 
			
		||||
# a list of builtin themes.
 | 
			
		||||
#
 | 
			
		||||
import sphinx_rtd_theme
 | 
			
		||||
 | 
			
		||||
html_theme = 'sphinx_rtd_theme'
 | 
			
		||||
 | 
			
		||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
 | 
			
		||||
 | 
			
		||||
# 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']
 | 
			
		||||
 | 
			
		||||
# Provázání s jinými dokumentacemi
 | 
			
		||||
intersphinx_mapping = {'python': ('https://docs.python.org/3', None),
 | 
			
		||||
                       'django': (f'http://docs.djangoproject.com/en/{get_docs_version()}/',
 | 
			
		||||
                        f'http://docs.djangoproject.com/en/{get_docs_version()}/_objects/'),}
 | 
			
		||||
 | 
			
		||||
# Generování tříd/funkcí/atributů v pořádí jak jsou naprogramované
 | 
			
		||||
autodoc_member_order = "bysource"
 | 
			
		||||
 | 
			
		||||
# Nezobrazování zděděné (ze super tříd) dokumentace TODO nefunguje?
 | 
			
		||||
autodoc_inherit_docstrings = False
 | 
			
		||||
 | 
			
		||||
source_suffix = {
 | 
			
		||||
    '.rst': 'restructuredtext',
 | 
			
		||||
    '.md': 'markdown',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Autodoc má ignorovat některé moduly
 | 
			
		||||
# Ref: https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#event-autodoc-skip-member
 | 
			
		||||
# Kudos: https://stackoverflow.com/a/21449475/
 | 
			
		||||
def ignorovat(app, what, name, obj, skip, options):
 | 
			
		||||
	blacklist = (
 | 
			
		||||
		# typ (what), name
 | 
			
		||||
		('module', 'settings.mamweb_prod'),
 | 
			
		||||
		)
 | 
			
		||||
	ignore = (what, name) in blacklist
 | 
			
		||||
	return True if ignore else None
 | 
			
		||||
 | 
			
		||||
def setup(app):
 | 
			
		||||
	app.connect('autodoc-skip-member', ignorovat)
 | 
			
		||||
							
								
								
									
										27
									
								
								docs/css.rst
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								docs/css.rst
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,27 +0,0 @@
 | 
			
		|||
CSS (a další styly na webu)
 | 
			
		||||
===========================
 | 
			
		||||
 | 
			
		||||
Inspirován `css-trick článkem <https://css-tricks.com/methods-organize-css/>`_ jsem se rozhodl rozdělit
 | 
			
		||||
CSSka do
 | 
			
		||||
 | 
			
		||||
- Konstant (``constants.css``), které jsou využívány na mnoha místech CSSek
 | 
			
		||||
- Nastylování html tagů (``base.css``)
 | 
			
		||||
- Layoutu (``layout.css``), což je to, co určuje celkové rozložení stránky
 | 
			
		||||
- Jednotlivých prvků (``modules.css``)
 | 
			
		||||
 | 
			
		||||
Dále jsem separoval CSSka pro **galerii** (potřebuje hodně specifických stylů). Stejně tak **korekturovátko** má styly separátně.
 | 
			
		||||
 | 
			
		||||
Dále web (asi) používá externí frameworky (v separátních složkách – mají k sobě i JS a podobné věci):
 | 
			
		||||
 | 
			
		||||
- bootstrap: dělá nějaké basic stylování, *web je na něm hodně závislý* (například jsem zjistil, že bootstrap kdysi přidával ``font-size:14px``, bez čehož se web úplně rozpadnul) (také na něm běží mobilní meníčko, které navíc vyžaduje Popper, tedy bootstrap.bundle.js místo bootstrap.js)
 | 
			
		||||
 | 
			
		||||
Pak jsou tu ``mamweb-dev.css`` a ``printtable.css``, co jsem si ještě nerozmyslel, co s tím.
 | 
			
		||||
 | 
			
		||||
Pár myšlenek
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
- Až na pár výjimek (galerii a korekturovátko) bych styly držel v jedné složce a málo souborech,
 | 
			
		||||
protože CSS šíleně dědí všechno možné
 | 
			
		||||
- Chce to dobře pojmenovávat třídy (speciálně aby bylo vidět, co ta třída dělá nebo kde se používá)
 | 
			
		||||
- Chce to hodně komentovat kód (speciálně tam, kde není splněn předchozí bod)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,86 +0,0 @@
 | 
			
		|||
Další soubory/složky v kořenovém adresáři
 | 
			
		||||
=========================================
 | 
			
		||||
 | 
			
		||||
media
 | 
			
		||||
-----
 | 
			
		||||
Složka, kam django nahrává soubory „jako by je nahrávalo do databáze“.
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
------
 | 
			
		||||
Složka, kam django nakopíruje všechno ze složek static a pak na to z templatů / kódu jde ukazovat pomocí ``static``.
 | 
			
		||||
 | 
			
		||||
data
 | 
			
		||||
----
 | 
			
		||||
Obsahuje data, která patří do databáze, ale jsou přímo součástí webu jako
 | 
			
		||||
takového. Aktuálně jsou to statické stránky, meníčko a rozložení obrázků
 | 
			
		||||
v pozadí meníčka.
 | 
			
		||||
 | 
			
		||||
Generuje se za pomocí::
 | 
			
		||||
 | 
			
		||||
    ./manage.py dumpdata flatpages > data/flat_new.json
 | 
			
		||||
    ./fix_json.py data/flat_new.json data/flat.json
 | 
			
		||||
 | 
			
		||||
nebo (v případě meníčka)::
 | 
			
		||||
 | 
			
		||||
    ./manage.py dumpdata sitetree --natural-foreign > data/sitetree_new.json
 | 
			
		||||
    ./fix_json.py data/sitetree_new.json data/sitetree.json
 | 
			
		||||
 | 
			
		||||
deploy_v2
 | 
			
		||||
---------
 | 
			
		||||
Věci, které byly potřeba při nasazování nového (2021) webu.
 | 
			
		||||
 | 
			
		||||
docs
 | 
			
		||||
----
 | 
			
		||||
Zde je dokumentace webu. Viz :ref:`Sphinx na našem webu`.
 | 
			
		||||
 | 
			
		||||
setup
 | 
			
		||||
-----
 | 
			
		||||
Tato složka obsahuje různé konfiguráky potřebné k rozběhnutí webu na serveru.
 | 
			
		||||
 | 
			
		||||
vue_frontend
 | 
			
		||||
------------
 | 
			
		||||
Obsahuje první pokusy o editory treenodů ve vue.
 | 
			
		||||
 | 
			
		||||
.gitignore
 | 
			
		||||
----------
 | 
			
		||||
Klasické `.gitignore`_
 | 
			
		||||
 | 
			
		||||
.. _.gitignore: https://git-scm.com/docs/gitignore
 | 
			
		||||
 | 
			
		||||
checklinks.sh
 | 
			
		||||
-------------
 | 
			
		||||
„Týrací“ skript na kontrolu, že nic, kam se lze proklikat na webu, nehází chybu.
 | 
			
		||||
 | 
			
		||||
constraints.txt
 | 
			
		||||
---------------
 | 
			
		||||
Obsahuje omezení na :ref:`requirements.txt`.
 | 
			
		||||
 | 
			
		||||
convert_spaces_to_tabs.sh
 | 
			
		||||
-------------------------
 | 
			
		||||
Skript na změnu odsazování.
 | 
			
		||||
 | 
			
		||||
db-local.sqlite3
 | 
			
		||||
----------------
 | 
			
		||||
Lokální databáze (na serveru není).
 | 
			
		||||
 | 
			
		||||
diff_db_backup.sh
 | 
			
		||||
-----------------
 | 
			
		||||
Nevím. Typoval bych skript na diff záloh (resp. dumpů) databáze.
 | 
			
		||||
 | 
			
		||||
Makefile
 | 
			
		||||
--------
 | 
			
		||||
Klasické `Makefile`_. Obsahuje například vytvoření virtual_env, instalaci a nasazování webu.
 | 
			
		||||
 | 
			
		||||
.. _Makefile: https://www.gnu.org/software/make/manual/make.html
 | 
			
		||||
 | 
			
		||||
manage.py
 | 
			
		||||
---------
 | 
			
		||||
Základní soubor djanga.
 | 
			
		||||
 | 
			
		||||
README.md
 | 
			
		||||
---------
 | 
			
		||||
Většina je spíš zbytek po bývalých webařích.
 | 
			
		||||
 | 
			
		||||
requirements.txt
 | 
			
		||||
----------------
 | 
			
		||||
Seznam balíčků, které jsou potřeba pro běh mamwebu. (Cílem je vytvoření virtualenvu se všemi těmito balíčky, např. pomocí daného příkazu v :ref:`Makefile`.)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,55 +0,0 @@
 | 
			
		|||
Defaultní dokumentace speciálních souborů
 | 
			
		||||
=========================================
 | 
			
		||||
 | 
			
		||||
Drobná nápověda k běžným django souborům. (Do nich jsem to vkládal copy-paste.)
 | 
			
		||||
 | 
			
		||||
admin.py
 | 
			
		||||
--------
 | 
			
		||||
Soubor sloužící k definici toho, co bude v adminu. Většinou pouhým zavoláním
 | 
			
		||||
funkce :func:`django.contrib.admin.site.register`, v případě, že chceme něco
 | 
			
		||||
upravit, tak jako třída rozšiřující :class:`django.contrib.admin.ModelAdmin`
 | 
			
		||||
s dekorátorem :func:`django.contrib.admin.register`.
 | 
			
		||||
 | 
			
		||||
Zde se definuje admin pro:
 | 
			
		||||
 | 
			
		||||
apps.py
 | 
			
		||||
-------
 | 
			
		||||
Soubor sloužící k pojmenování a jiným nastavením djangovské aplikace.
 | 
			
		||||
 | 
			
		||||
forms.py
 | 
			
		||||
--------
 | 
			
		||||
Formuláře (:class:`django.forms.Form`) umožňují jednoduchou tvorbu formulářů,
 | 
			
		||||
které lze pak jednoduše dát do frontendu i zpracovat na backendu.
 | 
			
		||||
 | 
			
		||||
Pro přidání políčka do formuláře je potřeba
 | 
			
		||||
 - mít v modelu tu položku, kterou chci upravovat
 | 
			
		||||
 - přidat do views (prihlaskaView, resitelEditView)
 | 
			
		||||
 - přidat do forms
 | 
			
		||||
 - includovat do html
 | 
			
		||||
 | 
			
		||||
models.py
 | 
			
		||||
---------
 | 
			
		||||
Tento soubor slouží k definici databázového modelu.
 | 
			
		||||
 | 
			
		||||
Třídy rozšiřují většinou :class:`django.db.models.Model` a jejich atributy jsou
 | 
			
		||||
většinou sloupce v databázi (tj. nastaví se na hodnotu něčeho z :mod:`django.db.models`).
 | 
			
		||||
Na výběr jsou:
 | 
			
		||||
 | 
			
		||||
	- :class:`django.db.models.TextField`
 | 
			
		||||
	- :class:`django.db.models.ForeignKey`
 | 
			
		||||
	- :class:`django.db.models.DateField`
 | 
			
		||||
	- :class:`django.db.models.DateTimeField`
 | 
			
		||||
	- :class:`django.db.models.ImageField`
 | 
			
		||||
	- :class:`django.db.models.CharField`
 | 
			
		||||
 | 
			
		||||
testutils.py
 | 
			
		||||
------------
 | 
			
		||||
Soubor sloužící ke generování testdat.
 | 
			
		||||
 | 
			
		||||
urls.py
 | 
			
		||||
-------
 | 
			
		||||
Soubor sloužící jako „router“, tj. zde se definují url adresy a na co ukazují:
 | 
			
		||||
 | 
			
		||||
views.py
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,45 +0,0 @@
 | 
			
		|||
.. Web M&M documentation master file, created by
 | 
			
		||||
   sphinx-quickstart on Mon Jan 31 21:56:04 2022.
 | 
			
		||||
   You can adapt this file completely to your liking, but it should at least
 | 
			
		||||
   contain the root `toctree` directive.
 | 
			
		||||
 | 
			
		||||
Vítejte v dokumentaci M&Mího webu!
 | 
			
		||||
===================================
 | 
			
		||||
 | 
			
		||||
Tzv. produkce (tedy to, co vidí uživatelé) běží na `<mam.mff.cuni.cz>`_ (resp.
 | 
			
		||||
`<mam.matfyz.cz>`_), menu, obrázky v pozadí menu a spousta stránek (ty pouze se
 | 
			
		||||
statickým textem/obrázky) se mění přímo na produkci. Testovací verze běží na
 | 
			
		||||
`<https://mam-test.ks.matfyz.cz/>`_.
 | 
			
		||||
 | 
			
		||||
Abychom uměli web vyvíjet, musíme ho většinou nejdřív umět
 | 
			
		||||
:doc:`naklonovat a spustit lokálně <vyvoj>`.
 | 
			
		||||
 | 
			
		||||
:doc:`struktura mamwebu <struktura>` se řídí hlavně djangem, ale snažíme se
 | 
			
		||||
také o oddělení jednotlivých částí do :doc:`samostatných aplikací
 | 
			
		||||
<modules/modules>`.
 | 
			
		||||
 | 
			
		||||
Dokumentace (jak v ``docs/``, tak přímo v kódu) je psaná ve
 | 
			
		||||
:doc:`sphinxu <sphinx>`.
 | 
			
		||||
 | 
			
		||||
.. toctree::
 | 
			
		||||
   :caption: M&M web
 | 
			
		||||
   :maxdepth: 2
 | 
			
		||||
   :titlesonly:
 | 
			
		||||
 | 
			
		||||
   vyvoj
 | 
			
		||||
   zavislosti
 | 
			
		||||
   sphinx
 | 
			
		||||
   skripty
 | 
			
		||||
   zkratky
 | 
			
		||||
   modules/modules
 | 
			
		||||
   dalsi_soubory
 | 
			
		||||
   zapisy/zapisy
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Rejstříky a vyhledávání
 | 
			
		||||
==================
 | 
			
		||||
 | 
			
		||||
* :ref:`genindex`
 | 
			
		||||
* :ref:`modindex`
 | 
			
		||||
* :ref:`search`
 | 
			
		||||
							
								
								
									
										108
									
								
								docs/skripty.rst
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								docs/skripty.rst
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,108 +0,0 @@
 | 
			
		|||
Skripty pro práci s repozitářem
 | 
			
		||||
===================
 | 
			
		||||
 | 
			
		||||
Máme dvě hlavní sady skriptů/příkazů na ovládání webu a repozitáře. Skripty pro
 | 
			
		||||
práci s webem psané v Pythonu jsou uložené ve složkách
 | 
			
		||||
``<aplikace>/management/commands/``, případně vestavěné, a volají se pomocí
 | 
			
		||||
``./manage.py <příkaz>``. Oproti tomu skripty pro práci s repozitářem a pro
 | 
			
		||||
úpravy databáze a souborů „zvenčí“ se nejčastěji nacházejí ve složce ``make/``
 | 
			
		||||
a volají se pomocí cesty: ``make/<příkaz>``.
 | 
			
		||||
 | 
			
		||||
Občas existují i nějaké další skripty na různých jiných místech. Všechny by
 | 
			
		||||
měly být ideálně popsány asi tady.
 | 
			
		||||
 | 
			
		||||
Make skripty
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
Skripty v ``make/`` se označují jako „Make skripty“. Slouží často k velkým
 | 
			
		||||
úkonům s repozitářem, jako je nasazení celého webu, zprovoznění lokálního webu
 | 
			
		||||
a podobně.
 | 
			
		||||
 | 
			
		||||
.. note:: Označení pro tyto skripty je dáno tím, že byly původně volány pomocí
 | 
			
		||||
   make (tj. z Makefile). Ve skutečnosti je lze stále volat i jako ``make
 | 
			
		||||
   <skript>``, ale pak není možné předávat parametry a obecně je tato cesta
 | 
			
		||||
   zastaralá a existuje jen pro zpětnou kompatibilitu se svalovou pamětí.
 | 
			
		||||
 | 
			
		||||
Tyto skripty jsou samonosné, dají se spustit rovnou a v případě problémů si
 | 
			
		||||
budou hlasitě stěžovat. Pro účely debugování různých věcí jsou ale (bohužel?)
 | 
			
		||||
hlasité i při normálním spuštění, konkrétně vypisují všechny příkazy, které se
 | 
			
		||||
spouštějí (\ ``set -x``). Tyto příkazy jsou vidět za jedním či více plusky (\ ``+``).
 | 
			
		||||
 | 
			
		||||
.. tip:: Pokud některý make skript selže, tak by na konci měl vypsat, že se něco nepovedlo.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Knihovna ``make/lib.sh``
 | 
			
		||||
^^^^^^
 | 
			
		||||
 | 
			
		||||
Pro pohodlí při psaní velká část z nich využívá knihovnu uloženou
 | 
			
		||||
v ``make/lib.sh``. Jsou zde definované užitečné proměnné, kontroly a společný
 | 
			
		||||
kód. Kromě toho při inicializaci otestuje, že je skript spuštěn z kořene
 | 
			
		||||
repozitáře (takže to pak není potřeba zkoumat v ostatních skriptech).
 | 
			
		||||
 | 
			
		||||
Proměnné
 | 
			
		||||
"""""
 | 
			
		||||
 | 
			
		||||
Popsány jsou jen užitečné proměnné, ve skutečnosti jich je definovaných víc,
 | 
			
		||||
ale jsou triviální a samopopisné.
 | 
			
		||||
 | 
			
		||||
``VENV_PATH``
 | 
			
		||||
  Cesta virtuálního prostředí. Též lze přepsat.
 | 
			
		||||
``REPO``
 | 
			
		||||
  Cesta ke gitovému repozitáři na serveru, rovnou použitelná v ``git clone``
 | 
			
		||||
``GIMLI_LOGIN``
 | 
			
		||||
  Přihlašovací údaje ke Gimlimu
 | 
			
		||||
``PRODWEB`` a ``TESTWEB``
 | 
			
		||||
  Cesty ke složkám s produkčním a testovacím webem
 | 
			
		||||
 | 
			
		||||
Funkce a další zkratky
 | 
			
		||||
""""""
 | 
			
		||||
 | 
			
		||||
``ensure_venv``
 | 
			
		||||
  Zajistí, že se zbytek skriptu spustí ve virtuálním prostředí, a pokud neexistuje, tak jej založí.
 | 
			
		||||
``ensure_web_installed``
 | 
			
		||||
  Vyzkouší, že je web (django) aspoň elementárně zprovozněno a pokud ne, tak vyzve uživatele, aby to spravil.
 | 
			
		||||
``gimli_only``
 | 
			
		||||
  Otestuje, že je příkaz spuštěn na Gimlim, pokud tomu tak není, zeptá se, jestli si uživatel skutečně přeje zbytek skriptu vykonat
 | 
			
		||||
``only_in_directory <složka>``
 | 
			
		||||
  Otestuje, že skript běží z konkrétní složky. Zejména použitelné s ``gimli_only`` a ``$TESTWEB``
 | 
			
		||||
``safe_checkout_branch <větev>``
 | 
			
		||||
  Bezpečně přepne repozitář na jinou větev. Pokud by mělo dojít k přepsání
 | 
			
		||||
  knihovny nebo volajícího make skriptu, vyzve uživatele, aby přepnul ručně.
 | 
			
		||||
``install_everything``
 | 
			
		||||
  Společná část kódu pro nasazování produkce a testwebu.
 | 
			
		||||
 | 
			
		||||
Skripty pro lokální vývoj
 | 
			
		||||
^^^^^^^
 | 
			
		||||
 | 
			
		||||
``make/install_web`` (nebo ekvivalentně ``make/install``)
 | 
			
		||||
  Vytvoří virtualenv a nainstaluje do něj závislosti webu podle ``requirements.txt``. Následně popíše, jak vyrobit zbytek lokálního webu.
 | 
			
		||||
``make/run``
 | 
			
		||||
  Spustí lokální web (ekvivalentní s ``./manage.py runserver``)
 | 
			
		||||
``make/schema``
 | 
			
		||||
  Vykreslí závislosti a atributy modelů
 | 
			
		||||
``make/sync_prod_flatpages``
 | 
			
		||||
  Stáhne z produkce aktuální statické stránky a uloží je do složky ``data/``
 | 
			
		||||
``make/test``
 | 
			
		||||
  Spustí testy (ekvivalentní s ``./manage.py test -v2``)
 | 
			
		||||
``make/init_local``
 | 
			
		||||
  Zkratka za posloupnost ``make/install_web``, ``./manage.py testdata``, ``./manage.py loaddata data/*``, ``make/sync_prod_flatpages``
 | 
			
		||||
 | 
			
		||||
Práce s testwebem
 | 
			
		||||
^^^^^^^
 | 
			
		||||
 | 
			
		||||
``make/deploy``
 | 
			
		||||
  Nasadí testweb. Volitelně bere jako parametr jméno větve, kterou má nasadit.
 | 
			
		||||
  Rovnou nastaví přihlašování a vygeneruje příslušnou verzi dokumentace `sem <https://mam-test.ks.matfyz.cz/docs>`_.
 | 
			
		||||
``make/push_compiled_vue_to_test``
 | 
			
		||||
  **Neotestováno** Nahraje Vue z lokálního počítače na testweb. (Gimli často má moc starou verzi Node.js, takže nejde zkompilovat tam)
 | 
			
		||||
``make/sync_test_db_aggressive``
 | 
			
		||||
  Zkopíruje databázi z produkčního webu.
 | 
			
		||||
``make/sync_test_media``
 | 
			
		||||
  Zkopíruje média (obrázky, nahrané soubory) z produkčního webu.
 | 
			
		||||
``make/sync_test``
 | 
			
		||||
  Zkratka za ``make/sync_test_db_aggressive`` + ``make/sync_test_media``.
 | 
			
		||||
 | 
			
		||||
Nasazení produkce
 | 
			
		||||
^^^^
 | 
			
		||||
 | 
			
		||||
``make/deploy_prod``. Před samotným nasazením zálohuje databázi a zkontroluje, že se nasazuje větev ``master``.
 | 
			
		||||
| 
						 | 
				
			
			@ -1,41 +0,0 @@
 | 
			
		|||
Sphinx na našem webu
 | 
			
		||||
====================
 | 
			
		||||
 | 
			
		||||
Dokumentace se zkompiluje příkazem ``make html`` ve složce ``docs``. (Musíte mít zapnutý virtualenv)
 | 
			
		||||
 | 
			
		||||
Složka ``modules`` je automaticiky generována a přegenerovávána. (**Nic v ní neupravovat!**)
 | 
			
		||||
Jinak všechny rst, co jsou ve složce ``docs`` a jejích podsložkách nezačínajících podtržítkem, budou v dokumentaci a to je přesně to, co editovat pro změnu dokumentace (kromě dokumentace přímo v Pythonu).
 | 
			
		||||
 | 
			
		||||
Sphinx se píše v rst: `Návod na syntaxi rst`_ `Cheat sheet`_
 | 
			
		||||
 | 
			
		||||
Pokud něco chcete protlačit do bočního meníčka, je potřeba to připsat do souboru ``docs/index.rst`` (Zatím není úplně konsensus nad tím, co tam má a nemá být, takže pokud si nejste jistí, cpěte tam *všechno* ☺)
 | 
			
		||||
 | 
			
		||||
To je snad vše, co je potřeba vědět k dokumentaci mamwebu. Následující sekce jsou o tom, co jsem provedl Sphinxu, aby to fungovalo:
 | 
			
		||||
 | 
			
		||||
.. _Návod na syntaxi rst: https://sphinx-tutorial.readthedocs.io/step-1/#sections
 | 
			
		||||
.. _Cheat sheet: https://sphinx-tutorial.readthedocs.io/cheatsheet/
 | 
			
		||||
 | 
			
		||||
make html
 | 
			
		||||
---------
 | 
			
		||||
``make html`` dělá následující: Vygenerují se rst soubory do modules z pythoní dokumentace pomocí::
 | 
			
		||||
 | 
			
		||||
    sphinx-apidoc --module-first -o modules .. ../*/migrations --templatedir _templates -f
 | 
			
		||||
 | 
			
		||||
- ``--module-first`` říká, že dokumentace modulu má být dřív než to, co obsahuje,
 | 
			
		||||
- ``-o`` je výstupní složka příkazu,
 | 
			
		||||
- ``..`` prochází složku mamweb,
 | 
			
		||||
- ``../*/migrations`` ignoruje migrace
 | 
			
		||||
- ``--templatedir _templates`` určuje templaty, podle kterých se vyrábí rst z Pythoní dokumentace a struktury složek a souborů,
 | 
			
		||||
- ``-f`` donutí phinx znovu přegenerovat soubory, protože nepozná, že se nějaká dokumentace změnila)
 | 
			
		||||
 | 
			
		||||
Poté se spustí „samotný sphinx“ a vygenerují se soubory v ``_build/html``.
 | 
			
		||||
 | 
			
		||||
Templates
 | 
			
		||||
---------
 | 
			
		||||
Templaty jsou originální s pár změnami:
 | 
			
		||||
 | 
			
		||||
    - Změnil jsem nadpisy
 | 
			
		||||
    - Odstranil jsem některá slova v nadpisech (module, package, …)
 | 
			
		||||
    - Odstranil jsem nadpis Subpackages
 | 
			
		||||
 | 
			
		||||
přišlo mi to takhle lepší. Ale stále nejsem moc spokojen, protože je to pořád nepřehledné.
 | 
			
		||||
| 
						 | 
				
			
			@ -1,32 +0,0 @@
 | 
			
		|||
Co kde najít (mamweb + django)
 | 
			
		||||
==============================
 | 
			
		||||
 | 
			
		||||
Nejdůležitější aplikace z pohledu djanga je ``mamweb``. Tu totiž django pouští
 | 
			
		||||
a obsahuje tedy nastavení (tam se přidávají ostatní aplikace, včetně těch
 | 
			
		||||
importovaných z djanga, a nastavují se tam různé věci jak v djangu, tak i naše,
 | 
			
		||||
například složky, kam se budou věci přidané uživateli ukládat). Dále obsahuje
 | 
			
		||||
základní urls, udávající, „na jaké adrese co je“. A nakonec obsahuje obecné
 | 
			
		||||
věci jako chybové hlášky a vzhled M&M stránek (menu, patička, atd.). Aktuálně
 | 
			
		||||
i veškeré csv.
 | 
			
		||||
 | 
			
		||||
Další jsou pak jednotlivé aplikace (pokud něco hledáte, tak zřejmě chcete najít
 | 
			
		||||
tu aplikaci, která tomu odpovídá, respektive se k ní dostat přes url).
 | 
			
		||||
 | 
			
		||||
**TLDR: Nevšímejte si složek data/ seminar/ a souborů přímo v kořenové složce.**
 | 
			
		||||
Kromě věcí potřebných ke gitu, :doc:`ke spuštění <vyvoj>` a fukci djanga,
 | 
			
		||||
dalších drobností, lokální databáze a již zmíněných aplikací jsou tu ``data``,
 | 
			
		||||
kde je takový ten obsah webu, co by se měl dát snadno měnit (tudíž musí být v
 | 
			
		||||
databázi), tj. statické stránky, menu a obrázky v pozadí menu. Ten je třeba
 | 
			
		||||
měnit hlavně na produkci a sekundárně tady (může to dělat i newebař a nechcete
 | 
			
		||||
přepsat jeho práci). Vše, co nejsou aplikace je popsáno :doc:`tady <dalsi_soubory>`.
 | 
			
		||||
 | 
			
		||||
Ještě je tu aplikace ``seminar/``, kde bylo původně skoro všechno, a tak nám
 | 
			
		||||
tam zbývá spoustu historických migrací (čehož se jen tak nezbavíme).
 | 
			
		||||
 | 
			
		||||
Základy djanga
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
mamweb je psaný téměř čistě v djangu. Což znamená, že to „co je vidět na stránkách“
 | 
			
		||||
jsou views.
 | 
			
		||||
							
								
								
									
										184
									
								
								docs/vyvoj.rst
									
									
									
									
									
								
							
							
						
						
									
										184
									
								
								docs/vyvoj.rst
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,184 +0,0 @@
 | 
			
		|||
Lokální vývoj mamwebu
 | 
			
		||||
=====================
 | 
			
		||||
 | 
			
		||||
Asi hlavní část vývoje většiny webu probíhá lokálně. Každý tak může pracovat na
 | 
			
		||||
vlastních úpravách nezávisle na ostatních.
 | 
			
		||||
 | 
			
		||||
Potřebné vybavení
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
Tento soupis cílí na Linuxáky. Jistě je
 | 
			
		||||
spousta dalších možností, které zde nejsou postihnuty – poraď se s webaři,
 | 
			
		||||
pokud si nejsi jistý. (Speciálně lze nějak vyvíjet na Windows, leč lze často
 | 
			
		||||
narazit na odlišné chování od Linuxu.)
 | 
			
		||||
 | 
			
		||||
Motivace cílení na Linux je to, že Gimli je Linuxový stroj, takže je vývojové
 | 
			
		||||
prostředí pak podobné produkci a zmenšuje to množství odlišného chování.
 | 
			
		||||
 | 
			
		||||
.. TODO: Na dokumentaci odlišného chování (Postgres vs. SQLite, Win vs. Linux, …)
 | 
			
		||||
   by to asi chtělo výhledově separátní stránku, ale teď píšu tuhle :-)
 | 
			
		||||
 | 
			
		||||
Nutné
 | 
			
		||||
^^^^
 | 
			
		||||
 | 
			
		||||
- `Git <https://git-scm.com>`_
 | 
			
		||||
- `Python <https://python.org>`_
 | 
			
		||||
 | 
			
		||||
  - Ideálně ve verzi 3.9 (to je to, co je aktuálně (2022) na Gimlim)
 | 
			
		||||
  - Včetně pip-u (na Ubuntu balíček ``python3-pip``), venvu (``python3-venv``) a knihoven pro kompilaci
 | 
			
		||||
    Cčkových rozšíření (``python3-dev``)
 | 
			
		||||
- Knihovna pro práci s PostgreSQL (``libpq-dev``, protože jsou potřeba všechny db backendy)
 | 
			
		||||
- Webový prohlížeč
 | 
			
		||||
- \*NIXový shell (typicky ``bash``)
 | 
			
		||||
 | 
			
		||||
.. TODO: Pokud tu něco chybí, tak to dopiš :-)
 | 
			
		||||
 | 
			
		||||
Kromě toho je potřeba mít účet na `Gitee <https://gitea.ks.matfyz.cz>`_, kde
 | 
			
		||||
bydlí gitový repozitář s kódem.
 | 
			
		||||
 | 
			
		||||
.. tip:: Potřebné balíčky v různých distribucích jsou sepsané v :ref:`tabulce
 | 
			
		||||
   prerekvizit <Alternativní jména balíčků>`.
 | 
			
		||||
 | 
			
		||||
Doporučené
 | 
			
		||||
^^^^^^^^^^
 | 
			
		||||
 | 
			
		||||
- Python wheel (možná řeší problémy s potřebou ``-dev`` balíčků…)
 | 
			
		||||
- Editor / IDE podporující `Editorconfig <https://editorconfig.org/>`_
 | 
			
		||||
- Uživatelská zkušenost s `produkční verzí webu <https://mam.matfyz.cz>`_
 | 
			
		||||
- Účet v `Kanci <https://kanboard.ledoian.cz>`_
 | 
			
		||||
 | 
			
		||||
.. TODO: A nejspíš další věci, na které jsem si teď nevzpomněl.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Zprovoznění
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
Nejprve je potřeba stáhnout si repozitář. To se provede příkazem ``git clone
 | 
			
		||||
https://gitea.ks.matfyz.cz/mam/mamweb.git``, případně ``git clone
 | 
			
		||||
git@gitea.ks.matfyz.cz:mam/mamweb.git``, pokud už máš nahraný SSH klíč na
 | 
			
		||||
Giteu. (Obě adresy se dají zkopírovat ze `stránky repozitáře
 | 
			
		||||
<https://gitea.ks.matfyz.cz/mam/mamweb>`_.) To vyrobí složku ``mamweb``, přepni
 | 
			
		||||
se do ní (``cd mamweb``)
 | 
			
		||||
 | 
			
		||||
O zprovoznění webu se stará skript ``make/install_web``, stačí ho spustit. Ten
 | 
			
		||||
vytvoří virtualenv (neexistuje-li) a nainstaluje do něj závislosti webu (podle
 | 
			
		||||
souboru ``requirements.txt``).
 | 
			
		||||
 | 
			
		||||
.. FIXME: Novowebaři zmínka o requirements.txt tady moc nepomůže, to má být na
 | 
			
		||||
   stránce o celkové stavbě repozitáře a stacku…
 | 
			
		||||
 | 
			
		||||
Následně je potřeba nahrát další data do databáze, což uděláš pomocí příkazů
 | 
			
		||||
``./manage.py testdata`` a ``./manage.py loaddata data/*``. Skript
 | 
			
		||||
``make/install_web`` to kdyžtak na konci připomene.
 | 
			
		||||
 | 
			
		||||
.. caution:: Zatímco skripty v ``make/`` to nepotřebují, pro použití skriptu
 | 
			
		||||
  ``./manage.py`` (a dalších) se potřebuješ přepnout do virtuálního prostředí.
 | 
			
		||||
  To uděláš velmi pravděpodobně spuštěním ``source env/bin/activate``, před
 | 
			
		||||
  začátkem *promptu* by se mělo objevit ``(env)``. Pro opuštění spusť
 | 
			
		||||
  ``deactivate``.
 | 
			
		||||
 | 
			
		||||
Samotný web se spustí třeba pomocí ``make/run``, nebo ekvivalentně
 | 
			
		||||
``./manage.py runserver`` a pak je vidět na `<http://127.0.0.1:8000>`_.
 | 
			
		||||
 | 
			
		||||
Časté problémy
 | 
			
		||||
^^^^^^
 | 
			
		||||
 | 
			
		||||
- ``make/install_web`` vypíše ``Error: pg_config executable not found.``:
 | 
			
		||||
  Chybí ``libpq-dev``
 | 
			
		||||
- Chybová hláška obsahuje ``#include <Python.h>``: chybí ``python3-dev``
 | 
			
		||||
- Na webu není vidět meníčko: spusť ``./manage.py loaddata data/*``
 | 
			
		||||
- ``locale.Error: unsupported locale setting``: Chybí podpora pro příslušný
 | 
			
		||||
  jazyk ve tvém systému. Odkomentuj příslušnou lokalizaci v ``/etc/locale.gen``
 | 
			
		||||
  a spusť ``locale-gen`` jako root, tím se to spraví.
 | 
			
		||||
 | 
			
		||||
S dalšími problémy se zkus obrátit na další webaře, třeba někdo bude vědět :-)
 | 
			
		||||
 | 
			
		||||
Příkazy pro ovládání webu
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
Příkazy se dělí do několika skupin. Některé souvisí přímo s webem, Djangem,
 | 
			
		||||
databází a podobně, ty typicky používají ``./manage.py``. Skripty pro
 | 
			
		||||
obhospodařování repozitáře a webu „zvenku“ typicky bydlí ve složce ``make/``.
 | 
			
		||||
Ostatní skripty jsou na náhodných místech :-)
 | 
			
		||||
 | 
			
		||||
Tady jsou rozebrány jen příkazy relevantní pro lokální web a univerzálně
 | 
			
		||||
užitečné, ostatní najdeš v :ref:`Skripty pro práci s repozitářem`.
 | 
			
		||||
 | 
			
		||||
Make skripty
 | 
			
		||||
^^^^^^^
 | 
			
		||||
 | 
			
		||||
- ``make/install_web`` nainstaluje závislosti webu
 | 
			
		||||
- ``make/run`` spustí web (ekvivalentní s ``./manage.py runserver``)
 | 
			
		||||
- ``make/schema`` nakreslí schéma vazeb modelů (může se hodit pro referenci a představu)
 | 
			
		||||
- ``make/test`` spustí testy (ale moc jich zatím není; ekvivalentní s ``./manage.py test``)
 | 
			
		||||
- ``make/sync_prod_flatpages`` stáhne statické stránky z produkčního webu a
 | 
			
		||||
  uloží je do souboru v gitu, což umožňuje jejich verzování
 | 
			
		||||
 | 
			
		||||
Manage.py skripty
 | 
			
		||||
^^^^^
 | 
			
		||||
 | 
			
		||||
.. note:: Je potřeba je spouštět ve virtuálním prostředí, viz výše.
 | 
			
		||||
 | 
			
		||||
Všechny skripty kdyžtak mají ``--help``, dá se tak zjistit, co všechno umějí.
 | 
			
		||||
 | 
			
		||||
- ``./manage.py testdata`` vygeneruje spíše chudá testovací data, aby bylo na
 | 
			
		||||
  čem testovat web.
 | 
			
		||||
- ``./manage.py loaddata <soubor/y>`` nahraje data ze souborů do databáze
 | 
			
		||||
- ``./manage.py dumpdata <model>`` naopak z databáze vyrobí textovou reprezentaci
 | 
			
		||||
- ``./manage.py shell`` spustí interaktivní pythoní shell, ze kterého lze
 | 
			
		||||
  interagovat s webem / Djangem.
 | 
			
		||||
- ``./manage.py dbshell`` spustí databázový shell (typicky používá SQL)
 | 
			
		||||
 | 
			
		||||
- ``./manage.py makemigrations`` vyrobí popis migrací, ``./manage.py migrate``
 | 
			
		||||
  je spustí, ``showmigrations`` ukáže, které migrace jsou aplikované a které
 | 
			
		||||
  ne.
 | 
			
		||||
- ``./manage.py runserver_plus`` spouští o něco lepší vývojový server (ale
 | 
			
		||||
  nikdy jsem asi ty lepší featury nepoužil)
 | 
			
		||||
 | 
			
		||||
Může se hodit vědět, že spuštění ``./manage.py`` bez parametrů vypíše seznam
 | 
			
		||||
všech příkazů, které lze spustit.
 | 
			
		||||
 | 
			
		||||
Dokumentace djangových příkazů je v `dokumentaci Djanga
 | 
			
		||||
<https://docs.djangoproject.com/en/3.2/ref/django-admin/#available-commands>`_
 | 
			
		||||
 | 
			
		||||
Ostatní užitečné příkazy
 | 
			
		||||
^^^^^
 | 
			
		||||
 | 
			
		||||
- ``git status`` je univerzální nápověda na aktuální stav repozitáře a co s tím
 | 
			
		||||
  lze dělat.
 | 
			
		||||
- ``git clean -fxd`` smaže všechny soubory, které nejsou uložené v gitu (včetně
 | 
			
		||||
  ignorovaných). **Nebezpečný příkaz**, zamysli se, než ho spustíš
 | 
			
		||||
 | 
			
		||||
Specifika lokálního webu
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
Lokální uživatelé
 | 
			
		||||
^^^^^^^
 | 
			
		||||
 | 
			
		||||
Přihlašovací údaje jsou psány jako ``login:heslo``
 | 
			
		||||
 | 
			
		||||
- Superuživatel: ``admin:admin``
 | 
			
		||||
- Orgovské účty: ``o:o``, ``o1:o`` až ``o3:o``
 | 
			
		||||
- Řešitelské účty: ``r:r``, ``r1:r`` až ``r3:r``
 | 
			
		||||
 | 
			
		||||
Všechny tyto účty jsou (?) svázané s nějakými fiktivními osobami, není ale zřejmé se
 | 
			
		||||
kterými, budeš to muset vyzkoušet a pak tady zdokumentovat :-)
 | 
			
		||||
 | 
			
		||||
E-maily
 | 
			
		||||
^^^^^
 | 
			
		||||
 | 
			
		||||
Posílání e-mailů se lokálně dá zkoušet, e-mail se vypíše do terminálu, kde je
 | 
			
		||||
web spuštěn (e.g. pomocí ``make/run``).
 | 
			
		||||
 | 
			
		||||
Pruhy
 | 
			
		||||
^^^^
 | 
			
		||||
 | 
			
		||||
To, že má lokální web po stranách zelené pruhy je normální a správně, slouží to
 | 
			
		||||
k vizuálnímu odlišení lokálního webu.
 | 
			
		||||
 | 
			
		||||
.. TODO: Mít někde popis všech tří instancí a tady na něj pak odkázat.
 | 
			
		||||
.. - Tahák k používání gitových větví: do workflow, ne sem…
 | 
			
		||||
.. - Užitečné odkazy – kam se kouknout
 | 
			
		||||
  (dohledávání views podle URL, settings_*, )
 | 
			
		||||
.. - Zpříjemnění práce (ssh-klíče, tea, --help, …)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -116,7 +116,7 @@ Aktuálně: Jakýsi coding style zhruba existuje, není popsaný, šíří se li
 | 
			
		|||
- Nesmí být striktně vynucovaný
 | 
			
		||||
- Musel by být hodně nastavitelný
 | 
			
		||||
    - Nechceme mít kód plný `#NOQA: WTF42`
 | 
			
		||||
- Nejspíš vždycky bude mít false positives (`tvorba.utils.roman_numerals`) i false negatives (`tvorba.models.Cislo.posli_cislo_mailem`)
 | 
			
		||||
- Nejspíš vždycky bude mít false positives (`seminar.utils.roman_numerals`) i false negatives (`seminar.models.tvorba.Cislo.posli_cislo_mailem`)
 | 
			
		||||
    - Možná dobrý sluha, ale určitě špatný pán (also: špatná zkušenost ☺)
 | 
			
		||||
- __Důsledek:__ Hrozí, že těch falešných varování bude moc, čímž to ztratí smysl úplně
 | 
			
		||||
    - Potenciálně by šlo aplikovat jen lokálně na změny?
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +0,0 @@
 | 
			
		|||
Zápisy
 | 
			
		||||
======
 | 
			
		||||
 | 
			
		||||
.. toctree::
 | 
			
		||||
   :caption: Importy zápisů z Markdownu
 | 
			
		||||
   :maxdepth: 1
 | 
			
		||||
 | 
			
		||||
   2021-12-06-testovani_dokumentace_codereview
 | 
			
		||||
| 
						 | 
				
			
			@ -1,97 +0,0 @@
 | 
			
		|||
Závislosti webu
 | 
			
		||||
@@@@@@@@@@@@@@@
 | 
			
		||||
 | 
			
		||||
Web ke svému běhu potřebuje různé další programy. Tahle stránka se snaží je pokrýt.
 | 
			
		||||
 | 
			
		||||
Stránka je koncipována jako odrážkový seznam balíčků pro Ubuntu s případnými
 | 
			
		||||
komentáři, na konci stránky jsou uvedena :ref:`jména balíčků <Alternativní jména
 | 
			
		||||
balíčků>` v různých dalších distribucích. (Seznam mj. cílí na lokální
 | 
			
		||||
rozchození, proto popisuji Ubuntu a ne Debian. I tak se ale snažíme popsat web
 | 
			
		||||
v úplnosti.)
 | 
			
		||||
 | 
			
		||||
.. I use Arch, btw.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Základ webu
 | 
			
		||||
===========
 | 
			
		||||
 | 
			
		||||
- ``python3`` – Ideálně Python 3.9, jenž je na Gimlim
 | 
			
		||||
- ``python3-pip`` pro instalaci dalších Pythoních balíčků podle ``requirements.txt``
 | 
			
		||||
- ``python3-venv``
 | 
			
		||||
- ``gcc`` – kompilace Pythoních knihoven ze zdrojových distribucí (sdist), možná (neotestováno) jde jako alternativu použít ``python3-wheel`` a stahovat bdists
 | 
			
		||||
- ``python3-dev`` – taktéž
 | 
			
		||||
- ``libpq-dev`` do třetice…
 | 
			
		||||
- ``ghostscript`` TODO konverze PDF v korekturovátku
 | 
			
		||||
- ``pdflatex`` FIXME! generování obálek a stvrzenek
 | 
			
		||||
- ``git`` – používán :ref:`Make skripty`
 | 
			
		||||
- ``locales`` pro české formáty
 | 
			
		||||
 | 
			
		||||
Nasazení na produkci / testweb
 | 
			
		||||
==============================
 | 
			
		||||
 | 
			
		||||
(nejsou nutně potřeba k provozu lokální instance)
 | 
			
		||||
 | 
			
		||||
- ``rsync``
 | 
			
		||||
- ``pg_utils`` FIXME
 | 
			
		||||
- ``htpasswd`` FIXME – aby testweb nepoužívali náhodní kolemjdoucí
 | 
			
		||||
- ``postgresql-server`` TODO
 | 
			
		||||
- ``acl`` pro nastavování práv přes ``setfacl``
 | 
			
		||||
 | 
			
		||||
Pro testweb je potřeba i všechno pro :ref:`dokumentaci <Dokumentace>`, vizte níž.
 | 
			
		||||
 | 
			
		||||
Předpokládá se nasazení v uWSGI pod Nginxem a služba běžící pod systemd, nicméně to už je spíš záležitost infrastruktury a ne specifikum mamwebu.
 | 
			
		||||
 | 
			
		||||
Dokumentace
 | 
			
		||||
===========
 | 
			
		||||
 | 
			
		||||
- ``make`` pro zbuildění
 | 
			
		||||
- Pythoní balíčky podle příslušné části ``requirements.txt``
 | 
			
		||||
 | 
			
		||||
Vývojové nástroje
 | 
			
		||||
=================
 | 
			
		||||
 | 
			
		||||
(Nejsou nezbytně nutné, ale předpokládáme jejich užitečnost. Mohou se hodit i na produkci.)
 | 
			
		||||
 | 
			
		||||
- ``psql`` TODO pro manuální dotazy do PostgreSQL
 | 
			
		||||
- ``sqlite3`` TODO totéž pro SQLite3
 | 
			
		||||
- ``ssh``
 | 
			
		||||
- ``graphviz`` pro vygenerování schématu
 | 
			
		||||
- ``rsync``
 | 
			
		||||
- ``ipython3`` – hezčí interaktivní shell (stačí z ``requirements.txt``)
 | 
			
		||||
 | 
			
		||||
Potenciální usnadnění života
 | 
			
		||||
============================
 | 
			
		||||
 | 
			
		||||
(Úplně zbytečné, ale sdílíme pozitivní zkušenosti :-))
 | 
			
		||||
 | 
			
		||||
- ``tea`` – CLI klient pro Giteu, aby člověk nepotřeboval otevírat web pro založení PR
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Alternativní jména balíčků
 | 
			
		||||
==========================
 | 
			
		||||
 | 
			
		||||
Různé distribuce balí SW různě, takže to, co je v jedné distribuci jeden
 | 
			
		||||
balíček může být v jiné rozděleno do víc. Pro usnadnění nasazení je tady
 | 
			
		||||
přehled známých alternativních jmen.
 | 
			
		||||
 | 
			
		||||
TODO: tabulka není úplná. Pokud na něco narazíte, tak ji prosím doplňte.
 | 
			
		||||
 | 
			
		||||
.. admonition:: Jak se pozná, že web funguje, pro účely tabulky?
 | 
			
		||||
 | 
			
		||||
   Na čistém repozitáři (``git clean -fxd``) a čistém systému spouštíme
 | 
			
		||||
   ``make/init_local``. Když to spadne, tak do tabulky zapíšeme, co jsme
 | 
			
		||||
   přiinstalovali. Protože nefunguje synchronizace flatpages (nemáme SSH klíč),
 | 
			
		||||
   ``make/init_local`` sestřelíme při pokusu o synchronizaci a vyzkoušíme, že
 | 
			
		||||
   ``make/test`` spustí testy.
 | 
			
		||||
 | 
			
		||||
.. Grafické tabulky (grid-tables, simple-tables) jsou strašný porod vyrábět, dlabu na to a cpu to do CSV…
 | 
			
		||||
 | 
			
		||||
.. csv-table:: Prerekvizity v jednotlivých distribucích
 | 
			
		||||
   :header: Distribuce / OS, Repozitář s Py3.9, venv, py knihovny, PostgreSQL knihovna, poznámky
 | 
			
		||||
 | 
			
		||||
   Ubuntu 22.10, ??, ``python3-venv``, ``python3-dev``, ``libpq-dev``, "Je potřeba zapnout zdroj ``universe`` a nainstalovat kompilátor C (``gcc``)?"
 | 
			
		||||
   Linux Mint 21, ??, ``python3-venv``, ``python3-dev``, ``libpq-dev``, ""
 | 
			
		||||
   Archlinux 2022.11.01, AUR, vestavěný, vestavěné, ``postgresql-libs``, "Je potřeba céčkový kompilátor (``gcc``); nezapomenout vygenerovat locale ``cs_CZ.UTF-8``"
 | 
			
		||||
   openSUSE Leap 15.4, oficiální (``python39``), předinstalovaný?, ``python39-devel``, ??FIXME!!, "Výchozí verze pythonu je 3.6 a ta je moc stará, potřeba instalovat ``gcc``. Nevím jak sehnat pg_config."
 | 
			
		||||
   Debian 11, "oficiální, výchozí", ??, ??, ??, "Určitě to tam rozběhat jde, protože Gimli. Nejspíš bude relativně podobné Ubuntu."
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,86 +0,0 @@
 | 
			
		|||
Zkratky aplikací ve zdrojácích
 | 
			
		||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 | 
			
		||||
 | 
			
		||||
Ve zdrojácích (zejména různé ``models.py``, ``views.py`` ap.) používáme spoustu
 | 
			
		||||
modelů. Někdy je praktičtější / někdo preferuje importovat celou aplikaci jako
 | 
			
		||||
jedno jméno a používat modely bez explicitních importů, tj::
 | 
			
		||||
 | 
			
		||||
    # „hromadné“ importy:
 | 
			
		||||
    import personalni.models as p
 | 
			
		||||
    ...
 | 
			
		||||
    p.Organizator.objects.all()
 | 
			
		||||
 | 
			
		||||
    # „explicitní“ importy:
 | 
			
		||||
    from personalni.models import Organizator
 | 
			
		||||
    ...
 | 
			
		||||
    Organizator.objects.all()
 | 
			
		||||
 | 
			
		||||
Na webschůzce 2024-11-05 jsme na toto téma otevřeli diskusi, tady je její závěr.
 | 
			
		||||
 | 
			
		||||
.. admonition:: Historické okénko
 | 
			
		||||
   :class: note
 | 
			
		||||
 | 
			
		||||
   Kdysi jsme měli (prakticky) všechny modely v jedné aplikaci, ``seminar``. Na
 | 
			
		||||
   různých místech se pak ``seminar.models`` importovalo typicky jako ``s``
 | 
			
		||||
   nebo jako ``m``.
 | 
			
		||||
 | 
			
		||||
   Přirozeně, toto už nejde tak snadno, protože už neexistuje jedno místo, ze
 | 
			
		||||
   kterého chceme tahat modely v kódu.
 | 
			
		||||
 | 
			
		||||
Konvence
 | 
			
		||||
========
 | 
			
		||||
 | 
			
		||||
Shodli jsme se, že nám rozhodně nevadí explicitní importy a z pohledu
 | 
			
		||||
čitelnosti je preferujeme. Nicméně při psaní kódu to některým webařům přijde
 | 
			
		||||
nepohodlné, takže očekáváme, že bude existovat spousta kódu, která bude chtít
 | 
			
		||||
importovat hromadně. Usnesli jsme se proto na následujících kanonických
 | 
			
		||||
zkratkách, aby se aplikace alespoň zkracovaly konzistentně.
 | 
			
		||||
 | 
			
		||||
V závorkách je uvedené případné jméno, ale nepředpokládáme, že někdo bude danou
 | 
			
		||||
aplikaci chtít importovat hromadně. Některé aplikace zkratku nemají, ty se
 | 
			
		||||
importují vždy pod plným jménem nebo explicitně.
 | 
			
		||||
 | 
			
		||||
.. list-table::
 | 
			
		||||
   :header-rows: 1
 | 
			
		||||
 | 
			
		||||
   * - Model
 | 
			
		||||
     - Zkratka
 | 
			
		||||
   * - ``aesop``
 | 
			
		||||
     - ---
 | 
			
		||||
   * - ``api``
 | 
			
		||||
     - --- (``api``)
 | 
			
		||||
   * - ``galerie``
 | 
			
		||||
     - ``g``
 | 
			
		||||
   * - ``header_fotky``
 | 
			
		||||
     - --- (``hdr``)
 | 
			
		||||
   * - ``korektury``
 | 
			
		||||
     - ``kor``
 | 
			
		||||
   * - ``novinky``
 | 
			
		||||
     - ``nov``
 | 
			
		||||
   * - ``odevzdavatko``
 | 
			
		||||
     - ``odev``
 | 
			
		||||
   * - ``personální``
 | 
			
		||||
     - ``pers``/``p``
 | 
			
		||||
   * - ``sifrovacka``
 | 
			
		||||
     - (``sifr``)
 | 
			
		||||
   * - ``soustredeni``
 | 
			
		||||
     - ``sou``
 | 
			
		||||
   * - ``treenode``
 | 
			
		||||
     - ``tn``
 | 
			
		||||
   * - ``tvorba``
 | 
			
		||||
     - ``tv``
 | 
			
		||||
   * - ``various``
 | 
			
		||||
     - ``v``/``var``
 | 
			
		||||
   * - ``vyroci``
 | 
			
		||||
     - ---
 | 
			
		||||
   * - ``vysledkovky``
 | 
			
		||||
     - ``vysl``
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.. admonition:: O všech modelech pod jedním jménem
 | 
			
		||||
   :class: warning
 | 
			
		||||
 | 
			
		||||
   Historické okénko výš zatajuje jeden detail: Při práci v shellu se hodí mít
 | 
			
		||||
   modely k dispozici a nemuset přemýšlet nad dělením do aplikací, takže ve
 | 
			
		||||
   skutečnosti existuje ``mamweb.vsechno``, jenž všechny modely obsahuje.
 | 
			
		||||
   Z čitelnostních důvodů je ale *zakázáno* tento modul používat v kódu.
 | 
			
		||||
							
								
								
									
										25
									
								
								galerie/TODO
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								galerie/TODO
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
========
 | 
			
		||||
| TODO |
 | 
			
		||||
|======|
 | 
			
		||||
 | 
			
		||||
Aktualni
 | 
			
		||||
* co s titulni fotkou
 | 
			
		||||
* do CSS
 | 
			
		||||
  * nahledy
 | 
			
		||||
    * nastylovat tabulku s nahledy
 | 
			
		||||
    * komentare uz na nahledy?
 | 
			
		||||
  * detail
 | 
			
		||||
    * nahledy pred a po
 | 
			
		||||
    * opravit prechodove sipky
 | 
			
		||||
    * vyrobit prechodove sipky ve M&M-stylu
 | 
			
		||||
 | 
			
		||||
Dlouhodobe
 | 
			
		||||
* sipky na prechazeni mezi fotkami
 | 
			
		||||
* hromadne PRIDANI fotek do jiz existujici galerie
 | 
			
		||||
 | 
			
		||||
Fylozoficke
 | 
			
		||||
* zvolit velikosti velke a male fotky
 | 
			
		||||
* je potreba i jine razeni nez automaticky podle casu nebo staci podgalerie?
 | 
			
		||||
  * napr. dve hry na dvou ruznych mistech ve stejny cas
 | 
			
		||||
  * fotky od ucastniku ze hry (skupinky se pohybuji ve stejny cas, ale maji sled fotek) -- nestaci to pripadne vrazit do podgalerii?
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
from galerie.models import Obrazek, Galerie, VZDY, ORG, NIKDY, UCASTNIK
 | 
			
		||||
#coding: utf-8
 | 
			
		||||
 | 
			
		||||
from galerie.models import Obrazek, Galerie
 | 
			
		||||
from django.contrib import admin
 | 
			
		||||
from django.http import HttpResponseRedirect
 | 
			
		||||
from django import forms
 | 
			
		||||
| 
						 | 
				
			
			@ -8,9 +10,8 @@ from django.db import models
 | 
			
		|||
 | 
			
		||||
def zverejnit_fotogalerii(modeladmin, request, queryset):
 | 
			
		||||
	'''zverejni vybranou fotogalerii i jeji vsechny podgalerie'''
 | 
			
		||||
	queryset = queryset.filter(zobrazit=ORG)
 | 
			
		||||
	for galerie in queryset:
 | 
			
		||||
		galerie.zobrazit = VZDY
 | 
			
		||||
		galerie.zobrazit = 0
 | 
			
		||||
		galerie.save()
 | 
			
		||||
		zverejnit_fotogalerii(modeladmin, request,
 | 
			
		||||
				Galerie.objects.filter(galerie_up = galerie))
 | 
			
		||||
| 
						 | 
				
			
			@ -19,9 +20,8 @@ def zverejnit_fotogalerii(modeladmin, request, queryset):
 | 
			
		|||
 | 
			
		||||
def prepnout_fotogalerii_do_org_rezimu(modeladmin, request, queryset):
 | 
			
		||||
	'''zneverjni vybranou fotogalerii i jeji vsechny podgalerie'''
 | 
			
		||||
	queryset = queryset.filter(zobrazit=VZDY)
 | 
			
		||||
	for galerie in queryset:
 | 
			
		||||
		galerie.zobrazit = ORG
 | 
			
		||||
		galerie.zobrazit = 1
 | 
			
		||||
		galerie.save()
 | 
			
		||||
		prepnout_fotogalerii_do_org_rezimu(modeladmin, request,
 | 
			
		||||
				Galerie.objects.filter(galerie_up = galerie))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										47
									
								
								galerie/autocomplete_light_registry.py.old
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								galerie/autocomplete_light_registry.py.old
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,47 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
from autocomplete_light import shortcuts as autocomplete_light
 | 
			
		||||
 | 
			
		||||
from .models import Obrazek, Galerie
 | 
			
		||||
from .views import cesta_od_korene
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ObrazekAutocomplete(autocomplete_light.AutocompleteModelBase):
 | 
			
		||||
 | 
			
		||||
    model = Obrazek
 | 
			
		||||
    search_fields = ['nazev', 'popis']
 | 
			
		||||
    split_words = True
 | 
			
		||||
    limit_choices = 15
 | 
			
		||||
    attrs = {
 | 
			
		||||
        # This will set the input placeholder attribute:
 | 
			
		||||
        'placeholder': u'Obrázek',
 | 
			
		||||
        # This will set the yourlabs.Autocomplete.minimumCharacters
 | 
			
		||||
        # options, the naming conversion is handled by jQuery
 | 
			
		||||
        'data-autocomplete-minimum-characters': 1,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    choice_html_format = '''
 | 
			
		||||
        <span class="block" data-value="{}">
 | 
			
		||||
            <span class="block">
 | 
			
		||||
                {}
 | 
			
		||||
                <span class="block">{}</span>
 | 
			
		||||
            </span>
 | 
			
		||||
        </span>
 | 
			
		||||
    '''
 | 
			
		||||
 | 
			
		||||
    def choice_label(self, obrazek):
 | 
			
		||||
        cesta = "/".join(g.nazev for g in cesta_od_korene(obrazek.galerie))
 | 
			
		||||
        popis = "{}<br>".format(obrazek.popis) if obrazek.popis else ""
 | 
			
		||||
        return '{}<br>{}{}'.format(obrazek.nazev, popis, cesta)
 | 
			
		||||
 | 
			
		||||
    def choice_html(self, obrazek):
 | 
			
		||||
        """Vrátí kus html i s obrázkem, které se pak ukazuje v nabídce"""
 | 
			
		||||
        return self.choice_html_format.format(self.choice_value(obrazek),
 | 
			
		||||
            obrazek.obrazek_maly_tag(), self.choice_label(obrazek))
 | 
			
		||||
 | 
			
		||||
    widget_attrs={
 | 
			
		||||
        'data-widget-maximum-values': 15,
 | 
			
		||||
        'class': 'modern-style',
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
autocomplete_light.register(ObrazekAutocomplete)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,7 @@
 | 
			
		|||
#coding: utf-8
 | 
			
		||||
 | 
			
		||||
from django import forms
 | 
			
		||||
from seminar.models import Soustredeni
 | 
			
		||||
 | 
			
		||||
class KomentarForm(forms.Form):
 | 
			
		||||
	komentar = forms.CharField(label = "Komentář:", max_length = 300, required=False)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
# Generated by Django 1.11.20 on 2019-04-30 21:40
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
# Generated by Django 1.11.21 on 2019-06-10 21:58
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +0,0 @@
 | 
			
		|||
# Generated by Django 4.2.11 on 2024-04-30 21:53
 | 
			
		||||
 | 
			
		||||
from django.db import migrations
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('galerie', '0010_auto_20200819_0947'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
    ]
 | 
			
		||||
| 
						 | 
				
			
			@ -1,20 +0,0 @@
 | 
			
		|||
# Generated by Django 4.2.11 on 2024-05-01 13:07
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
import django.db.models.deletion
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('soustredeni', '0001_split_from_seminar'),
 | 
			
		||||
        ('galerie', '0011_pre_split_soustredeni'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='galerie',
 | 
			
		||||
            name='soustredeni',
 | 
			
		||||
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='soustredeni.soustredeni'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
| 
						 | 
				
			
			@ -1,14 +0,0 @@
 | 
			
		|||
# Generated by Django 4.2.11 on 2024-05-01 13:35
 | 
			
		||||
 | 
			
		||||
from django.db import migrations
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('galerie', '0012_soustredeni_relink'),
 | 
			
		||||
        ('soustredeni', '0003_post_split_soustredeni'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
    ]
 | 
			
		||||
| 
						 | 
				
			
			@ -1,18 +0,0 @@
 | 
			
		|||
# Generated by Django 4.2.20 on 2025-04-23 18:37
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('galerie', '0013_post_split_soustredeni'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='galerie',
 | 
			
		||||
            name='zobrazit',
 | 
			
		||||
            field=models.IntegerField(choices=[(0, 'Vždy'), (1, 'Organizátorům'), (3, 'Účastníkům a orgům'), (2, 'Nikdy')], default=1, verbose_name='Zobrazit?'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
| 
						 | 
				
			
			@ -1,19 +0,0 @@
 | 
			
		|||
# Generated by Django 4.2.16 on 2025-04-30 18:53
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
import django.db.models.deletion
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('galerie', '0014_alter_galerie_zobrazit'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='galerie',
 | 
			
		||||
            name='galerie_up',
 | 
			
		||||
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='galerie.galerie'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
| 
						 | 
				
			
			@ -1,19 +0,0 @@
 | 
			
		|||
# Generated by Django 4.2.16 on 2025-04-30 19:02
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
import django.db.models.deletion
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('galerie', '0015_alter_galerie_galerie_up'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='obrazek',
 | 
			
		||||
            name='galerie',
 | 
			
		||||
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='galerie.galerie'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
| 
						 | 
				
			
			@ -1,20 +1,21 @@
 | 
			
		|||
# coding: utf-8
 | 
			
		||||
 | 
			
		||||
from django.db import models
 | 
			
		||||
#from django.db.models import Q
 | 
			
		||||
from django.utils.encoding import force_text
 | 
			
		||||
from imagekit.models import ImageSpecField
 | 
			
		||||
from imagekit.processors import ResizeToFit, Transpose
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
from soustredeni.models import Soustredeni
 | 
			
		||||
from seminar.models import Soustredeni
 | 
			
		||||
 | 
			
		||||
VZDY=0
 | 
			
		||||
ORG=1
 | 
			
		||||
NIKDY=2
 | 
			
		||||
UCASTNIK=3
 | 
			
		||||
VIDITELNOST = (
 | 
			
		||||
	(VZDY, 'Vždy'),
 | 
			
		||||
	(ORG, 'Organizátorům'),
 | 
			
		||||
	(UCASTNIK, 'Účastníkům a orgům'),
 | 
			
		||||
	(NIKDY, 'Nikdy'),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -56,7 +57,7 @@ class Obrazek(models.Model):
 | 
			
		|||
	nazev = models.CharField('Název', max_length=50, blank=True, null=True)
 | 
			
		||||
	popis = models.TextField('Popis', blank=True, null=True)
 | 
			
		||||
	datum_vlozeni = models.DateTimeField('Datum vložení', auto_now_add=True)
 | 
			
		||||
	galerie = models.ForeignKey('Galerie', blank=True, null=True, on_delete=models.CASCADE)
 | 
			
		||||
	galerie = models.ForeignKey('Galerie', blank=True, null=True, on_delete=models.SET_NULL)
 | 
			
		||||
	poradi = models.IntegerField('Pořadí', blank=True, null=True)
 | 
			
		||||
 | 
			
		||||
	def __str__(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -90,7 +91,7 @@ class Galerie(models.Model):
 | 
			
		|||
	titulni_obrazek = models.ForeignKey(Obrazek, blank = True, null = True, related_name = "+", on_delete = models.SET_NULL)
 | 
			
		||||
	zobrazit = models.IntegerField('Zobrazit?', default = ORG, choices = VIDITELNOST)
 | 
			
		||||
	galerie_up = models.ForeignKey('Galerie', blank = True, null = True,
 | 
			
		||||
		on_delete=models.PROTECT)
 | 
			
		||||
		on_delete=models.SET_NULL)
 | 
			
		||||
	soustredeni = models.ForeignKey(Soustredeni, blank = True, null = True,
 | 
			
		||||
		on_delete=models.PROTECT)
 | 
			
		||||
	poradi = models.IntegerField('Pořadí', blank = True, null = False, default = 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -100,3 +101,25 @@ class Galerie(models.Model):
 | 
			
		|||
	class Meta:
 | 
			
		||||
		verbose_name = 'Galerie'
 | 
			
		||||
		verbose_name_plural = 'Galerie'
 | 
			
		||||
 | 
			
		||||
	#def link_na_preview(self):
 | 
			
		||||
		#"""Odkaz na galerii, používá se v admin rozhranní. """
 | 
			
		||||
		#return '<a href="/fotogalerie/galerie/%s/">Preview</a>' % self.id
 | 
			
		||||
	#link_na_preview.allow_tags = True
 | 
			
		||||
	#link_na_preview.short_description = 'Zobrazit galerii'
 | 
			
		||||
#
 | 
			
		||||
	#def je_publikovano(self):
 | 
			
		||||
		#"""Vraci True, pokud je tato galerie publikovana. """ 
 | 
			
		||||
		#if self.zobrazit == VZDY:
 | 
			
		||||
			#return True
 | 
			
		||||
		#if self.zobrazit == PODLE_CLANKU:
 | 
			
		||||
			#for clanek in self.clanek_set.all():
 | 
			
		||||
				#if clanek.je_publikovano():
 | 
			
		||||
					#return True
 | 
			
		||||
		#return False
 | 
			
		||||
#
 | 
			
		||||
	#@staticmethod
 | 
			
		||||
	#def publikovane_galerie():
 | 
			
		||||
		#"""Vraci galerie, ktere uz maji byt publikovane."""
 | 
			
		||||
		#clanky = Blog.models.Clanek.publikovane_clanky()
 | 
			
		||||
		#return Galerie.objects.filter(Q(zobrazit=VZDY) | (Q(clanek__in=clanky) & Q(zobrazit=PODLE_CLANKU))).distinct()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,191 +0,0 @@
 | 
			
		|||
@charset "utf-8"; /* vynuť utf-8 */
 | 
			
		||||
 | 
			
		||||
/* Galerie */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* velká fotka */
 | 
			
		||||
/* zmenšování spolu s oknem prohlížeče */
 | 
			
		||||
.galerie .obrazek, .titulni_obrazek {
 | 
			
		||||
	max-width: 100%;
 | 
			
		||||
	height: auto;
 | 
			
		||||
	width: auto\9; /* ie8 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.predchozi_obrazek{
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	z-index: 1;
 | 
			
		||||
	width: 33%;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	left: 0;
 | 
			
		||||
	top: 0;
 | 
			
		||||
}
 | 
			
		||||
.predchozi_obrazek:hover{
 | 
			
		||||
	background-image: url("/static/galerie/prvky/predchozi.svg");
 | 
			
		||||
	filter: drop-shadow(0px 5px 5px rgba(0, 0, 0, 0.4));
 | 
			
		||||
	background-position: left center;
 | 
			
		||||
	background-repeat: no-repeat;
 | 
			
		||||
}
 | 
			
		||||
.dalsi_obrazek{
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	z-index: 1;
 | 
			
		||||
	width: 33%;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	left: 67%;
 | 
			
		||||
	top: 0;
 | 
			
		||||
}
 | 
			
		||||
.dalsi_obrazek:hover{
 | 
			
		||||
	background-image: url("/static/galerie/prvky/dalsi.svg");
 | 
			
		||||
	filter: drop-shadow(0px 5px 5px rgba(0, 0, 0, 0.4));
 | 
			
		||||
	background-position: right center;
 | 
			
		||||
	background-repeat: no-repeat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.galerie {
 | 
			
		||||
	position: relative;
 | 
			
		||||
	text-align: center;
 | 
			
		||||
	margin: 20px auto 0 auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.galerie h1 {
 | 
			
		||||
	text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.galerie_hlavicka {
 | 
			
		||||
	margin: 30px auto 30px auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popis {
 | 
			
		||||
	margin: 10px 10px 30px 0px;
 | 
			
		||||
	text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#nahoru {
 | 
			
		||||
	text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* titulní obrázek hlavní galerie soustředění */
 | 
			
		||||
 | 
			
		||||
.galerie_nahledy{
 | 
			
		||||
	/*margin: 1em 0;*/
 | 
			
		||||
	margin: auto;
 | 
			
		||||
	padding: 10px;
 | 
			
		||||
	text-align: center;
 | 
			
		||||
	overflow: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.galerie_nahledy img {
 | 
			
		||||
	margin: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.galerie_nahledy div.navigace {
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.galerie_nahled, .podgalerie_nahled { /* frame */
 | 
			
		||||
	display: block;
 | 
			
		||||
	position: relative;
 | 
			
		||||
	float: left;
 | 
			
		||||
	width: 200px;
 | 
			
		||||
	height: 200px;
 | 
			
		||||
	text-align: center;
 | 
			
		||||
	border: solid;
 | 
			
		||||
	border-width: 1px;
 | 
			
		||||
	border-radius: 4px;
 | 
			
		||||
	border-color: var(--svetla-oranzova);
 | 
			
		||||
	background-color: var(--barva-pozadi);
 | 
			
		||||
	white-space: nowrap;
 | 
			
		||||
	margin: 10px;
 | 
			
		||||
	font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.galerie_nahled:hover, .podgalerie_nahled:hover {
 | 
			
		||||
	background-color: var(--svetla-oranzova);
 | 
			
		||||
	filter: drop-shadow(0px 5px 5px rgba(0, 0, 0, 0.4));
 | 
			
		||||
	color: var(--tmava-oranzova);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.vystredeno{ /* helper */
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	vertical-align: middle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.galerie_nahled img {
 | 
			
		||||
	vertical-align: middle;
 | 
			
		||||
	max-height: 180px;
 | 
			
		||||
	max-width: 180px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.galerie_nahled div {
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	bottom: 0px;
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.podgalerie_nahled img {
 | 
			
		||||
	margin-top: 20px;
 | 
			
		||||
	margin-bottom: 15px;
 | 
			
		||||
	max-height: 125px;
 | 
			
		||||
	max-width: 167px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.podgalerie_nahled .nazev_galerie {
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	top: 160px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.podgalerie_nahled.mam-org-only, .podgalerie_nahled.mam-resitel-only {
 | 
			
		||||
	margin: 10px;
 | 
			
		||||
	padding: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Odkazy na předchozí a následující podgalerii */
 | 
			
		||||
.galerie_predchozi_nasledujici {
 | 
			
		||||
	overflow: auto;
 | 
			
		||||
	margin: 10px auto 10px auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.galerie_predchozi_nasledujici .predchozi {
 | 
			
		||||
	float: left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.galerie_predchozi_nasledujici .nasledujici {
 | 
			
		||||
	float: right;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* posune kotvu obrázku v galerii o oranžový pruh dolu, aby se pod ním obrázek neschovával */
 | 
			
		||||
/* https://stackoverflow.com/questions/10732690/offsetting-an-html-anchor-to-adjust-for-fixed-header */
 | 
			
		||||
.kotva_obrazku {
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	width: 0;
 | 
			
		||||
	height: 55px; /* viz #title */
 | 
			
		||||
	margin-top: -55px; /* viz #title */
 | 
			
		||||
}
 | 
			
		||||
@media(max-width: 860px) {
 | 
			
		||||
	.kotva_obrazku {
 | 
			
		||||
		height: 3em; /* #FIXME nemám páru, jak zjistit výšku toho elementu */
 | 
			
		||||
		margin-top: -3em; /* #FIXME */
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* plus a minus tlacitka */
 | 
			
		||||
.mam-org-only-galerie {
 | 
			
		||||
	background: var(--orgovska-svetla-fialova);
 | 
			
		||||
	padding: 10px;
 | 
			
		||||
	margin: 10px 10px 10px -20px;
 | 
			
		||||
	border: #333 2px dashed;
 | 
			
		||||
	float: left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mam-org-only-galerie a{
 | 
			
		||||
	padding: 3px 5px;
 | 
			
		||||
	margin: 5px;
 | 
			
		||||
	border-radius: 20px;
 | 
			
		||||
	background-color: var(--tmava-oranzova);;
 | 
			
		||||
	color: var(--barva-pozadi);
 | 
			
		||||
	float: left;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
{% extends "galerie/base.html" %}
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{% block nadpis1a %}
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +46,6 @@
 | 
			
		|||
 | 
			
		||||
{% block content %}
 | 
			
		||||
 | 
			
		||||
  <div class="{% if obrazek.galerie.zobrazit == 1 or obrazek.galerie.zobrazit == 2 %}mam-org-only{% endif %}{% if obrazek.galerie.zobrazit == 3 %}mam-resitel-only{% endif %}">
 | 
			
		||||
 | 
			
		||||
  <h2>
 | 
			
		||||
    {% for g in cesta %}
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +83,7 @@
 | 
			
		|||
 | 
			
		||||
  {# Popisek fotky #}
 | 
			
		||||
  <div class="popis">
 | 
			
		||||
    {% if upravy_popisku %}
 | 
			
		||||
    {% if preview %}
 | 
			
		||||
    <form action=".#nahoru" method="post" id="komentarform">
 | 
			
		||||
      {% csrf_token %}
 | 
			
		||||
      <table>
 | 
			
		||||
| 
						 | 
				
			
			@ -134,6 +133,4 @@
 | 
			
		|||
      {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  </div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
{% extends "galerie/base.html" %}
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
 | 
			
		||||
{% block nadpis1a %}
 | 
			
		||||
Galerie {{galerie.nazev}}
 | 
			
		||||
| 
						 | 
				
			
			@ -6,11 +6,8 @@ Galerie {{galerie.nazev}}
 | 
			
		|||
 | 
			
		||||
{% block content %}
 | 
			
		||||
 | 
			
		||||
  {# FIXME: použít konstanty… #}
 | 
			
		||||
  {% if galerie.zobrazit == 1 or galerie.zobrazit == 2 %}
 | 
			
		||||
  {% if galerie.zobrazit > 0 %}
 | 
			
		||||
    <div class="mam-org-only">
 | 
			
		||||
  {% elif galerie.zobrazit == 3 %}
 | 
			
		||||
    <div class="mam-resitel-only">
 | 
			
		||||
  {% endif %}
 | 
			
		||||
 | 
			
		||||
  <h2>
 | 
			
		||||
| 
						 | 
				
			
			@ -48,43 +45,37 @@ Galerie {{galerie.nazev}}
 | 
			
		|||
    {% if podgalerie %}
 | 
			
		||||
      {% with 22 as max_delka_nazvu %}
 | 
			
		||||
      <div class="galerie_nahledy">
 | 
			
		||||
      {% for pgalerie in podgalerie %}
 | 
			
		||||
          <a href="../{{pgalerie.pk}}"
 | 
			
		||||
            {% if pgalerie.nazev|length > max_delka_nazvu %}
 | 
			
		||||
              title="{{ pgalerie.nazev }}"
 | 
			
		||||
      {% for galerie in podgalerie %}
 | 
			
		||||
        <a href="../{{galerie.pk}}"
 | 
			
		||||
          {% if galerie.nazev|length > max_delka_nazvu %}
 | 
			
		||||
            title="{{ galerie.nazev }}"
 | 
			
		||||
          {% endif %}
 | 
			
		||||
         class="podgalerie_nahled">
 | 
			
		||||
            {% if galerie.titulni_obrazek %}
 | 
			
		||||
              {% with galerie.titulni_obrazek.obrazek_maly as obrazek %}
 | 
			
		||||
                <img src="{{ obrazek.url }}"
 | 
			
		||||
                />
 | 
			
		||||
              {% endwith %}
 | 
			
		||||
            {% endif %}
 | 
			
		||||
           class="podgalerie_nahled {% if pgalerie.zobrazit == 1 or pgalerie.zobrazit == 2 %}mam-org-only{% endif %}{% if pgalerie.zobrazit == 3 %}mam-resitel-only{% endif %}">
 | 
			
		||||
              {% if pgalerie.titulni_obrazek %}
 | 
			
		||||
                {% with pgalerie.titulni_obrazek.obrazek_maly as obrazek %}
 | 
			
		||||
                  <img src="{{ obrazek.url }}"
 | 
			
		||||
                  />
 | 
			
		||||
                {% endwith %}
 | 
			
		||||
              {% endif %}
 | 
			
		||||
              <div class="nazev_galerie">
 | 
			
		||||
              {{ pgalerie|truncatechars:max_delka_nazvu }}
 | 
			
		||||
              </div>
 | 
			
		||||
          </a>
 | 
			
		||||
          {% if galerie.zobrazit == 1 or galerie.zobrazit == 2 %}
 | 
			
		||||
          {% if user.je_org %}
 | 
			
		||||
            <div class="mam-org-only-galerie">
 | 
			
		||||
              ({{pgalerie.poradi}})
 | 
			
		||||
              <span class="plus"><a href="plus/{{pgalerie.pk}}/">+</a></span>
 | 
			
		||||
              <span class="minus"><a href="minus/{{pgalerie.pk}}/">-</a></span>
 | 
			
		||||
            <div class="nazev_galerie">
 | 
			
		||||
            {{ galerie|truncatechars:max_delka_nazvu }}
 | 
			
		||||
            </div>
 | 
			
		||||
          {% endif %}
 | 
			
		||||
          {% endif %}
 | 
			
		||||
        </a>
 | 
			
		||||
        {% if user.je_org and galerie.zobrazit > 0 %}
 | 
			
		||||
          <div class="mam-org-only-galerie">
 | 
			
		||||
            ({{galerie.poradi}})
 | 
			
		||||
            <span class="plus"><a href="plus/{{galerie.pk}}/">+</a></span>
 | 
			
		||||
            <span class="minus"><a href="minus/{{galerie.pk}}/">-</a></span>
 | 
			
		||||
          </div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
      {% endfor %}
 | 
			
		||||
      </div>
 | 
			
		||||
      {% endwith %}
 | 
			
		||||
    {% endif %}
 | 
			
		||||
  {% endif %}
 | 
			
		||||
  {% if user.je_org %}
 | 
			
		||||
  {% if user.je_org and galerie.zobrazit > 0 %}
 | 
			
		||||
  <div class="mam-org-only">
 | 
			
		||||
    {% if galerie.zobrazit == 1 or galerie.zobrazit == 2 %}
 | 
			
		||||
      <a href="./new">Vytvořit novou podgalerii</a>, <a href="{% url 'admin:galerie_galerie_change' galerie.pk %}">upravit galerii v adminu</a>
 | 
			
		||||
    {% else %}
 | 
			
		||||
      Jestli chceš změnit pořadí podgalerií nebo přidat novou, nastav zobrazení jen pro orgy v <a href="{% url 'admin:galerie_galerie_change' galerie.pk %}">adminu</a>.
 | 
			
		||||
    {% endif %}
 | 
			
		||||
      <a href="./new">Vytvořit novou podgalerii </a>
 | 
			
		||||
  </div>
 | 
			
		||||
  {% endif %}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -129,10 +120,8 @@ Galerie {{galerie.nazev}}
 | 
			
		|||
    {% endif %}
 | 
			
		||||
  {% endif %}
 | 
			
		||||
 | 
			
		||||
  {% if galerie.zobrazit == 1 or galerie.zobrazit == 2 %}
 | 
			
		||||
  {% if galerie.zobrazit > 0 %}
 | 
			
		||||
    </div> {# mam-org-only #}
 | 
			
		||||
  {% elif galerie.zobrazit == 2 %}
 | 
			
		||||
    </div> {# mam-resitel-only #}
 | 
			
		||||
  {% endif %}
 | 
			
		||||
 | 
			
		||||
{% endblock content %}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
{% extends "galerie/base.html" %}
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +0,0 @@
 | 
			
		|||
{% extends "base.html" %}
 | 
			
		||||
{% load static %}
 | 
			
		||||
 | 
			
		||||
{% block custom_css %}
 | 
			
		||||
  <link href="{% static 'css/galerie.css' %}?version=2" rel="stylesheet">
 | 
			
		||||
{% endblock %}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,7 @@
 | 
			
		|||
# coding: utf-8
 | 
			
		||||
 | 
			
		||||
from django.urls import path
 | 
			
		||||
from personalni.utils import org_required
 | 
			
		||||
from seminar.utils import org_required
 | 
			
		||||
from . import views
 | 
			
		||||
 | 
			
		||||
urlpatterns = [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +0,0 @@
 | 
			
		|||
from galerie.models import Galerie
 | 
			
		||||
 | 
			
		||||
def top_galerie(g: Galerie) -> Galerie:
 | 
			
		||||
	while g.galerie_up is not None:
 | 
			
		||||
		g = g.galerie_up
 | 
			
		||||
	return g
 | 
			
		||||
							
								
								
									
										141
									
								
								galerie/views.py
									
									
									
									
									
								
							
							
						
						
									
										141
									
								
								galerie/views.py
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,41 +1,24 @@
 | 
			
		|||
# coding: utf-8
 | 
			
		||||
 | 
			
		||||
import random
 | 
			
		||||
 | 
			
		||||
from django.http import HttpResponse, Http404, HttpRequest
 | 
			
		||||
from django.http import HttpResponse, Http404
 | 
			
		||||
from django.shortcuts import render, HttpResponseRedirect, get_object_or_404
 | 
			
		||||
from django.template import RequestContext
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
from galerie.utils import top_galerie
 | 
			
		||||
from personalni.utils import resitel_uzivatele
 | 
			
		||||
 | 
			
		||||
from galerie.models import Obrazek, Galerie, VZDY, ORG, UCASTNIK, NIKDY
 | 
			
		||||
from soustredeni.models import Soustredeni
 | 
			
		||||
from galerie.models import Obrazek, Galerie
 | 
			
		||||
from seminar.models import Soustredeni
 | 
			
		||||
from galerie.forms import KomentarForm, NewGalerieForm
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
logger = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
def galerie_ke_zobrazeni(soustredeni: Soustredeni | None, request: HttpRequest) -> tuple[int]:
 | 
			
		||||
	if request.user.is_superuser: return (VZDY, ORG, UCASTNIK, NIKDY)
 | 
			
		||||
	if request.user.je_org: return (VZDY, ORG, UCASTNIK)
 | 
			
		||||
	if request.user.is_anonymous: return (VZDY,)
 | 
			
		||||
	if soustredeni is None: return (VZDY,)
 | 
			
		||||
	if (resitel := resitel_uzivatele(request.user)) is not None:
 | 
			
		||||
		if resitel.soustredeni_set.contains(soustredeni):
 | 
			
		||||
			return (VZDY, UCASTNIK)
 | 
			
		||||
def zobrazit(galerie, request):
 | 
			
		||||
	preview = False
 | 
			
		||||
	if galerie.zobrazit >= 1:
 | 
			
		||||
		if request.user.je_org:
 | 
			
		||||
			preview = True;
 | 
			
		||||
		else:
 | 
			
		||||
			return (VZDY,)
 | 
			
		||||
	logger.warning("Nepodařilo se zjistit, jaké galerie se mají zobrazit!")
 | 
			
		||||
	return (VZDY,)
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
def zobrazit(galerie: Galerie, request: HttpRequest) -> bool:
 | 
			
		||||
	soustredeni = top_galerie(galerie).soustredeni
 | 
			
		||||
	return galerie.zobrazit in galerie_ke_zobrazeni(soustredeni, request)
 | 
			
		||||
 | 
			
		||||
def dovolit_upravy_popisku(galerie: Galerie, request: HttpRequest) -> bool:
 | 
			
		||||
	# FIXME: Dočasné: úpravy jen když je to v org-only stavu. (Odpovídá předchozímu chování)
 | 
			
		||||
	return request.user.je_org and galerie.zobrazit in (ORG, NIKDY)
 | 
			
		||||
			raise Http404
 | 
			
		||||
	return preview
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def cesta_od_korene(g):
 | 
			
		||||
| 
						 | 
				
			
			@ -50,19 +33,19 @@ def cesta_od_korene(g):
 | 
			
		|||
def nahled(request, pk, soustredeni):
 | 
			
		||||
	"""Zobrazeni nahledu vsech fotek ve skupine."""
 | 
			
		||||
	galerie = get_object_or_404(Galerie, pk=pk)
 | 
			
		||||
	soustredeni = top_galerie(galerie).soustredeni
 | 
			
		||||
 | 
			
		||||
	# FIXME: přepsat model a použít přímo dolů…
 | 
			
		||||
	podgalerie = Galerie.objects.filter(galerie_up = galerie).order_by('poradi')
 | 
			
		||||
	podgalerie = podgalerie.filter(zobrazit__in=galerie_ke_zobrazeni(soustredeni, request))
 | 
			
		||||
	if not request.user.je_org:
 | 
			
		||||
		podgalerie = podgalerie.filter(zobrazit__lt=1)
 | 
			
		||||
 | 
			
		||||
	obrazky = galerie.obrazek_set.all().order_by('poradi', 'nazev')
 | 
			
		||||
	ma_se_zobrazit = zobrazit(galerie, request)
 | 
			
		||||
	if not ma_se_zobrazit: raise Http404("Galerie sice existuje, ale my se tváříme, že ne :-D")
 | 
			
		||||
	obrazky = Obrazek.objects.filter(galerie = galerie).order_by('poradi', 'nazev')
 | 
			
		||||
	preview = zobrazit(galerie, request)
 | 
			
		||||
 | 
			
		||||
	sourozenci = []
 | 
			
		||||
	if galerie.galerie_up:
 | 
			
		||||
		sourozenci = galerie.galerie_up.galerie_set.filter(zobrazit__in=galerie_ke_zobrazeni(soustredeni, request)).order_by('poradi')
 | 
			
		||||
		sourozenci = galerie.galerie_up.galerie_set.all().order_by('poradi')
 | 
			
		||||
		if not request.user.je_org:
 | 
			
		||||
			sourozenci = sourozenci.filter(zobrazit__lt=1)
 | 
			
		||||
 | 
			
		||||
	predchozi = None
 | 
			
		||||
	nasledujici = None
 | 
			
		||||
| 
						 | 
				
			
			@ -81,6 +64,7 @@ def nahled(request, pk, soustredeni):
 | 
			
		|||
		{'galerie' : galerie,
 | 
			
		||||
		 'podgalerie' : podgalerie,
 | 
			
		||||
		 'obrazky' : obrazky,
 | 
			
		||||
		 'preview' : preview,
 | 
			
		||||
		 'cesta': cesta,
 | 
			
		||||
		 'sourozenci': sourozenci,
 | 
			
		||||
		 'predchozi': predchozi,
 | 
			
		||||
| 
						 | 
				
			
			@ -96,41 +80,9 @@ def detail(request, pk, fotka, soustredeni):
 | 
			
		|||
	NAHLEDU = 1
 | 
			
		||||
 | 
			
		||||
	galerie = get_object_or_404(Galerie, pk=pk)
 | 
			
		||||
	soustredeni = top_galerie(galerie).soustredeni
 | 
			
		||||
	ma_se_zobrazit = zobrazit(galerie, request)
 | 
			
		||||
	if not ma_se_zobrazit: raise Http404("Obrázek neukážu!")
 | 
			
		||||
	preview = zobrazit(galerie, request)
 | 
			
		||||
	obrazek = get_object_or_404(Obrazek, pk=fotka)
 | 
			
		||||
 | 
			
		||||
	# Pořadí není povinné. FIXME: `nazev` je zavádějící… Ale tohle je kanonické pořadí obrázků v galerii…
 | 
			
		||||
	obrazky = galerie.obrazek_set.all().order_by('poradi', 'nazev')
 | 
			
		||||
	obrazky = list(obrazky)
 | 
			
		||||
	index_obrazku = obrazky.index(obrazek)
 | 
			
		||||
	# Podle mě se nemůže stát, že by volání výš selhalo, kdyžtak shodí web. (původně to byl explicitně ošetřený stav dávající 404)
 | 
			
		||||
	predchozi_obrazky = list(reversed(obrazky[:index_obrazku]))
 | 
			
		||||
	nasledujici_obrazky = obrazky[index_obrazku+1:]
 | 
			
		||||
	# Může jich být hodně…
 | 
			
		||||
	predchozi_obrazky = predchozi_obrazky[:NAHLEDU]
 | 
			
		||||
	nasledujici_obrazky = nasledujici_obrazky[:NAHLEDU]
 | 
			
		||||
	# Předchozí obrázky chceme v normálním pořadí
 | 
			
		||||
	predchozi_obrazky = list(reversed(predchozi_obrazky))
 | 
			
		||||
 | 
			
		||||
	if galerie.galerie_up is not None:
 | 
			
		||||
		sousedni_galerie = Galerie.objects.filter(galerie_up=galerie.galerie_up, zobrazit__in=galerie_ke_zobrazeni(soustredeni, request)).order_by('poradi')
 | 
			
		||||
		sousedni_galerie = list(sousedni_galerie)
 | 
			
		||||
		# Teoreticky se můžeme dívat na galerie.poradi, ale jednak už tenhle pattern stejně je výš a druhak je galerií málo, takže pomalost nevadí.
 | 
			
		||||
		index_galerie = sousedni_galerie.index(galerie)
 | 
			
		||||
		predchozi_galerie = sousedni_galerie[index_galerie-1] if index_galerie > 0 else None
 | 
			
		||||
		nasledujici_galerie = sousedni_galerie[index_galerie+1] if index_galerie < len(sousedni_galerie) - 1 else None
 | 
			
		||||
	else:
 | 
			
		||||
		predchozi_galerie = None
 | 
			
		||||
		nasledujici_galerie = None
 | 
			
		||||
 | 
			
		||||
	# Pokud je obrázků dost, tak další galerii nepotřebujeme
 | 
			
		||||
	# (jo, mohli jsme si ušetřit práci, ale takhle je kód imho přehlednější a za pár ušetřených dotazů do DB to nestojí)
 | 
			
		||||
	if len(predchozi_obrazky) >= NAHLEDU:
 | 
			
		||||
		predchozi_galerie = None
 | 
			
		||||
	if len(nasledujici_obrazky) >= NAHLEDU:
 | 
			
		||||
		nasledujici_galerie = None
 | 
			
		||||
 | 
			
		||||
	# vytvoreni a obslouzeni formulare
 | 
			
		||||
	if request.method == 'POST':
 | 
			
		||||
| 
						 | 
				
			
			@ -141,6 +93,49 @@ def detail(request, pk, fotka, soustredeni):
 | 
			
		|||
	else:
 | 
			
		||||
		form = KomentarForm({'komentar': obrazek.popis})
 | 
			
		||||
 | 
			
		||||
	# Poradi aktualniho obrazku v galerii/stitku.
 | 
			
		||||
	for i in range(len(obrazky)):
 | 
			
		||||
		if obrazky[i] == obrazek:
 | 
			
		||||
			poradi = i
 | 
			
		||||
			break
 | 
			
		||||
	else:
 | 
			
		||||
		# Obrazek neni v galerii/stitku.
 | 
			
		||||
		raise Http404
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	# Nacteni okolnich obrazku a galerii
 | 
			
		||||
	# TODO vyjmout zjisteni predchozich a nasledujicich galerii
 | 
			
		||||
	# a udelat z toho funkci, ktera se pouzije u nahledu
 | 
			
		||||
	predchozi_galerie = None
 | 
			
		||||
	nasledujici_galerie = None
 | 
			
		||||
	obrazky_dalsi = obrazky[poradi+1:poradi+NAHLEDU+1]
 | 
			
		||||
	if (poradi+1) > NAHLEDU:
 | 
			
		||||
		obrazky_predchozi = obrazky[poradi-NAHLEDU:poradi]
 | 
			
		||||
	else:
 | 
			
		||||
		obrazky_predchozi = obrazky[0:poradi]
 | 
			
		||||
		if galerie.poradi > 1:
 | 
			
		||||
			predchozi_galerie = Galerie.objects.\
 | 
			
		||||
				filter(galerie_up=galerie.galerie_up).\
 | 
			
		||||
				filter(poradi=(galerie.poradi-1))
 | 
			
		||||
		if predchozi_galerie:
 | 
			
		||||
			predchozi_galerie = predchozi_galerie[0]
 | 
			
		||||
		else:
 | 
			
		||||
			predchozi_galerie = None
 | 
			
		||||
	if (poradi+1) == len(obrazky):		# Tohle je poslední obrázek
 | 
			
		||||
		if (galerie.poradi is not None
 | 
			
		||||
			and galerie.galerie_up is not None):
 | 
			
		||||
				nasledujici_galerie = Galerie.objects.\
 | 
			
		||||
					filter(galerie_up=galerie.galerie_up).\
 | 
			
		||||
					filter(poradi=(galerie.poradi+1))
 | 
			
		||||
		else:
 | 
			
		||||
			nasledujici_galerie = None
 | 
			
		||||
		if nasledujici_galerie:
 | 
			
		||||
			nasledujici_galerie = nasledujici_galerie[0]
 | 
			
		||||
		else:
 | 
			
		||||
			nasledujici_galerie = None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	# Preskalovani obrazku do vybraneho prostoru.
 | 
			
		||||
	vyska = obrazek.obrazek_stredni.height
 | 
			
		||||
	sirka = obrazek.obrazek_stredni.width
 | 
			
		||||
| 
						 | 
				
			
			@ -158,9 +153,9 @@ def detail(request, pk, fotka, soustredeni):
 | 
			
		|||
		 'obrazek' : obrazek,
 | 
			
		||||
		 'vyska' : vyska,
 | 
			
		||||
		 'sirka' : sirka,
 | 
			
		||||
		 'obrazky_predchozi' : predchozi_obrazky,
 | 
			
		||||
		 'obrazky_dalsi' : nasledujici_obrazky,
 | 
			
		||||
		 'upravy_popisku' : dovolit_upravy_popisku(galerie, request),
 | 
			
		||||
		 'obrazky_predchozi' : obrazky_predchozi,
 | 
			
		||||
		 'obrazky_dalsi' : obrazky_dalsi,
 | 
			
		||||
		 'preview' : preview,
 | 
			
		||||
		 'form' : form,
 | 
			
		||||
		 'cesta': cesta_od_korene(galerie),
 | 
			
		||||
		})
 | 
			
		||||
| 
						 | 
				
			
			@ -186,7 +181,7 @@ def new_galerie(request, galerie, soustredeni):
 | 
			
		|||
			gal = Galerie()
 | 
			
		||||
			gal.nazev = form.cleaned_data['nazev']
 | 
			
		||||
			#gal.popis = form.cleaned_data['popis'] # popis nepouzivame
 | 
			
		||||
			gal.zobrazit = ORG # galerie je v procesu vytvareni
 | 
			
		||||
			gal.zobrazit = 1 # galerie je v procesu vytvareni
 | 
			
		||||
			''' pokud je to podgalerie pridej nadrazenou galerii
 | 
			
		||||
			a nadrazene soustredeni nechej volne,
 | 
			
		||||
			pokud je to hlavni galerie, tak nadrazena galerie neexistuje,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +0,0 @@
 | 
			
		|||
"""
 | 
			
		||||
Aplikace umožňující „na uživatelské úrovni“ měnit obrázek v pozadí meníčka.
 | 
			
		||||
 | 
			
		||||
Umožňuje uložit obrázek a následně popsat, na kterých stránkách (podle url)
 | 
			
		||||
a v který čas (den/noc) se má zobrazovat.
 | 
			
		||||
"""
 | 
			
		||||
| 
						 | 
				
			
			@ -4,10 +4,6 @@ import header_fotky.models as m
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
class FotkaPozadiAdmin(ModelAdmin):
 | 
			
		||||
    """
 | 
			
		||||
    Nastaví čas vložení (:attr:`~header_fotky.models.FotkaHeader.cas`) jako
 | 
			
		||||
    readonly = neměnitelný
 | 
			
		||||
    """
 | 
			
		||||
    readonly_fields = ['cas']
 | 
			
		||||
 | 
			
		||||
admin.site.register(m.FotkaHeader, FotkaPozadiAdmin)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,4 +3,3 @@ from django.apps import AppConfig
 | 
			
		|||
 | 
			
		||||
class HeaderFotkyConfig(AppConfig):
 | 
			
		||||
    name = 'header_fotky'
 | 
			
		||||
    verbose_name = 'Fotky v záhlaví'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,4 @@
 | 
			
		|||
"""
 | 
			
		||||
Context processory lze přidat do djanga v :mod:`~mamweb.settings` a dělají to,
 | 
			
		||||
že do contextu (tj. to, z čeho se např. berou proměnné v templatech) libovolné
 | 
			
		||||
stránky přidají další věci.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from datetime import datetime, date
 | 
			
		||||
import random
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -12,46 +8,38 @@ from header_fotky.models import FotkaUrlVazba
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def vzhled(request):
 | 
			
		||||
	"""
 | 
			
		||||
		Podle času přidá do contextu, zdali je nebo není noc. Dále podle dení
 | 
			
		||||
		doby a url přidá do contextu správnou fotku.
 | 
			
		||||
    ''' Podle casu prida do templatu, zdali je nebo neni noc '''
 | 
			
		||||
    hodin = datetime.now().hour
 | 
			
		||||
    if (hodin <= 6) or (hodin >= 20):
 | 
			
		||||
        noc = True
 | 
			
		||||
        nedoba = 'den'
 | 
			
		||||
        doba = 'noc'
 | 
			
		||||
    else:
 | 
			
		||||
        noc = False
 | 
			
		||||
        nedoba = 'noc'
 | 
			
		||||
        doba = 'den'
 | 
			
		||||
    url = request.path
 | 
			
		||||
 | 
			
		||||
		url adresu nejprve vyzkouší celou, pak postupně odřezává věci za
 | 
			
		||||
		lomítkem, dokud nenajde url, pro kterou existuje alespoň jedna fotka.
 | 
			
		||||
		Z fotek pro toto url zkusí vybrat tu ve správné denní době a až poté
 | 
			
		||||
		libovolnou. (Z více možných fotek pro 1 url a 1 dobu vybírá náhodně.)
 | 
			
		||||
	"""
 | 
			
		||||
	hodin = datetime.now().hour
 | 
			
		||||
	if (hodin <= 6) or (hodin >= 20):
 | 
			
		||||
		noc = True
 | 
			
		||||
		nedoba = 'den'
 | 
			
		||||
		doba = 'noc'
 | 
			
		||||
	else:
 | 
			
		||||
		noc = False
 | 
			
		||||
		nedoba = 'noc'
 | 
			
		||||
		doba = 'den'
 | 
			
		||||
	url = request.path
 | 
			
		||||
    fotky = FotkaUrlVazba.objects.exclude(denni_doba=nedoba)
 | 
			
		||||
    fotka = None
 | 
			
		||||
 | 
			
		||||
	fotky = FotkaUrlVazba.objects.exclude(denni_doba=nedoba)
 | 
			
		||||
	fotka = None
 | 
			
		||||
    # TODO rychlejší patternmatch?
 | 
			
		||||
    while (fotka is None) and (url != ''):
 | 
			
		||||
        presne = fotky.filter(url__exact=url)
 | 
			
		||||
        if presne.count() > 0:
 | 
			
		||||
            presne_doba = presne.filter(denni_doba=doba)
 | 
			
		||||
            if presne_doba.count() > 0:
 | 
			
		||||
                fotka = random.choice(presne_doba).url_fotky()
 | 
			
		||||
            else:
 | 
			
		||||
                fotka = random.choice(presne).url_fotky()
 | 
			
		||||
 | 
			
		||||
	# TODO rychlejší patternmatch?
 | 
			
		||||
	while (fotka is None) and (url != ''):
 | 
			
		||||
		presne = fotky.filter(url__exact=url)
 | 
			
		||||
		if presne.count() > 0:
 | 
			
		||||
			presne_doba = presne.filter(denni_doba=doba)
 | 
			
		||||
			if presne_doba.count() > 0:
 | 
			
		||||
				fotka = random.choice(presne_doba).url_fotky()
 | 
			
		||||
			else:
 | 
			
		||||
				fotka = random.choice(presne).url_fotky()
 | 
			
		||||
        url = url[:-1]
 | 
			
		||||
        index = url.rfind('/')
 | 
			
		||||
        if index != -1:
 | 
			
		||||
            url = url[:index+1]
 | 
			
		||||
 | 
			
		||||
		url = url[:-1]
 | 
			
		||||
		index = url.rfind('/')
 | 
			
		||||
		if index != -1:
 | 
			
		||||
			url = url[:index+1]
 | 
			
		||||
    if fotka is None:
 | 
			
		||||
        fotka = settings.STATIC_URL + "images/header/vikendovka.jpg"
 | 
			
		||||
 | 
			
		||||
	if fotka is None:
 | 
			
		||||
		fotka = settings.STATIC_URL + "images/header/vikendovka.jpg"
 | 
			
		||||
 | 
			
		||||
	return {'noc': noc, 'fotka': fotka}
 | 
			
		||||
    return {'noc': noc, 'fotka': fotka}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,6 @@ from django.utils import timezone
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
class FotkaHeader(models.Model):
 | 
			
		||||
	""" fotka pro :mod:`fotka_header`, konkrétně :class:`~fotka_header.models.FotkaUrlVazba` """
 | 
			
		||||
	class Meta:
 | 
			
		||||
		ordering = ['-cas']
 | 
			
		||||
		db_table = 'fotky_header'
 | 
			
		||||
| 
						 | 
				
			
			@ -12,34 +11,27 @@ class FotkaHeader(models.Model):
 | 
			
		|||
		verbose_name_plural = u'fotky do pozadí menu'
 | 
			
		||||
 | 
			
		||||
	cas = models.DateTimeField(u'čas vložení fotky', default=timezone.now, help_text='Čas vložení fotky')
 | 
			
		||||
	""" čas vložení fotky """
 | 
			
		||||
 | 
			
		||||
	nazev = models.CharField(
 | 
			
		||||
		u'název fotky', null=False, blank=False, unique=True, primary_key=True,
 | 
			
		||||
		max_length=50, help_text='Název např. archiv_noc'
 | 
			
		||||
	)
 | 
			
		||||
	""" jméno fotky na webu """
 | 
			
		||||
 | 
			
		||||
	fotka = models.ImageField(upload_to='header', null=False, blank=False)
 | 
			
		||||
	""" soubor fotky (Nahrává se automaticky do složky ``media``.) """
 | 
			
		||||
 | 
			
		||||
	def __str__(self):
 | 
			
		||||
		return self.nazev
 | 
			
		||||
 | 
			
		||||
	def clean(self):
 | 
			
		||||
		""" kontroluje, zda sedí poměr stran """
 | 
			
		||||
		if not self.fotka:
 | 
			
		||||
			raise ValidationError("Chybí obrázek")
 | 
			
		||||
		""" Kontroluje, zda sedí poměr stran """
 | 
			
		||||
		if abs(self.fotka.width - (self.fotka.height * 970 / 350)) > 2:
 | 
			
		||||
			raise ValidationError("Obrázek by měl mít rozměry 970w na 350h, nebo alespoň podobný poměr stran.")
 | 
			
		||||
		super().clean()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FotkaUrlVazba(models.Model):
 | 
			
		||||
	"""
 | 
			
		||||
		spojení :class:`~fotka_header.models.FotkaHeader` a url
 | 
			
		||||
		(resp. „prefixu“ url), na které má být zobrazována
 | 
			
		||||
	"""
 | 
			
		||||
	class Meta:
 | 
			
		||||
		ordering = ['url']
 | 
			
		||||
		db_table = 'fotky_url_vazby'
 | 
			
		||||
| 
						 | 
				
			
			@ -50,13 +42,11 @@ class FotkaUrlVazba(models.Model):
 | 
			
		|||
		u'URL', blank=True, null=False, max_length=100,
 | 
			
		||||
		help_text='url prefix stránek např: /archiv/ nebo /'
 | 
			
		||||
	)
 | 
			
		||||
	""" url prefix stránek, kde má být fotka zobrazena, např: /archiv/ nebo / """
 | 
			
		||||
 | 
			
		||||
	fotka = models.ForeignKey(
 | 
			
		||||
		FotkaHeader, blank=False, null=False, verbose_name='fotka',
 | 
			
		||||
		on_delete=models.CASCADE
 | 
			
		||||
	)
 | 
			
		||||
	""" :class:`~fotka_header.models.FotkaHeader`, která má být zobrazována """
 | 
			
		||||
 | 
			
		||||
	DOBA_DEN = 'den'
 | 
			
		||||
	DOBA_NOC = 'noc'
 | 
			
		||||
| 
						 | 
				
			
			@ -67,11 +57,9 @@ class FotkaUrlVazba(models.Model):
 | 
			
		|||
		(DOBA_OBOJI, 'Zobrazovat pořád')]
 | 
			
		||||
 | 
			
		||||
	denni_doba = models.CharField('denní doba', max_length=16, choices=DOBA_CHOICES, blank=False, default=DOBA_OBOJI)
 | 
			
		||||
	""" dení doba, kdy tam má být zobrazována """
 | 
			
		||||
 | 
			
		||||
	def __str__(self):
 | 
			
		||||
		return self.url
 | 
			
		||||
 | 
			
		||||
	def url_fotky(self):
 | 
			
		||||
		""" vrací url fotky (tj. url, kde reálně získám soubor fotky) """
 | 
			
		||||
		return self.fotka.fotka.url
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,3 @@
 | 
			
		|||
FIXME přepsat do rst, přidat i další věci a případně přesunout na wiki
 | 
			
		||||
Přidání obrázků do odměn:
 | 
			
		||||
admin -> flatpage odměn -> ikona přidat obrázek
 | 
			
		||||
záložka odeslat, vybrat obrázek, odeslat
 | 
			
		||||
							
								
								
									
										11
									
								
								korektury/TODO
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								korektury/TODO
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
- korektura potrebuje reakci
 | 
			
		||||
+ komentáře fixně na username
 | 
			
		||||
  - používat skutečné jméno?
 | 
			
		||||
- vyžádat pozornost autora obsahu
 | 
			
		||||
- zvednout upload limit na 5MB
 | 
			
		||||
- sbalit a rozbalit korekturu
 | 
			
		||||
- nahrávání jiných věcí než PDF - kontrolovat?
 | 
			
		||||
- stylování
 | 
			
		||||
- seznam PDF - co zobrazovat?
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +0,0 @@
 | 
			
		|||
"""
 | 
			
		||||
    Seznam pdf k opravě a `opraf`_ v djangu místo PHP.
 | 
			
		||||
 | 
			
		||||
    .. _opraf: https://github.com/vitstradal/opraf
 | 
			
		||||
"""
 | 
			
		||||
| 
						 | 
				
			
			@ -1,23 +1,16 @@
 | 
			
		|||
from django.contrib import admin
 | 
			
		||||
from reversion.admin import VersionAdmin
 | 
			
		||||
from korektury.models import KorekturovanePDF, Oprava, KorekturaTag
 | 
			
		||||
from korektury.models import KorekturovanePDF
 | 
			
		||||
 | 
			
		||||
from django.core.mail import EmailMessage
 | 
			
		||||
from django.core.mail import send_mail
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
 | 
			
		||||
# Register your models here.
 | 
			
		||||
class KorekturovanePDFAdmin(VersionAdmin):
 | 
			
		||||
	"""
 | 
			
		||||
	nastaví čas vložení (:attr:`~koretkury.models.KorekturovanePDF.cas`) a počet
 | 
			
		||||
	stran (:attr:`~koretkury.models.KorekturovanePDF.stran`) jako readonly =
 | 
			
		||||
	neměnitelný
 | 
			
		||||
 | 
			
		||||
	Při prvním uložení pošle e-mail.
 | 
			
		||||
	"""
 | 
			
		||||
 | 
			
		||||
	readonly_fields = ['cas', 'stran']
 | 
			
		||||
 | 
			
		||||
	def get_readonly_fields(self, request, obj=None):
 | 
			
		||||
		""" Když pdf existuje, tak nedovolím měnit ani pdf."""
 | 
			
		||||
		if obj:
 | 
			
		||||
			return self.readonly_fields + ['pdf']
 | 
			
		||||
		return self.readonly_fields
 | 
			
		||||
| 
						 | 
				
			
			@ -25,18 +18,14 @@ class KorekturovanePDFAdmin(VersionAdmin):
 | 
			
		|||
	fieldsets = [
 | 
			
		||||
			(None,
 | 
			
		||||
				{'fields':
 | 
			
		||||
					['pdf', 'cas', 'stran', 'nazev', 'orgove', 'komentar', 'poslat_mail']}),
 | 
			
		||||
					['pdf', 'cas', 'org', 'stran', 'nazev', 'komentar', 'poslat_mail']}),
 | 
			
		||||
			# (u'PDF',       {'fields': ['pdf']}),
 | 
			
		||||
				]
 | 
			
		||||
	list_display = ['nazev', 'cas', 'stran']
 | 
			
		||||
	list_display = ['nazev', 'cas', 'stran', 'org']
 | 
			
		||||
	list_filter = []
 | 
			
		||||
	search_fields = []
 | 
			
		||||
	autocomplete_fields = ['orgove']
 | 
			
		||||
 | 
			
		||||
	def save_model(self, request, obj, form, change):
 | 
			
		||||
		"""
 | 
			
		||||
			Pokud je soubor nový a má se poslat e-mail, tak pošle e-mail o novém pdf.
 | 
			
		||||
		"""
 | 
			
		||||
		super().save_model(request, obj, form, change)
 | 
			
		||||
		if not change and obj.poslat_mail: # Je nový a má se poslat mail
 | 
			
		||||
			odkaz = request.build_absolute_uri(reverse('korektury', kwargs={'pdf': obj.id}))
 | 
			
		||||
| 
						 | 
				
			
			@ -54,19 +43,6 @@ Popis souboru:
 | 
			
		|||
S pozdravem a korekturám zdar!
 | 
			
		||||
Korekturovátko
 | 
			
		||||
'''
 | 
			
		||||
			EmailMessage(
 | 
			
		||||
				subject=predmet,
 | 
			
		||||
				body=text,
 | 
			
		||||
				from_email=odesilatel,
 | 
			
		||||
				to=[prijemce],
 | 
			
		||||
			).send()
 | 
			
		||||
			send_mail(predmet,text,odesilatel,[prijemce])
 | 
			
		||||
 | 
			
		||||
admin.site.register(KorekturovanePDF, KorekturovanePDFAdmin)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class OpravaAdmin(admin.ModelAdmin):
 | 
			
		||||
	model = Oprava
 | 
			
		||||
	filter_horizontal = ("informovani_orgove", "tagy",)
 | 
			
		||||
 | 
			
		||||
admin.site.register(Oprava, OpravaAdmin)
 | 
			
		||||
admin.site.register(KorekturaTag)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +0,0 @@
 | 
			
		|||
from django.apps import AppConfig
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ApiConfig(AppConfig):
 | 
			
		||||
	default_auto_field = 'django.db.models.BigAutoField'
 | 
			
		||||
	name = 'korektury.api'
 | 
			
		||||
	label = 'korektury_api' # Protože jedno api už máme.
 | 
			
		||||
| 
						 | 
				
			
			@ -1,11 +0,0 @@
 | 
			
		|||
from django.urls import path
 | 
			
		||||
from personalni.utils import org_required
 | 
			
		||||
from . import views
 | 
			
		||||
 | 
			
		||||
urlpatterns = [
 | 
			
		||||
	path('<int:pdf_id>/stav', org_required(views.korektury_stav_view), name='korektury_api_pdf_stav'),
 | 
			
		||||
	path('oprava/stav', org_required(views.oprava_stav_view), name='korektury_api_oprava_stav'),
 | 
			
		||||
	path('<int:pdf_id>/opravy_a_komentare', org_required(views.opravy_a_komentare_view), name='korektury_api_opravy_a_komentare'),
 | 
			
		||||
	path('oprava/smaz', org_required(views.oprava_smaz_view), name='korektury_api_oprava_smaz'),
 | 
			
		||||
	path('komentar/smaz', org_required(views.komentar_smaz_view), name='korektury_api_komentar_smaz'),
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			@ -1,134 +0,0 @@
 | 
			
		|||
from http import HTTPStatus
 | 
			
		||||
 | 
			
		||||
from django.http import JsonResponse, HttpResponse
 | 
			
		||||
from django.shortcuts import get_object_or_404
 | 
			
		||||
from django.utils.html import linebreaks
 | 
			
		||||
 | 
			
		||||
from rest_framework import serializers
 | 
			
		||||
 | 
			
		||||
from korektury.utils import send_email_notification_komentar
 | 
			
		||||
from korektury.models import Oprava, KorekturovanePDF, Komentar, KorekturaTag
 | 
			
		||||
from personalni.models import Organizator
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def korektury_stav_view(request, pdf_id: int, **kwargs):
 | 
			
		||||
	q = request.POST
 | 
			
		||||
	pdf = get_object_or_404(KorekturovanePDF, id=pdf_id)
 | 
			
		||||
	status = q.get('state')
 | 
			
		||||
	if status is not None:
 | 
			
		||||
		assert status in KorekturovanePDF.STATUS.values
 | 
			
		||||
		pdf.status = status
 | 
			
		||||
		pdf.save()
 | 
			
		||||
	return JsonResponse({'status': pdf.status})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def oprava_stav_view(request, **kwargs):
 | 
			
		||||
	q = request.POST
 | 
			
		||||
	op_id_str = q.get('id')
 | 
			
		||||
	assert op_id_str is not None
 | 
			
		||||
	op_id = int(op_id_str)
 | 
			
		||||
	op = get_object_or_404(Oprava, id=op_id)
 | 
			
		||||
	status = q.get('action')
 | 
			
		||||
	if status is not None:
 | 
			
		||||
		assert status in Oprava.STATUS.values
 | 
			
		||||
		op.status = status
 | 
			
		||||
		op.save()
 | 
			
		||||
	return JsonResponse({'status': op.status})
 | 
			
		||||
 | 
			
		||||
def oprava_smaz_view(request, **kwargs):
 | 
			
		||||
	q = request.POST
 | 
			
		||||
	op_id_str = q.get('oprava_id')
 | 
			
		||||
	assert op_id_str is not None
 | 
			
		||||
	op_id = int(op_id_str)
 | 
			
		||||
	oprava = get_object_or_404(Oprava, id=op_id)
 | 
			
		||||
	oprava.delete()
 | 
			
		||||
	return HttpResponse(status=HTTPStatus.NO_CONTENT)
 | 
			
		||||
 | 
			
		||||
def komentar_smaz_view(request, **kwargs):
 | 
			
		||||
	q = request.POST
 | 
			
		||||
	kom_id_str = q.get('komentar_id')
 | 
			
		||||
	assert kom_id_str is not None
 | 
			
		||||
	kom_id = int(kom_id_str)
 | 
			
		||||
	komentar = get_object_or_404(Komentar, id=kom_id)
 | 
			
		||||
	komentar.delete()
 | 
			
		||||
	return HttpResponse(status=HTTPStatus.NO_CONTENT)
 | 
			
		||||
 | 
			
		||||
class KomentarSerializer(serializers.ModelSerializer):
 | 
			
		||||
	class Meta:
 | 
			
		||||
		model = Komentar
 | 
			
		||||
		fields = '__all__'
 | 
			
		||||
 | 
			
		||||
	def to_representation(self, instance):
 | 
			
		||||
		ret = super().to_representation(instance)
 | 
			
		||||
		ret["autor"] = str(instance.autor)
 | 
			
		||||
		ret["text"] = linebreaks(ret["text"], autoescape=True) # Autora není třeba escapovat, ten se vkládá jako text.
 | 
			
		||||
		return ret
 | 
			
		||||
 | 
			
		||||
class KorekturaTagSerializer(serializers.ModelSerializer):
 | 
			
		||||
	class Meta:
 | 
			
		||||
		model = KorekturaTag
 | 
			
		||||
		fields = '__all__'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class OpravaSerializer(serializers.ModelSerializer):
 | 
			
		||||
	class Meta:
 | 
			
		||||
		model = Oprava
 | 
			
		||||
		fields = '__all__'
 | 
			
		||||
 | 
			
		||||
	def to_representation(self, instance):
 | 
			
		||||
		ret = super().to_representation(instance)
 | 
			
		||||
		ret["komentare"] = [KomentarSerializer(komentar).data for komentar in instance.komentar_set.all()]
 | 
			
		||||
		ret["tagy"] = [KorekturaTagSerializer(tag).data for tag in instance.tagy.all()]
 | 
			
		||||
		return ret
 | 
			
		||||
 | 
			
		||||
	# komentar_set = serializers.ListField(child=KomentarSerializer())
 | 
			
		||||
 | 
			
		||||
def opravy_a_komentare_view(request, pdf_id: int, **kwargs):
 | 
			
		||||
	if request.method == 'POST':
 | 
			
		||||
		q = request.POST
 | 
			
		||||
 | 
			
		||||
		x = int(q.get('x'))
 | 
			
		||||
		y = int(q.get('y'))
 | 
			
		||||
		img_id = int(q.get('img_id'))
 | 
			
		||||
		oprava_id = int(q.get('oprava_id'))
 | 
			
		||||
		komentar_id = int(q.get('komentar_id'))
 | 
			
		||||
		text = q.get('text')
 | 
			
		||||
 | 
			
		||||
		# prirazeni autora podle prihlaseni
 | 
			
		||||
		autor_user = request.user
 | 
			
		||||
		# pokud existuje ucet (user), ale neni to organizator = 403
 | 
			
		||||
		autor = Organizator.objects.filter(osoba__user=autor_user).first()
 | 
			
		||||
 | 
			
		||||
		if komentar_id != -1:
 | 
			
		||||
			komentar = get_object_or_404(Komentar, id=komentar_id)
 | 
			
		||||
			if komentar.text != text:
 | 
			
		||||
				komentar.text = text
 | 
			
		||||
				komentar.autor = autor
 | 
			
		||||
				komentar.save()
 | 
			
		||||
			oprava = komentar.oprava
 | 
			
		||||
		else:
 | 
			
		||||
			if oprava_id != -1:
 | 
			
		||||
				oprava = get_object_or_404(Oprava, id=oprava_id)
 | 
			
		||||
			else:
 | 
			
		||||
				pdf = get_object_or_404(KorekturovanePDF, id=pdf_id)
 | 
			
		||||
				oprava = Oprava.objects.create(
 | 
			
		||||
					pdf=pdf,
 | 
			
		||||
					strana=img_id,
 | 
			
		||||
					x=x,
 | 
			
		||||
					y=y,
 | 
			
		||||
				)
 | 
			
		||||
 | 
			
		||||
			Komentar.objects.create(oprava=oprava, autor=autor, text=text)
 | 
			
		||||
			send_email_notification_komentar(oprava, autor, request)
 | 
			
		||||
 | 
			
		||||
		tagy_raw = q.get('tagy')
 | 
			
		||||
		if tagy_raw is not None:
 | 
			
		||||
			oprava.tagy.clear()
 | 
			
		||||
			if tagy_raw != "":
 | 
			
		||||
				tagy = list(map(int, tagy_raw.split(",")))
 | 
			
		||||
				oprava.tagy.add(*KorekturaTag.objects.filter(id__in=tagy))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	opravy = Oprava.objects.filter(pdf=pdf_id).all()
 | 
			
		||||
	# Serializovat list je prý security vulnerability, tedy je přidán slovník pro bezpečnost
 | 
			
		||||
	return JsonResponse({"context": [OpravaSerializer(oprava).data for oprava in opravy]})
 | 
			
		||||
							
								
								
									
										13
									
								
								korektury/forms.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								korektury/forms.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
from django import forms
 | 
			
		||||
 | 
			
		||||
class OpravaForm(forms.Form):
 | 
			
		||||
	text = forms.CharField(max_length=256)
 | 
			
		||||
	autor = forms.CharField(max_length=20)
 | 
			
		||||
	x = forms.IntegerField()
 | 
			
		||||
	y = forms.IntegerField()
 | 
			
		||||
	scroll = forms.CharField(max_length=256)
 | 
			
		||||
	pdf = forms.CharField(max_length=256)
 | 
			
		||||
	img_id = forms.CharField(max_length=256)
 | 
			
		||||
	id = forms.CharField(max_length=256)
 | 
			
		||||
	action = forms.CharField(max_length=256)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
# Generated by Django 1.11.20 on 2019-04-30 21:40
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
# Generated by Django 1.11.21 on 2019-06-10 21:58
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,18 +0,0 @@
 | 
			
		|||
# Generated by Django 2.2.28 on 2022-12-05 19:14
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('korektury', '0018_korekturovanepdf_poslat_mail'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='korekturovanepdf',
 | 
			
		||||
            name='nazev',
 | 
			
		||||
            field=models.CharField(help_text='Název (např. 22.1 verze 4) korekturovaného PDF', max_length=50, verbose_name='název PDF'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
		Reference in a new issue