diff options
70 files changed, 1177 insertions, 297 deletions
diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..210f85f9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,15 @@ +.venv +scripts +htmlcov +__pycache__ +.vagrant +.pytest_cache +.git +.github +.cache +Vagrantfile +.coverage +.coveragerc +.gitignore +.travis.yml +docker diff --git a/.travis.yml b/.travis.yml index 21e52051..4e2516be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,16 +9,26 @@ branches: only: - "master" +sudo: required + +services: + - docker + +env: + global: + - PIPENV_VENV_IN_PROJECT=1 + - PIPENV_IGNORE_VIRTUALENVS=1 + install: - - pip install -r requirements.txt - - pip install -r requirements-ci.txt + - pip install pipenv + - pipenv sync --dev --three script: - - flake8 + - pipenv run lint - python gunicorn_config.py - - py.test app_test.py --cov pysite --cov-report term-missing -v - - coveralls + - pipenv run test + - pipenv run coveralls after_success: - - python deploy.py + - bash scripts/deploy.sh cache: pip diff --git a/Pipfile b/Pipfile new file mode 100644 index 00000000..13811259 --- /dev/null +++ b/Pipfile @@ -0,0 +1,43 @@ +[[source]] +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +flask = "==0.12.2" +rethinkdb = "*" +requests = "*" +gevent = "*" +"gevent-websocket" = "*" +wsaccel = "*" +ujson = "*" +schema = "*" +"flask_sockets" = "*" +"Flask-Dance" = "*" +"logmatic-python" = "*" +"Flask-WTF" = "*" +docutils = "*" +pygments = "*" +gunicorn = "*" + +[dev-packages] +"flake8" = "*" +"flake8-bugbear" = "*" +"flake8-bandit" = "*" +"flake8-import-order" = "*" +"flake8-tidy-imports" = "*" +"flake8-string-format" = "*" +requests = "*" +"Flask-Testing" = "*" +pytest = "*" +pytest-cov = "*" +python-coveralls = "*" + +[requires] +python_version = "3.6" + +[scripts] +start = "gunicorn -w 12 -b 0.0.0.0:10012 -c gunicorn_config.py --log-level info -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker app:app" +lint = "python -m flake8" +test = "py.test app_test.py --cov pysite --cov-report term-missing -v" +clean = "rm -rf __pycache__ htmlcov .coverage .pytest_cache" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 00000000..fbabe5bb --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,612 @@ +{ + "_meta": { + "hash": { + "sha256": "a824288bd4a4c6498aa926af19245920da11113f087729774d53ce1fb4468469" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.6" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.python.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "certifi": { + "hashes": [ + "sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7", + "sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0" + ], + "version": "==2018.4.16" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "click": { + "hashes": [ + "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d", + "sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b" + ], + "version": "==6.7" + }, + "docutils": { + "hashes": [ + "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", + "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", + "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6" + ], + "index": "pypi", + "version": "==0.14" + }, + "flask": { + "hashes": [ + "sha256:0749df235e3ff61ac108f69ac178c9770caeaccad2509cb762ce1f65570a8856", + "sha256:49f44461237b69ecd901cc7ce66feea0319b9158743dd27a2899962ab214dac1" + ], + "index": "pypi", + "version": "==0.12.2" + }, + "flask-dance": { + "hashes": [ + "sha256:0c608d9f003a38493fdff092a2eb482c2c6b768ef878112e0d03676a6a92fa67", + "sha256:2cea678b882f94e04f82545dd0fcf751376ff58b5cd8e3af489529b11bdeb63d", + "sha256:56b50af359842e767a9b20d1ea2afea2a7268558e76c1fbadc652aa840abec7d" + ], + "index": "pypi", + "version": "==0.14.0" + }, + "flask-sockets": { + "hashes": [ + "sha256:072927da8edca0e81e024f5787e643c87d80b351b714de95d723becb30e0643b", + "sha256:350a76d55f5889f64afd2ca9b32f262680b7960965f0830365576307d30cfe1e" + ], + "index": "pypi", + "version": "==0.2.1" + }, + "flask-wtf": { + "hashes": [ + "sha256:5d14d55cfd35f613d99ee7cba0fc3fbbe63ba02f544d349158c14ca15561cc36", + "sha256:d9a9e366b32dcbb98ef17228e76be15702cd2600675668bca23f63a7947fd5ac" + ], + "index": "pypi", + "version": "==0.14.2" + }, + "gevent": { + "hashes": [ + "sha256:0901975628790e8a57fc92bb7062e5b856edea48c8de9caf36cfda14eae07329", + "sha256:1af93825db5753550fa8ff5ab2f2132e8733170b3f8d38347b34fa4a984cb624", + "sha256:2ff045a91509c35664c27a849c8cbf742a227f587b7cdbc88301e9c85dcaedff", + "sha256:33fa6759eabc9176ddbe0d29b66867a82e19a61f06eb7cfabbac35343c0ecf24", + "sha256:35790f1a3c8e431ada3471b70bb2105050009ea4beb15cbe41b86bc716a7ffa9", + "sha256:4791c8ae9c57d6f153354736e1ccab1e2baf6c8d9ae5a77a9ac90f41e2966b2d", + "sha256:4f098002126ebef7f2907188b6c8b09e5193161ce968847d9e6a8bc832b0db9a", + "sha256:552719cec4721673b8c7d2f9de666e3f7591b9b182f801ecaef1c76e638052aa", + "sha256:59e9237af027f8db85e5d78a9da2e328ae96f01d67a0d62abcecad3db7876908", + "sha256:60109741377367eef8ded9283a1bf629621b73acaf3e1e8aac9d1a0f50fa0f05", + "sha256:6892fabc9051e8c0a171d543b6536859aabeb6d169db79b2f45d64dc2a15808c", + "sha256:70558dd45c7a1f8046ba45792e489dd0f409bd8a3b7a0635ca9d3055223b3dff", + "sha256:74bce0c30bb2240e3d5d515ba8cb3eadf840c2bde7109a1979c7a26c9d0f5a6a", + "sha256:7f93b67b680f4a921f517294048d05f8f6f0ed5962b78d6685a6cf0fcd7d8202", + "sha256:81cb24e0f7bd9888596364e8d8ed0d65c2547c84884c67bb46d956faeed67396", + "sha256:833bebdc36bfeeedefc200ca9aee9b8eddd80f56b63ca1e886e18b97b1240edd", + "sha256:8a710eddb3e9e5f22bdbd458b5f211b94f59409ecd6896f15b9fee2cba266a59", + "sha256:9b492bb1a043540abb6e54fdb5537531e24962ca49c09f3b47dc4f9c37f6297c", + "sha256:a0ed8ba787b9c0c1c565c2675d71652e6c1e2d4e91f53530860d0303e867fe85", + "sha256:a16db4f56699ef07f0249b953ff949aae641e50b2bdc4710f11c0d8d9089b296", + "sha256:a66cf99f08da65c501826a19e30f5a6e7ba942fdd79baba5ce2d51eebaa13444", + "sha256:b67a10799923f9fed546ca5f8b93a2819c71a60132d7a97b4a13fbdab66b278a", + "sha256:b7e0e6400c2f3ce78a9ae1cdd55b53166feedd003d60c033863881227129a4d3", + "sha256:c35b29de49211014ec66d056fd4f9ba7a04795e2a654697f72879c0cf365d6d4", + "sha256:c9dd6534c46ed782e2d7236767cd07115cb29ce8670c2fc0794f264de9024fe0", + "sha256:de13a8e378103af84a8bf6015ad1d2761d46f29b8393e8dd6d9bb7cb51bbb713", + "sha256:deafd70d04ab62428d4e291e8e2c0fb22f38690e6a9f23a67ee6c304087634da", + "sha256:df52e06a2754c2d905aad75a7dc06a732c804d9edbc87f06f47c8f483ba98bca", + "sha256:fce894a64db3911897cdad6c37fbb23dfb18b7bf8b9cb8c00a8ea0a7253651c9" + ], + "index": "pypi", + "version": "==1.2.2" + }, + "gevent-websocket": { + "hashes": [ + "sha256:17b67d91282f8f4c973eba0551183fc84f56f1c90c8f6b6b30256f31f66f5242", + "sha256:7eaef32968290c9121f7c35b973e2cc302ffb076d018c9068d2f5ca8b2d85fb0" + ], + "index": "pypi", + "version": "==0.10.1" + }, + "greenlet": { + "hashes": [ + "sha256:09ef2636ea35782364c830f07127d6c7a70542b178268714a9a9ba16318e7e8b", + "sha256:0fef83d43bf87a5196c91e73cb9772f945a4caaff91242766c5916d1dd1381e4", + "sha256:1b7df09c6598f5cfb40f843ade14ed1eb40596e75cd79b6fa2efc750ba01bb01", + "sha256:1fff21a2da5f9e03ddc5bd99131a6b8edf3d7f9d6bc29ba21784323d17806ed7", + "sha256:42118bf608e0288e35304b449a2d87e2ba77d1e373e8aa221ccdea073de026fa", + "sha256:50643fd6d54fd919f9a0a577c5f7b71f5d21f0959ab48767bd4bb73ae0839500", + "sha256:58798b5d30054bb4f6cf0f712f08e6092df23a718b69000786634a265e8911a9", + "sha256:5b49b3049697aeae17ef7bf21267e69972d9e04917658b4e788986ea5cc518e8", + "sha256:75c413551a436b462d5929255b6dc9c0c3c2b25cbeaee5271a56c7fda8ca49c0", + "sha256:769b740aeebd584cd59232be84fdcaf6270b8adc356596cdea5b2152c82caaac", + "sha256:ad2383d39f13534f3ca5c48fe1fc0975676846dc39c2cece78c0f1f9891418e0", + "sha256:b417bb7ff680d43e7bd7a13e2e08956fa6acb11fd432f74c97b7664f8bdb6ec1", + "sha256:b6ef0cabaf5a6ecb5ac122e689d25ba12433a90c7b067b12e5f28bdb7fb78254", + "sha256:c2de19c88bdb0366c976cc125dca1002ec1b346989d59524178adfd395e62421", + "sha256:c7b04a6dc74087b1598de8d713198de4718fa30ec6cbb84959b26426c198e041", + "sha256:f8f2a0ae8de0b49c7b5b2daca4f150fdd9c1173e854df2cce3b04123244f9f45", + "sha256:fcfadaf4bf68a27e5dc2f42cbb2f4b4ceea9f05d1d0b8f7787e640bed2801634" + ], + "version": "==0.4.13" + }, + "gunicorn": { + "hashes": [ + "sha256:eb8d8924b117a609fae9f8cd85df0cad3535dd613fdbcdbba3ee88d5459f1d4f", + "sha256:f5ca088d029fe3cea166c59bb43b7ccc9c850fe25af3da61350fe712c5cc5aa2" + ], + "index": "pypi", + "version": "==19.8.0" + }, + "idna": { + "hashes": [ + "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f", + "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4" + ], + "version": "==2.6" + }, + "itsdangerous": { + "hashes": [ + "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519" + ], + "version": "==0.24" + }, + "jinja2": { + "hashes": [ + "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", + "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" + ], + "version": "==2.10" + }, + "lazy": { + "hashes": [ + "sha256:c80a77bf7106ba7b27378759900cfefef38271088dc63b014bcfe610c8e68e3d" + ], + "version": "==1.3" + }, + "logmatic-python": { + "hashes": [ + "sha256:0c15ac9f5faa6a60059b28910db642c3dc7722948c3cc940923f8c9039604342" + ], + "index": "pypi", + "version": "==0.1.7" + }, + "markupsafe": { + "hashes": [ + "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" + ], + "version": "==1.0" + }, + "oauthlib": { + "hashes": [ + "sha256:09d438bcac8f004ae348e721e9d8a7792a9e23cd574634e973173344046287f5", + "sha256:909665297635fa11fe9914c146d875f2ed41c8c2d78e21a529dd71c0ba756508" + ], + "version": "==2.0.7" + }, + "pygments": { + "hashes": [ + "sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d", + "sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc" + ], + "index": "pypi", + "version": "==2.2.0" + }, + "python-json-logger": { + "hashes": [ + "sha256:30999d1d742ecf6645991a2ce9273188505e98b713ad63be06aabff47dd1b3c4", + "sha256:8205cfe7061715de5cd1b37e3565d5b97d0ac13b30ff3ee612554abb6093d640" + ], + "version": "==0.1.8" + }, + "requests": { + "hashes": [ + "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", + "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e" + ], + "index": "pypi", + "version": "==2.18.4" + }, + "requests-oauthlib": { + "hashes": [ + "sha256:50a8ae2ce8273e384895972b56193c7409601a66d4975774c60c2aed869639ca", + "sha256:883ac416757eada6d3d07054ec7092ac21c7f35cb1d2cf82faf205637081f468" + ], + "version": "==0.8.0" + }, + "rethinkdb": { + "hashes": [ + "sha256:b5354ecd896b59065693e4139c067f401c9f57970268e9b93f83d869709d1c17" + ], + "index": "pypi", + "version": "==2.3.0.post6" + }, + "schema": { + "hashes": [ + "sha256:410f44cb025384959d20deef00b4e1595397fa30959947a4f0d92e9c84616f35", + "sha256:a058daf5d926e4ece9f13c4c2366a836143ca7913ef053c5023c569e00175b2a" + ], + "index": "pypi", + "version": "==0.6.7" + }, + "six": { + "hashes": [ + "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", + "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" + ], + "version": "==1.11.0" + }, + "ujson": { + "hashes": [ + "sha256:f66073e5506e91d204ab0c614a148d5aa938bdbf104751be66f8ad7a222f5f86" + ], + "index": "pypi", + "version": "==1.35" + }, + "urllib3": { + "hashes": [ + "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b", + "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f" + ], + "version": "==1.22" + }, + "urlobject": { + "hashes": [ + "sha256:47b2e20e6ab9c8366b2f4a3566b6ff4053025dad311c4bb71279bbcfa2430caa" + ], + "version": "==2.4.3" + }, + "werkzeug": { + "hashes": [ + "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c", + "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b" + ], + "version": "==0.14.1" + }, + "wsaccel": { + "hashes": [ + "sha256:425706acf0724d2f6bfa391ec37b4ef121d3432c956029de3cea4e101c218e0c" + ], + "index": "pypi", + "version": "==0.6.2" + }, + "wtforms": { + "hashes": [ + "sha256:ffdf10bd1fa565b8233380cb77a304cd36fd55c73023e91d4b803c96bc11d46f" + ], + "version": "==2.1" + } + }, + "develop": { + "attrs": { + "hashes": [ + "sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9", + "sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450" + ], + "version": "==17.4.0" + }, + "bandit": { + "hashes": [ + "sha256:cb977045497f83ec3a02616973ab845c829cdab8144ce2e757fe031104a9abd4", + "sha256:de4cc19d6ba32d6f542c6a1ddadb4404571347d83ef1ed1e7afb7d0b38e0c25b" + ], + "version": "==1.4.0" + }, + "certifi": { + "hashes": [ + "sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7", + "sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0" + ], + "version": "==2018.4.16" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "click": { + "hashes": [ + "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d", + "sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b" + ], + "version": "==6.7" + }, + "coverage": { + "hashes": [ + "sha256:00d464797a236f654337181af72b4baea3d35d056ca480e45e9163bb5df496b8", + "sha256:0a90afa6f5ea08889da9066dca3ce2ef85d47587e3f66ca06a4fa8d3a0053acc", + "sha256:0ba6c4345e3c197f6a3ba924d155c402ad28c080ac0d79529493eb17582fbc41", + "sha256:2be3748f45d2eb0259c3c93abccc15c10725ef715bf0817a4c0a1a1dad2abc6a", + "sha256:50727512afe77e044c7d7f2fd4cd0fe62b06527f965b335a810d956748e0514d", + "sha256:6c2fd127cd4e2decb0ab41fe3ac2948b87ad2ea0470e24b4be5f7e7fdfef8df3", + "sha256:6ed521ed3800d8f8911642b9b3c3891780a929db5e572c88c4713c1032530f82", + "sha256:76a73a48a308fb87a4417d630b0345d36166f489ef17ea5aa8e4596fb50a2296", + "sha256:7eaa0a33423476ed63317ee0a53cc07c0e36b5a390e3e95b95152e7eb6b3a6f6", + "sha256:845d0f8a1765074b3256f07ddbce2969e5a5316dfd0eb3289137010d7677326a", + "sha256:85b1275b6d7a61ccc8024a4e9a4c9e896394776edce1a5d075ec116f91925462", + "sha256:8e60e720cad3ee6b0a32f475ae4040552c5623870a9ca0d3d4263faa89a8d96b", + "sha256:93c50475f189cd226e9688b9897a0cd3c4c5d9c90b1733fa8f6445cfc0182c51", + "sha256:94c1e66610807a7917d967ed6415b9d5fde7487ab2a07bb5e054567865ef6ef0", + "sha256:964f86394cb4d0fd2bb40ffcddca321acf4323b48d1aa5a93db8b743c8a00f79", + "sha256:99043494b28d6460035dd9410269cdb437ee460edc7f96f07ab45c57ba95e651", + "sha256:addf63b5e39d573c459c3930b25176146395c1dc1afce4710067bb5e6dc4ea58", + "sha256:af2f59ce312523c384a7826821cae0b95f320fee1751387abba4f00eed737166", + "sha256:af6ed80340e5e1b89fa794f730ce7597651fbda3312e500002688b679c184ef9", + "sha256:beb96d32ce8cfa47ec6433d95a33e4afaa97c19ac1b4a47ea40a424fedfee7c2", + "sha256:c00bac0f6b35b82ace069a6a0d88e8fd4cd18d964fc5e47329cd02b212397fbe", + "sha256:d079e36baceea9707fd50b268305654151011274494a33c608c075808920eda8", + "sha256:d3188345f1c7161d701fd2ea9150f9bb6e2df890f3ddd6c0aea1f525e21d1544", + "sha256:e65c78bde155a734f0d624647c4d6e0f47fb4875355a0b95c37d537788737f4f", + "sha256:e813cba9ff0e3d37ad31dc127fac85d23f9a26d0461ef8042ac4539b2045e781", + "sha256:e96c13a40df389ce8cbb5ec108e5fb834989d1bedff5d8846e5aa3d270a5f3b6", + "sha256:ee2338539157cfc35fb1d6757dd799126804df39393c4a6c5fe88b402c8c0ab4" + ], + "version": "==4.0.3" + }, + "flake8": { + "hashes": [ + "sha256:7253265f7abd8b313e3892944044a365e3f4ac3fcdcfb4298f55ee9ddf188ba0", + "sha256:c7841163e2b576d435799169b78703ad6ac1bbb0f199994fc05f700b2a90ea37" + ], + "index": "pypi", + "version": "==3.5.0" + }, + "flake8-bandit": { + "hashes": [ + "sha256:a66c7b42af9530d5e988851ccee02958a51a85d46f1f4609ecc3546948f809b8", + "sha256:f7c3421fd9aebc63689c0693511e16dcad678fd4a0ce624b78ca91ae713eacdc" + ], + "index": "pypi", + "version": "==1.0.2" + }, + "flake8-bugbear": { + "hashes": [ + "sha256:541746f0f3b2f1a8d7278e1d2d218df298996b60b02677708560db7c7e620e3b", + "sha256:5f14a99d458e29cb92be9079c970030e0dd398b2decb179d76d39a5266ea1578" + ], + "index": "pypi", + "version": "==18.2.0" + }, + "flake8-import-order": { + "hashes": [ + "sha256:40d2a39ed91e080f3285f4c16256b252d7c31070e7f11b7854415bb9f924ea81", + "sha256:68d430781a9ef15c85a0121500cf8462f1a4bc7672acb2a32bfdbcab044ae0b7" + ], + "index": "pypi", + "version": "==0.17.1" + }, + "flake8-polyfill": { + "hashes": [ + "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9", + "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda" + ], + "version": "==1.0.2" + }, + "flake8-string-format": { + "hashes": [ + "sha256:68ea72a1a5b75e7018cae44d14f32473c798cf73d75cbaed86c6a9a907b770b2", + "sha256:774d56103d9242ed968897455ef49b7d6de272000cfa83de5814273a868832f1" + ], + "index": "pypi", + "version": "==0.2.3" + }, + "flake8-tidy-imports": { + "hashes": [ + "sha256:5fc28c82bba16abb4f1154dc59a90487f5491fbdb27e658cbee241e8fddc1b91", + "sha256:c05c9f7dadb5748a04b6fa1c47cb6ae5a8170f03cfb1dca8b37aec58c1ee6d15" + ], + "index": "pypi", + "version": "==1.1.0" + }, + "flask": { + "hashes": [ + "sha256:0749df235e3ff61ac108f69ac178c9770caeaccad2509cb762ce1f65570a8856", + "sha256:49f44461237b69ecd901cc7ce66feea0319b9158743dd27a2899962ab214dac1" + ], + "index": "pypi", + "version": "==0.12.2" + }, + "flask-testing": { + "hashes": [ + "sha256:dc076623d7d850653a018cb64f500948334c8aeb6b10a5a842bf1bcfb98122bc" + ], + "index": "pypi", + "version": "==0.7.1" + }, + "gitdb2": { + "hashes": [ + "sha256:b60e29d4533e5e25bb50b7678bbc187c8f6bcff1344b4f293b2ba55c85795f09", + "sha256:cf9a4b68e8c4da8d42e48728c944ff7af2d8c9db303ac1ab32eac37aa4194b0e" + ], + "version": "==2.0.3" + }, + "gitpython": { + "hashes": [ + "sha256:05069e26177c650b3cb945dd543a7ef7ca449f8db5b73038b465105673c1ef61", + "sha256:c47cc31af6e88979c57a33962cbc30a7c25508d74a1b3a19ec5aa7ed64b03129" + ], + "version": "==2.1.9" + }, + "idna": { + "hashes": [ + "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f", + "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4" + ], + "version": "==2.6" + }, + "itsdangerous": { + "hashes": [ + "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519" + ], + "version": "==0.24" + }, + "jinja2": { + "hashes": [ + "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", + "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" + ], + "version": "==2.10" + }, + "markupsafe": { + "hashes": [ + "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" + ], + "version": "==1.0" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "more-itertools": { + "hashes": [ + "sha256:0dd8f72eeab0d2c3bd489025bb2f6a1b8342f9b198f6fc37b52d15cfa4531fea", + "sha256:11a625025954c20145b37ff6309cd54e39ca94f72f6bb9576d1195db6fa2442e", + "sha256:c9ce7eccdcb901a2c75d326ea134e0886abfbea5f93e91cc95de9507c0816c44" + ], + "version": "==4.1.0" + }, + "pbr": { + "hashes": [ + "sha256:4e8a0ed6a8705a26768f4c3da26026013b157821fe5f95881599556ea9d91c19", + "sha256:dae4aaa78eafcad10ce2581fc34d694faa616727837fd8e55c1a00951ad6744f" + ], + "version": "==4.0.2" + }, + "pluggy": { + "hashes": [ + "sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff", + "sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c", + "sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5" + ], + "version": "==0.6.0" + }, + "py": { + "hashes": [ + "sha256:29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881", + "sha256:983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a" + ], + "version": "==1.5.3" + }, + "pycodestyle": { + "hashes": [ + "sha256:1ec08a51c901dfe44921576ed6e4c1f5b7ecbad403f871397feedb5eb8e4fa14", + "sha256:5ff2fbcbab997895ba9ead77e1b38b3ebc2e5c3b8a6194ef918666e4c790a00e", + "sha256:682256a5b318149ca0d2a9185d365d8864a768a28db66a84a2ea946bcc426766", + "sha256:6c4245ade1edfad79c3446fadfc96b0de2759662dc29d07d80a6f27ad1ca6ba9" + ], + "version": "==2.3.1" + }, + "pyflakes": { + "hashes": [ + "sha256:08bd6a50edf8cffa9fa09a463063c425ecaaf10d1eb0335a7e8b1401aef89e6f", + "sha256:8d616a382f243dbf19b54743f280b80198be0bca3a5396f1d2e1fca6223e8805" + ], + "version": "==1.6.0" + }, + "pytest": { + "hashes": [ + "sha256:54713b26c97538db6ff0703a12b19aeaeb60b5e599de542e7fca0ec83b9038e8", + "sha256:829230122facf05a5f81a6d4dfe6454a04978ea3746853b2b84567ecf8e5c526" + ], + "index": "pypi", + "version": "==3.5.1" + }, + "pytest-cov": { + "hashes": [ + "sha256:03aa752cf11db41d281ea1d807d954c4eda35cfa1b21d6971966cc041bbf6e2d", + "sha256:890fe5565400902b0c78b5357004aab1c814115894f4f21370e2433256a3eeec" + ], + "index": "pypi", + "version": "==2.5.1" + }, + "python-coveralls": { + "hashes": [ + "sha256:1748272081e0fc21e2c20c12e5bd18cb13272db1b130758df0d473da0cb31087", + "sha256:736dda01f64beda240e1500d5f264b969495b05fcb325c7c0eb7ebbfd1210b70" + ], + "index": "pypi", + "version": "==2.9.1" + }, + "pyyaml": { + "hashes": [ + "sha256:0c507b7f74b3d2dd4d1322ec8a94794927305ab4cebbe89cc47fe5e81541e6e8", + "sha256:16b20e970597e051997d90dc2cddc713a2876c47e3d92d59ee198700c5427736", + "sha256:3262c96a1ca437e7e4763e2843746588a965426550f3797a79fca9c6199c431f", + "sha256:326420cbb492172dec84b0f65c80942de6cedb5233c413dd824483989c000608", + "sha256:4474f8ea030b5127225b8894d626bb66c01cda098d47a2b0d3429b6700af9fd8", + "sha256:592766c6303207a20efc445587778322d7f73b161bd994f227adaa341ba212ab", + "sha256:5ac82e411044fb129bae5cfbeb3ba626acb2af31a8d17d175004b70862a741a7", + "sha256:5f84523c076ad14ff5e6c037fe1c89a7f73a3e04cf0377cb4d017014976433f3", + "sha256:827dc04b8fa7d07c44de11fabbc888e627fa8293b695e0f99cb544fdfa1bf0d1", + "sha256:b4c423ab23291d3945ac61346feeb9a0dc4184999ede5e7c43e1ffb975130ae6", + "sha256:bc6bced57f826ca7cb5125a10b23fd0f2fff3b7c4701d64c439a300ce665fff8", + "sha256:c01b880ec30b5a6e6aa67b09a2fe3fb30473008c85cd6a67359a1b15ed6d83a4", + "sha256:ca233c64c6e40eaa6c66ef97058cdc80e8d0157a443655baa1b2966e812807ca", + "sha256:e863072cdf4c72eebf179342c94e6989c67185842d9997960b3e69290b2fa269" + ], + "version": "==3.12" + }, + "requests": { + "hashes": [ + "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", + "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e" + ], + "index": "pypi", + "version": "==2.18.4" + }, + "six": { + "hashes": [ + "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", + "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" + ], + "version": "==1.11.0" + }, + "smmap2": { + "hashes": [ + "sha256:b78ee0f1f5772d69ff50b1cbdb01b8c6647a8354f02f23b488cf4b2cfc923956", + "sha256:c7530db63f15f09f8251094b22091298e82bf6c699a6b8344aaaef3f2e1276c3" + ], + "version": "==2.0.3" + }, + "stevedore": { + "hashes": [ + "sha256:e3d96b2c4e882ec0c1ff95eaebf7b575a779fd0ccb4c741b9832bed410d58b3d", + "sha256:f1c7518e7b160336040fee272174f1f7b29a46febb3632502a8f2055f973d60b" + ], + "version": "==1.28.0" + }, + "urllib3": { + "hashes": [ + "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b", + "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f" + ], + "version": "==1.22" + }, + "werkzeug": { + "hashes": [ + "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c", + "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b" + ], + "version": "==0.14.1" + } + } +} diff --git a/Vagrantfile b/Vagrantfile index bb8ff03f..89351891 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -18,7 +18,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| type: "virtualbox", mount_options: ["dmode=775,fmode=775"] end - config.vm.provision "shell", path: "Vagrant_bootstrap.sh" + config.vm.provision "shell", path: "scripts/vagrant_bootstrap.sh" end end @@ -1,5 +1,3 @@ -# coding=utf-8 - from os import environ from pysite.route_manager import RouteManager diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 00000000..cb2b1b5f --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,21 @@ +FROM pythondiscord/site-base:latest + +ENV PIPENV_VENV_IN_PROJECT=1 +ENV PIPENV_IGNORE_VIRTUALENVS=1 +ENV PIPENV_NOSPIN=1 +ENV PIPENV_HIDE_EMOJIS=1 + +RUN pip install pipenv + +RUN mkdir -p /site +COPY . /site +WORKDIR /site +ENV PYTHONPATH=/site + +RUN pipenv clean +RUN pipenv sync + +EXPOSE 10012 + +ENTRYPOINT ["/sbin/tini", "--"] +CMD ["pipenv", "run", "start"] diff --git a/docker/Dockerfile.base b/docker/Dockerfile.base new file mode 100644 index 00000000..87c6fd73 --- /dev/null +++ b/docker/Dockerfile.base @@ -0,0 +1,20 @@ +FROM python:3.6-alpine + +RUN apk add --update tini +RUN apk add --update git +RUN apk add --update build-base + +ENV PIPENV_VENV_IN_PROJECT=1 +ENV PIPENV_IGNORE_VIRTUALENVS=1 +ENV PIPENV_NOSPIN=1 +ENV PIPENV_HIDE_EMOJIS=1 + +RUN pip install pipenv + +RUN mkdir -p /site +COPY Pipfile /site +COPY Pipfile.lock /site +WORKDIR /site +ENV PYTHONPATH=/site + +RUN pipenv sync diff --git a/gunicorn_config.py b/gunicorn_config.py index 5b9f9055..0e374fdd 100644 --- a/gunicorn_config.py +++ b/gunicorn_config.py @@ -1,4 +1,3 @@ -# coding=utf-8 def when_ready(server=None): """ server hook that only runs when the gunicorn master process loads """ diff --git a/pysite/__init__.py b/pysite/__init__.py index 93362f6a..98e66630 100644 --- a/pysite/__init__.py +++ b/pysite/__init__.py @@ -1,4 +1,3 @@ -# coding=utf-8 import logging import sys from logging import Logger, StreamHandler diff --git a/pysite/base_route.py b/pysite/base_route.py index 1d30669d..e9df7afe 100644 --- a/pysite/base_route.py +++ b/pysite/base_route.py @@ -1,4 +1,3 @@ -# coding=utf-8 from collections import Iterable from typing import Any diff --git a/pysite/constants.py b/pysite/constants.py index 4eff3606..225550fe 100644 --- a/pysite/constants.py +++ b/pysite/constants.py @@ -1,5 +1,3 @@ -# coding=utf-8 - from enum import Enum, IntEnum from os import environ diff --git a/pysite/decorators.py b/pysite/decorators.py index 0b02ebde..0c31fe6e 100644 --- a/pysite/decorators.py +++ b/pysite/decorators.py @@ -1,4 +1,3 @@ -# coding=utf-8 import os from functools import wraps from json import JSONDecodeError diff --git a/pysite/logs.py b/pysite/logs.py index 301cb98b..e789b1ea 100644 --- a/pysite/logs.py +++ b/pysite/logs.py @@ -1,4 +1,3 @@ -# coding=utf-8 from logging.handlers import SocketHandler diff --git a/pysite/mixins.py b/pysite/mixins.py index 5108a9a1..a3edc4f2 100644 --- a/pysite/mixins.py +++ b/pysite/mixins.py @@ -1,4 +1,3 @@ -# coding=utf-8 from weakref import ref from flask import Blueprint diff --git a/pysite/route_manager.py b/pysite/route_manager.py index e6d2c92c..429a553e 100644 --- a/pysite/route_manager.py +++ b/pysite/route_manager.py @@ -1,4 +1,3 @@ -# coding=utf-8 import importlib import inspect import logging diff --git a/pysite/rst/__init__.py b/pysite/rst/__init__.py index 74f19285..97a77f40 100644 --- a/pysite/rst/__init__.py +++ b/pysite/rst/__init__.py @@ -1,4 +1,3 @@ -# coding=utf-8 import re from docutils.core import publish_parts @@ -68,12 +67,23 @@ def render(rst: str): if depth == 1: # Top-level header, so just store it in the current header current_header["id"] = match.group(1) - current_header["title"] = match.group(2) + + title = match.group(2) + + if title.startswith("<i"): # We've found an icon, which needs to have a space after it + title = title.replace("</i> ", "</i> ") + + current_header["title"] = title else: # Second-level (or deeper) header, should be stored in a list of sub-headers under the current sub_headers = current_header.get("sub_headers", []) + title = match.group(2) + + if title.startswith("<i"): # We've found an icon, which needs to have a space after it + title = title.replace("</i> ", "</i> ") + sub_headers.append({ "id": match.group(1), - "title": match.group(2) + "title": title }) current_header["sub_headers"] = sub_headers diff --git a/pysite/rst/directives/__init__.py b/pysite/rst/directives/__init__.py index 9bad5790..e69de29b 100644 --- a/pysite/rst/directives/__init__.py +++ b/pysite/rst/directives/__init__.py @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/pysite/rst/roles.py b/pysite/rst/roles.py index acba31e4..abade243 100644 --- a/pysite/rst/roles.py +++ b/pysite/rst/roles.py @@ -1,4 +1,3 @@ -# coding=utf-8 from docutils import nodes from docutils.parsers.rst.roles import set_classes from docutils.parsers.rst.states import Inliner @@ -41,7 +40,7 @@ def icon_role(_role: str, rawtext: str, text: str, lineno: int, inliner: Inliner return [prb], [msg] - html = f"""<i class="uk-icon {weight} fa-{parts[1]}"></i>""" + html = f"""<i class="uk-icon fa-fw {weight} fa-{parts[1]}"></i>""" node = nodes.raw(html, html, format="html", **options) return [node], [] diff --git a/pysite/views/api/__init__.py b/pysite/views/api/__init__.py index 9bad5790..e69de29b 100644 --- a/pysite/views/api/__init__.py +++ b/pysite/views/api/__init__.py @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/pysite/views/api/bot/hiphopify.py b/pysite/views/api/bot/hiphopify.py index 7ebf47e1..bb85d5b5 100644 --- a/pysite/views/api/bot/hiphopify.py +++ b/pysite/views/api/bot/hiphopify.py @@ -1,4 +1,3 @@ -# coding=utf-8 import datetime import logging diff --git a/pysite/views/api/bot/tags.py b/pysite/views/api/bot/tags.py index ee1a1bee..c901347e 100644 --- a/pysite/views/api/bot/tags.py +++ b/pysite/views/api/bot/tags.py @@ -1,5 +1,3 @@ -# coding=utf-8 - from flask import jsonify from schema import Optional, Schema diff --git a/pysite/views/api/bot/user.py b/pysite/views/api/bot/user.py index 3d8d7271..1394e699 100644 --- a/pysite/views/api/bot/user.py +++ b/pysite/views/api/bot/user.py @@ -1,4 +1,3 @@ -# coding=utf-8 import logging from flask import jsonify, request diff --git a/pysite/views/api/error_view.py b/pysite/views/api/error_view.py index 30e133f9..89b4d6ad 100644 --- a/pysite/views/api/error_view.py +++ b/pysite/views/api/error_view.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import jsonify from werkzeug.exceptions import HTTPException diff --git a/pysite/views/api/healthcheck.py b/pysite/views/api/healthcheck.py index d57f61fa..c873d674 100644 --- a/pysite/views/api/healthcheck.py +++ b/pysite/views/api/healthcheck.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import jsonify from pysite.base_route import APIView diff --git a/pysite/views/api/index.py b/pysite/views/api/index.py index e2bd8fe0..5111162c 100644 --- a/pysite/views/api/index.py +++ b/pysite/views/api/index.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pysite.base_route import APIView from pysite.constants import ErrorCodes diff --git a/pysite/views/error_handlers/http_4xx.py b/pysite/views/error_handlers/http_4xx.py index 2d6c54c6..69c0bdda 100644 --- a/pysite/views/error_handlers/http_4xx.py +++ b/pysite/views/error_handlers/http_4xx.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import request from werkzeug.exceptions import HTTPException diff --git a/pysite/views/error_handlers/http_5xx.py b/pysite/views/error_handlers/http_5xx.py index 46c65e38..5a4fbdc2 100644 --- a/pysite/views/error_handlers/http_5xx.py +++ b/pysite/views/error_handlers/http_5xx.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import request from werkzeug.exceptions import HTTPException, InternalServerError diff --git a/pysite/views/main/__init__.py b/pysite/views/main/__init__.py index 9bad5790..e69de29b 100644 --- a/pysite/views/main/__init__.py +++ b/pysite/views/main/__init__.py @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/pysite/views/main/abort.py b/pysite/views/main/abort.py index d9e3282f..ecfe8f91 100644 --- a/pysite/views/main/abort.py +++ b/pysite/views/main/abort.py @@ -1,4 +1,3 @@ -# coding=utf-8 from werkzeug.exceptions import InternalServerError from pysite.base_route import RouteView diff --git a/pysite/views/main/about/__init__.py b/pysite/views/main/about/__init__.py index 9bad5790..e69de29b 100644 --- a/pysite/views/main/about/__init__.py +++ b/pysite/views/main/about/__init__.py @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/pysite/views/main/about/index.py b/pysite/views/main/about/index.py index a3fecc31..9f211702 100644 --- a/pysite/views/main/about/index.py +++ b/pysite/views/main/about/index.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pysite.base_route import RouteView diff --git a/pysite/views/main/about/partners.py b/pysite/views/main/about/partners.py index b5e7f587..4fe321a5 100644 --- a/pysite/views/main/about/partners.py +++ b/pysite/views/main/about/partners.py @@ -1,4 +1,3 @@ -# coding=utf-8 import json from logging import getLogger diff --git a/pysite/views/main/about/rules.py b/pysite/views/main/about/rules.py index 805936a8..22e79afa 100644 --- a/pysite/views/main/about/rules.py +++ b/pysite/views/main/about/rules.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pysite.base_route import RouteView diff --git a/pysite/views/main/error.py b/pysite/views/main/error.py index 2e432102..07286eb4 100644 --- a/pysite/views/main/error.py +++ b/pysite/views/main/error.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import abort from pysite.base_route import RouteView diff --git a/pysite/views/main/index.py b/pysite/views/main/index.py index 210eb057..ef5ed700 100644 --- a/pysite/views/main/index.py +++ b/pysite/views/main/index.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pysite.base_route import RouteView diff --git a/pysite/views/main/info/__init__.py b/pysite/views/main/info/__init__.py index 9bad5790..e69de29b 100644 --- a/pysite/views/main/info/__init__.py +++ b/pysite/views/main/info/__init__.py @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/pysite/views/main/info/help.py b/pysite/views/main/info/help.py index 868b969f..a47362fc 100644 --- a/pysite/views/main/info/help.py +++ b/pysite/views/main/info/help.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pysite.base_route import RouteView diff --git a/pysite/views/main/info/index.py b/pysite/views/main/info/index.py index 3f36e50f..f9fab682 100644 --- a/pysite/views/main/info/index.py +++ b/pysite/views/main/info/index.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pysite.base_route import RouteView diff --git a/pysite/views/main/info/jams.py b/pysite/views/main/info/jams.py index 19e4cb9c..9158091f 100644 --- a/pysite/views/main/info/jams.py +++ b/pysite/views/main/info/jams.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pysite.base_route import RouteView diff --git a/pysite/views/main/info/resources.py b/pysite/views/main/info/resources.py index 2642e1ec..541b9ba1 100644 --- a/pysite/views/main/info/resources.py +++ b/pysite/views/main/info/resources.py @@ -1,4 +1,3 @@ -# coding=utf-8 import json from logging import getLogger diff --git a/pysite/views/main/redirects/github.py b/pysite/views/main/redirects/github.py index d2ceaf49..f861a91c 100644 --- a/pysite/views/main/redirects/github.py +++ b/pysite/views/main/redirects/github.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import redirect from pysite.base_route import RouteView diff --git a/pysite/views/main/redirects/invite.py b/pysite/views/main/redirects/invite.py index 5f31d7db..1895d36a 100644 --- a/pysite/views/main/redirects/invite.py +++ b/pysite/views/main/redirects/invite.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import redirect from pysite.base_route import RouteView diff --git a/pysite/views/main/redirects/stats.py b/pysite/views/main/redirects/stats.py index 7766f9ed..935f8539 100644 --- a/pysite/views/main/redirects/stats.py +++ b/pysite/views/main/redirects/stats.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import redirect from pysite.base_route import RouteView diff --git a/pysite/views/main/ws_test.py b/pysite/views/main/ws_test.py index c53515c5..a0b6215f 100644 --- a/pysite/views/main/ws_test.py +++ b/pysite/views/main/ws_test.py @@ -1,4 +1,3 @@ -# coding=utf-8 import os from pysite.base_route import RouteView diff --git a/pysite/views/main/ws_test_rst.py b/pysite/views/main/ws_test_rst.py index 9c2ee805..e80acc55 100644 --- a/pysite/views/main/ws_test_rst.py +++ b/pysite/views/main/ws_test_rst.py @@ -1,4 +1,3 @@ -# coding=utf-8 import os from pysite.base_route import RouteView diff --git a/pysite/views/staff/index.py b/pysite/views/staff/index.py index 7569ba32..11447f87 100644 --- a/pysite/views/staff/index.py +++ b/pysite/views/staff/index.py @@ -1,4 +1,3 @@ -# coding=utf-8 from pprint import pformat from flask import current_app diff --git a/pysite/views/tests/index.py b/pysite/views/tests/index.py index 3071bf0e..b96590c0 100644 --- a/pysite/views/tests/index.py +++ b/pysite/views/tests/index.py @@ -1,5 +1,3 @@ -# coding=utf-8 - from flask import jsonify from schema import Schema diff --git a/pysite/views/wiki/edit.py b/pysite/views/wiki/edit.py index 9cff9da0..2cd4181c 100644 --- a/pysite/views/wiki/edit.py +++ b/pysite/views/wiki/edit.py @@ -1,4 +1,3 @@ -# coding=utf-8 import datetime import difflib diff --git a/pysite/views/wiki/history/compare.py b/pysite/views/wiki/history/compare.py index d42a6b36..6296f734 100644 --- a/pysite/views/wiki/history/compare.py +++ b/pysite/views/wiki/history/compare.py @@ -1,4 +1,3 @@ -# coding=utf-8 import difflib from pygments import highlight diff --git a/pysite/views/wiki/history/show.py b/pysite/views/wiki/history/show.py index e18b017e..00a1dc27 100644 --- a/pysite/views/wiki/history/show.py +++ b/pysite/views/wiki/history/show.py @@ -1,4 +1,3 @@ -# coding=utf-8 import datetime from werkzeug.exceptions import NotFound @@ -9,7 +8,7 @@ from pysite.mixins import DBMixin class RevisionsListView(RouteView, DBMixin): - path = "/history/show/<string:page>" + path = "/history/show/<path:page>" name = "history.show" table_name = "wiki_revisions" diff --git a/pysite/views/wiki/index.py b/pysite/views/wiki/index.py index 778a808c..8290eac9 100644 --- a/pysite/views/wiki/index.py +++ b/pysite/views/wiki/index.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import url_for from werkzeug.utils import redirect diff --git a/pysite/views/wiki/page.py b/pysite/views/wiki/page.py index 500d5c04..26edfcc4 100644 --- a/pysite/views/wiki/page.py +++ b/pysite/views/wiki/page.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import redirect, url_for from werkzeug.exceptions import NotFound diff --git a/pysite/views/wiki/render.py b/pysite/views/wiki/render.py index 9d3e8cc3..b08f54dd 100644 --- a/pysite/views/wiki/render.py +++ b/pysite/views/wiki/render.py @@ -1,4 +1,3 @@ -# coding=utf-8 import re from docutils.utils import SystemMessage diff --git a/pysite/views/wiki/source.py b/pysite/views/wiki/source.py index 80f362df..83674447 100644 --- a/pysite/views/wiki/source.py +++ b/pysite/views/wiki/source.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import redirect, url_for from pygments import highlight from pygments.formatters.html import HtmlFormatter diff --git a/pysite/views/ws/echo.py b/pysite/views/ws/echo.py index 7e6b036f..b6f11168 100644 --- a/pysite/views/ws/echo.py +++ b/pysite/views/ws/echo.py @@ -1,4 +1,3 @@ -# coding=utf-8 import logging from geventwebsocket.websocket import WebSocket diff --git a/pysite/views/ws/rst.py b/pysite/views/ws/rst.py index 24bdb3ca..f2b2db24 100644 --- a/pysite/views/ws/rst.py +++ b/pysite/views/ws/rst.py @@ -1,4 +1,3 @@ -# coding=utf-8 import logging from geventwebsocket.websocket import WebSocket diff --git a/pysite/websockets.py b/pysite/websockets.py index 1e7960f7..19f9bf83 100644 --- a/pysite/websockets.py +++ b/pysite/websockets.py @@ -1,4 +1,3 @@ -# coding=utf-8 from flask import Blueprint from geventwebsocket.websocket import WebSocket diff --git a/requirements-ci.txt b/requirements-ci.txt deleted file mode 100644 index f10a0b78..00000000 --- a/requirements-ci.txt +++ /dev/null @@ -1,11 +0,0 @@ -flake8 -flake8-bugbear -flake8-bandit -flake8-import-order -flake8-tidy-imports -flake8-string-format -requests -Flask-Testing -pytest -pytest-cov -python-coveralls diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index bb66b59d..00000000 --- a/requirements.txt +++ /dev/null @@ -1,14 +0,0 @@ -flask==0.12.2 -rethinkdb -requests -gevent -gevent-websocket -wsaccel -ujson -schema -flask_sockets -Flask-Dance -logmatic-python -flask-wtf -docutils -pygments diff --git a/deploy.py b/scripts/deploy.py index 20d8edd5..20d8edd5 100644 --- a/deploy.py +++ b/scripts/deploy.py diff --git a/scripts/deploy.sh b/scripts/deploy.sh new file mode 100644 index 00000000..96723aa6 --- /dev/null +++ b/scripts/deploy.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Build and deploy on master branch +if [[ $TRAVIS_BRANCH == 'master' && $TRAVIS_PULL_REQUEST == 'false' ]]; then + echo "Connecting to docker hub" + echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + + echo "Building image" + docker build -t pythondiscord/site:latest -f docker/Dockerfile . + + echo "Pushing image" + docker push pythondiscord/site:latest + + echo "Deploying container" + pipenv run python scripts/deploy.py +else + echo "Skipping deploy" +fi diff --git a/Vagrant_bootstrap.sh b/scripts/vagrant_bootstrap.sh index 307107d4..307107d4 100644 --- a/Vagrant_bootstrap.sh +++ b/scripts/vagrant_bootstrap.sh diff --git a/static/resources.json b/static/resources.json index 210021d1..9bca279b 100644 --- a/static/resources.json +++ b/static/resources.json @@ -1,192 +1,376 @@ { - "Learning Resources": { - "description": "Tutorials and references for those that are just getting started with python", - "resources": { - "Automate the Boring Stuff with Python": { - "description": "One of the best books out there for Python beginners. You can buy a copy, but there's also a free online version.", - "urls": [ - { - "title": "Website", - "url": "https://automatetheboringstuff.com/", - "icon": "regular/link" - }, { - "title": "Amazon", - "url": "http://www.amazon.com/gp/product/1593275994/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1593275994&linkCode=as2&tag=playwithpyth-20&linkId=HDM7V3T6RHC5VVN4", - "icon": "branding/amazon" - } - ], - "payment": "optional", - "payment_description": "A free version is available online, with the option to buy a physical copy" - }, - "Code Combat": { - "description": "Learn Python while gaming - an open-source project with thousands of contributors, which teaches you Python through a deep, top-down RPG.", - "urls": [ - { - "title": "Website", - "url": "https://codecombat.com/", - "icon": "regular/link" - }, - { - "title": "GitHub", - "url": "https://github.com/codecombat/codecombat", - "icon": "branding/github" - } - ], - "payment": "optional", - "payment_description": "A wealth of free content is available, but you can also pay for more" - }, - "Get Started with Flask Web Development": { - "description": "A fully featured mega-tutorial for learning how to create web applications with the Flask framework.", - "urls": [ - { - "title": "Website", - "url": "https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world", - "icon": "regular/link" - } - ], - "payment": "free", - "payment_description": null - }, - "Getting Started for Non-Programmers": { - "description": "The list of resources for non-programmers from Python's official beginners' guide", - "urls": [ - { - "title": "Python Wiki", - "url": "https://wiki.python.org/moin/BeginnersGuide/NonProgrammers", - "icon": "regular/link" - } - ], - "payment": "free", - "payment_description": null - }, - "Getting Started for Programmers": { - "description": "The list of resources for programmers from Python's official beginners' guide", - "urls": [ - { - "title": "Python Wiki", - "url": "https://wiki.python.org/moin/BeginnersGuide/Programmers", - "icon": "regular/link" - } - ], - "payment": "free", - "payment_description": null - }, - "A Simple Guide to Git": { - "description": "A simple, no-nonsense guide to the basics of using Git.", - "urls": [ - { - "title": "Website", - "url": "http://rogerdudler.github.io/git-guide/", - "icon": "regular/link" - } - ], - "payment": "free", - "payment_description": null - }, - "Python Cheat Sheet": { - "description": "A Python 3 cheat sheet with useful information and tips, as well as common pitfalls for beginners. This is a PDF.", - "urls": [ - { - "title": "Website", - "url": "https://perso.limsi.fr/pointal/_media/python:cours:mementopython3-english.pdf", - "icon": "regular/link" - } - ], - "payment": "free", - "payment_description": null - }, - "Python Tutorials by Corey Schafer on YouTube": { - "description": "An in-depth look at the Python programming language, from one of YouTube's most popular Python tutors.", - "urls": [ - { - "title": "YouTube", - "url": "https://www.youtube.com/playlist?list=PL-osiE80TeTt2d9bfVyTiXJA-UTHn6WwU", - "icon": "branding/youtube" - } - ], - "payment": "free", - "payment_description": null - } + "Tutorials": { + "description": "Tutorials and references for those that are just getting started with python", + "resources": { + "A Simple Guide to Git": { + "description": "A simple, no-nonsense guide to the basics of using Git.", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "http://rogerdudler.github.io/git-guide/" + } + ] + }, + "Get Started with Flask Web Development": { + "description": "A fully featured mega-tutorial for learning how to create web applications with the Flask framework.", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world" + } + ] + }, + "Getting Started with Python": { + "description": "The list of resources for programmers and non-programmers from Python's official beginners' guide", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "regular/link", + "title": "Beginners Guide for Non-Programmers", + "url": "https://wiki.python.org/moin/BeginnersGuide/NonProgrammers" + }, + { + "icon": "regular/link", + "title": "Beginners Guide for Programmers", + "url": "https://wiki.python.org/moin/BeginnersGuide/Programmers" + } + ] + }, + "Python Cheat Sheet": { + "description": "A Python 3 cheat sheet with useful information and tips, as well as common pitfalls for beginners. This is a PDF.", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://perso.limsi.fr/pointal/_media/python:cours:mementopython3-english.pdf" + } + ] + } + } + }, + "Books": { + "description": "The best books for learning Python or Python Frameworks", + "resources": { + "A Byte of Python": { + "description": "A free book on programming using the Python language. It serves as a tutorial or guide to the Python language for a beginner audience. If all you know about computers is how to save text files, then this is the book for you.", + "payment": "optional", + "payment_description": "A free e-book is available online, a paper version can be bought from lulu.com.", + "urls": [ + { + "icon": "regular/link", + "title": "E-book", + "url": "https://python.swaroopch.com/" + }, + { + "icon": "regular/book", + "title": "Buy the book", + "url": "http://www.lulu.com/shop/swaroop-c-h/a-byte-of-python/paperback/product-21142968.html" + }, + { + "icon": "regular/tablet-alt", + "title": "Kindle edition", + "url": "https://www.amazon.com/Byte-Python-Swaroop-C-H-ebook/dp/B00FJ7S2JU/ref=sr_1_1?ie=UTF8&qid=1524816076&sr=8-1&keywords=a+byte+of+python" + } + ] + }, + "Automate the Boring Stuff with Python": { + "description": "One of the best books out there for Python beginners. This book will teach you the basics of Python, while also teaching invaluable automation tools and techniques for solving common problems. You'll learn how to go about scraping the web, manipulating files and automating keyboard and mouse input. Ideal for an office worker who wants to make himself more useful.", + "payment": "optional", + "payment_description": "A free e-book is available on the website, but you can buy it on Amazon if you want to support the author.", + "urls": [ + { + "icon": "regular/link", + "title": "E-book", + "url": "https://automatetheboringstuff.com/" + }, + { + "icon": "branding/amazon", + "title": "Amazon", + "url": "http://www.amazon.com/gp/product/1593275994/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1593275994&linkCode=as2&tag=playwithpyth-20&linkId=HDM7V3T6RHC5VVN4" + } + ] + }, + "Effective Python": { + "description": "A book that gives 59 best practices for writing excellent Python. Great for intermediates.", + "payment": "paid", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://effectivepython.com/" + }, + { + "icon": "branding/amazon", + "title": "Amazon", + "url": "https://www.amazon.com/Effective-Python-Specific-Software-Development/dp/0134034287" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/bslatkin/effectivepython" + } + ] + }, + "Flask Web Development": { + "description": "A comprehensive Flask walkthrough that has you building a complete social blogging application from scratch.", + "payment": "paid", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "http://shop.oreilly.com/product/0636920031116.do" + }, + { + "icon": "branding/amazon", + "title": "Amazon", + "url": "https://www.amazon.com/Flask-Web-Development-Developing-Applications/dp/1449372627" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/miguelgrinberg/flasky" + } + ] + }, + "Fluent Python": { + "description": "A veritable tome of intermediate and advanced Python information. A must-read for any Python professional.", + "payment": "paid", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://www.safaribooksonline.com/library/view/fluent-python/9781491946237/" + }, + { + "icon": "branding/amazon", + "title": "Amazon", + "url": "https://www.amazon.com/Fluent-Python-Concise-Effective-Programming/dp/1491946008" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/fluentpython" + } + ] + }, + "Python Cookbook": { + "description": "Complete with 'recipes' for various Python topics, including moving from Python 2 to Python 3.3", + "payment": "paid", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "http://shop.oreilly.com/product/0636920027072.do" + }, + { + "icon": "branding/amazon", + "title": "Amazon", + "url": "https://www.amazon.com/Python-Cookbook-Third-David-Beazley/dp/1449340377" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/dabeaz/python-cookbook" + } + ] + }, + "Two Scoops of Django": { + "description": "This book is chock-full of material that will help you with your Django projects.", + "payment": "paid", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://twoscoopspress.com/products/two-scoops-of-django-1-11" + }, + { + "icon": "branding/amazon", + "title": "Amazon", + "url": "https://www.amazon.com/Two-Scoops-Django-Best-Practices/dp/0981467342" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/twoscoops/two-scoops-of-django-2.0-code-examples" + } + ] + } + } + }, + "Courses": { + "description": "Online courses that relate to Python.", + "resources": { + "Python Tutorials by Corey Schafer on YouTube": { + "description": "An in-depth look at the Python programming language, from one of YouTube's most popular Python tutors.", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "branding/youtube", + "title": "YouTube", + "url": "https://www.youtube.com/playlist?list=PL-osiE80TeTt2d9bfVyTiXJA-UTHn6WwU" + } + ] + }, + "Code Combat": { + "description": "Learn Python while gaming - an open-source project with thousands of contributors, which teaches you Python through a deep, top-down RPG.", + "payment": "optional", + "payment_description": "A wealth of free content is available, but you can also pay for more", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://codecombat.com/" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/codecombat/codecombat" + } + ] + }, + "MIT: Introduction to Computer Science and Programming Using Python": { + "description": "This MITx offering teaches computer science with Python. It covers computational thinking, algorithms, data structures and the Python programming language itself.", + "payment": "optional", + "payment_description": "You can pay to enroll for a graded certificate, or choose to take the full course for free.", + "urls": [ + { + "icon": "regular/graduation-cap", + "title": "edX Course", + "url": "https://www.edx.org/course/introduction-computer-science-mitx-6-00-1x-11" + } + ] + }, + "University of Michigan: Programming for Everybody": { + "description": "A 5-part specialization course that teaches Python from scratch. The course has no pre-requisites and avoids all but the simplest mathematics.", + "payment": "optional", + "payment_description": "You can pay to enroll for a graded certificate and a capstone project, or choose to audit for free.", + "urls": [ + { + "icon": "regular/graduation-cap", + "title": "Python for Everyone Specialization", + "url": "https://www.coursera.org/learn/python" + } + ] + }, + "University of Toronto: Learn to Program": { + "description": "A 2-part course that teaches Python. Primarily intended for high school students and first-year university students who want to learn programming.", + "payment": "optional", + "payment_description": "You can pay to enroll for a graded certificate, or choose to audit for free.", + "urls": [ + { + "icon": "regular/graduation-cap", + "title": "Part 1: The Fundamentals", + "url": "https://www.coursera.org/learn/learn-to-program" + }, + { + "icon": "regular/graduation-cap", + "title": "Part 2: Crafting Quality Code", + "url": "https://www.coursera.org/learn/program-code" + } + ] + }, + "Automate the Boring Stuff with Python": { + "description": "The interactive course version of Al Sweigart's excellent book for beginners, taught by the author himself. This link has a discounted version of the course which will always cost 10 dollars. Thanks, Al!", + "payment": "paid", + "payment_description": "You can pay to enroll for a graded certificate, or choose to take the full course for free.", + "urls": [ + { + "icon": "regular/graduation-cap", + "title": "Udemy Course", + "url": "https://www.udemy.com/automate/?couponCode=FOR_LIKE_10_BUCKS" + } + ] + } + } + }, + "Editors": { + "description": "Lightweight code editors supporting Python", + "resources": { + "Atom": { + "description": "A free Electron-based editor, a \"hackable text editor for the 21st century\", maintained by the GitHub team.", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://atom.io/" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/atom/atom" + } + ] + }, + "Visual Studio Code": { + "description": "A fully-featured editor based on Electron, extendable with plugins.", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://code.visualstudio.com/" + } + ] + }, + "Sublime Text": { + "description": "A powerful Python-backed editor with great community support and a wealth of extensions.", + "payment": "optional", + "payment_description": "Nagware; will ask you to buy the full version after every X saves", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://www.sublimetext.com/" + } + ] + } + } + }, + "IDEs": { + "description": "Fully-integrated development environments for serious Python work", + "resources": { + "Spyder": { + "description": "The Scientific PYthon Development EnviRonment. Simpler and lighter than PyCharm, but still packs a punch.", + "payment": "free", + "payment_description": null, + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://pythonhosted.org/spyder/" + }, + { + "icon": "branding/github", + "title": "GitHub", + "url": "https://github.com/spyder-ide/spyder" + } + ] + }, + "PyCharm": { + "description": "The very best Python IDE, with a wealth of advanced features and convenience functions.", + "payment": "optional", + "payment_description": "There's a free Community Edition and a paid-for Professional Edition with more features available", + "urls": [ + { + "icon": "regular/link", + "title": "Website", + "url": "https://www.jetbrains.com/pycharm/" + } + ] + } + } } - }, - "Editors": { - "description": "Lightweight code editors supporting Python", - "resources": { - "Atom": { - "description": "A free Electron-based editor, a \"hackable text editor for the 21st century\", maintained by the GitHub team.", - "urls": [ - { - "title": "Website", - "url": "https://atom.io/", - "icon": "regular/link" - }, - { - "title": "GitHub", - "url": "https://github.com/atom/atom", - "icon": "branding/github" - } - ], - "payment": "free", - "payment_description": null - }, - "Sublime Text": { - "description": "A powerful Python-backed editor with great community support and a wealth of extensions.", - "urls": [ - { - "title": "Website", - "url": "https://www.sublimetext.com/", - "icon": "regular/link" - } - ], - "payment": "optional", - "payment_description": "Nagware; will ask you to buy the full version after every X saves" - }, - "Visual Studio Code": { - "description": "A fully-featured editor based on Electron, extendable with plugins.", - "urls": [ - { - "title": "Website", - "url": "https://code.visualstudio.com/", - "icon": "regular/link" - } - ], - "payment": "free", - "payment_description": null - } - } - }, - "IDEs": { - "description": "Fully-integrated development environments for serious Python work", - "resources": { - "PyCharm": { - "description": "The very best Python IDE, with a wealth of advanced features and convenience functions.", - "urls": [ - { - "title": "Website", - "url": "https://www.jetbrains.com/pycharm/", - "icon": "regular/link" - } - ], - "payment": "optional", - "payment_description": "There's a free Community Edition and a paid-for Professional Edition with more features available" - }, - "Spyder": { - "description": "The Scientific PYthon Development EnviRonment. Simpler and lighter than PyCharm, but still packs a punch.", - "urls": [ - { - "title": "Website", - "url": "https://pythonhosted.org/spyder/", - "icon": "regular/link" - }, - { - "title": "GitHub", - "url": "https://github.com/spyder-ide/spyder", - "icon": "branding/github" - } - ], - "payment": "free", - "payment_description": null - } - } - } -} +}
\ No newline at end of file diff --git a/static/style.css b/static/style.css index fabc8957..fd182b03 100644 --- a/static/style.css +++ b/static/style.css @@ -138,3 +138,16 @@ div#partner-cards div.uk-card-default { img.navbar-logo { max-width: 110%; } + +#wiki-nav .uk-nav-divider { + min-width: 7rem; +} + +/* Resource page styling */ +div.payment-icon img { + height: 2em; +} + +div.payment-icon { + margin-right: 1em; +} diff --git a/templates/main/info/resources.html b/templates/main/info/resources.html index c947d4ed..ae416d33 100644 --- a/templates/main/info/resources.html +++ b/templates/main/info/resources.html @@ -28,15 +28,22 @@ a resource or not. You can also hover them for more information on the payment (or tap them on mobile). </p> - <p class="uk-text-center"> - <img src="{{ static_file("images/payment_icons/green.svg") }}" style="height: 2rem;" uk-tooltip="Free" /> - Free - <img src="{{ static_file("images/payment_icons/yellow.svg") }}" style="height: 2rem;" uk-tooltip="Payment Optional" /> - Payment Optional - <img src="{{ static_file("images/payment_icons/red.svg") }}" style="height: 2rem;" uk-tooltip="Paid" /> - Paid - </p> + <div class="uk-text-center uk-flex uk-flex-center"> + <div class="payment-icon"> + <img src="{{ static_file("images/payment_icons/green.svg") }}" uk-tooltip="Free" /> + <span>Free</span> + </div> + <div class="payment-icon"> + <img src="{{ static_file("images/payment_icons/yellow.svg") }}" uk-tooltip="Payment Optional" /> + <span>Payment optional</span> + </div> + + <div class="payment-icon"> + <img src="{{ static_file("images/payment_icons/red.svg") }}" uk-tooltip="Paid" /> + <span>Paid</span> + </div> + </div> {% if categories is none %} <div class="uk-alert-danger" uk-alert> <p> diff --git a/templates/wiki/base.html b/templates/wiki/base.html index 87686a83..c6f8deca 100644 --- a/templates/wiki/base.html +++ b/templates/wiki/base.html @@ -32,22 +32,26 @@ {% include "main/navigation.html" %} <div class="uk-flex uk-flex-row uk-flex-1"> <div class="uk-card uk-card-body uk-flex-left uk-flex uk-card-primary"> - <ul class="uk-nav-default uk-nav-parent-icon" uk-nav> + <ul class="uk-nav-default uk-nav-parent-icon" uk-nav id="wiki-nav"> {% if data is defined %} {% if "headers" in data and data.headers %} <li class="uk-nav-header">Contents</li> {% for header in data.headers %} {% if "sub_headers" in header %} <li class="uk-parent"> - <a href="{{ header.id }}">{{ header.title }}</a> + <a href="{{ header.id }}"> + {{ header.title | safe }} + </a> <ul class="uk-nav-sub"> {% for sub in header.sub_headers %} - <li><a href="{{ sub.id }}"><i class="uk-icon fas fa-diamond fa-fw" style="font-size: 0.5rem; vertical-align: 1px"></i> {{ sub.title }}</a></li> + <li><a href="{{ sub.id }}"> + {{ sub.title | safe }} + </a></li> {% endfor %} </ul> </li> {% else %} - <li><a href="{{ header.id }}">{{ header.title }}</a></li> + <li><a href="{{ header.id }}">{{ header.title | safe }}</a></li> {% endif %} {% endfor %} <li class="uk-nav-divider"></li> @@ -62,6 +66,9 @@ <li><a href="{{ url_for("wiki.page", page="contributing") }}"> <i class="uk-icon fas fa-fw fa-code-branch"></i> Contributing </a></li> + <li><a href="{{ url_for("wiki.page", page="minecraft") }}"> + <i class="uk-icon fas fa-fw fa-cube"></i> Minecraft + </a></li> {# <li class="uk-active"><a href="#">active</a></li>#} {# <li class="uk-parent">#} {# <a href="#">Contributing</a>#} diff --git a/templates/wiki/page_in_use.html b/templates/wiki/page_in_use.html index 4110ee17..1707845c 100644 --- a/templates/wiki/page_in_use.html +++ b/templates/wiki/page_in_use.html @@ -5,7 +5,6 @@ {% block content %} <div class="uk-container uk-container-small"> <div uk-alert class="uk-alert-warning"> - <a class="uk-alert-close" uk-close></a> <h3>The page you requested is currently being edited</h3> <p>Please try again in a little bit when the lock has expired.</p> </div> diff --git a/templates/wiki/revision_list.html b/templates/wiki/revision_list.html index 6eb5b6a8..a1936c32 100644 --- a/templates/wiki/revision_list.html +++ b/templates/wiki/revision_list.html @@ -30,7 +30,7 @@ <a href="#" id="compare-submit" class="uk-button uk-button-primary">Compare selections</a> </div> <script> - let revisions = {{ revisions | tojson }} + let revisions = {{ revisions | tojson }}; </script> <script src="{{ static_file("js/revision_diff.js") }}"></script> {% endblock %} @@ -2,5 +2,5 @@ max-line-length=120 application_import_names=pysite ignore=P102,B311,W503,E226,S311 -exclude=__pycache__, venv, app_test.py -import-order-style=pycharm
\ No newline at end of file +exclude=__pycache__, venv, app_test.py, .venv +import-order-style=pycharm |