diff --git a/Pipfile b/Pipfile index 33955d9..08e632c 100644 --- a/Pipfile +++ b/Pipfile @@ -6,6 +6,7 @@ name = "pypi" [packages] gunicorn = "*" flask = "*" +pydantic = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 2010527..d00be3a 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "ceeddd812b1d235750e064b323a1270b3505e56f3a9357c569fd3757db6f5432" + "sha256": "e5763a4e03fd7bbaf97329e36f64ad1722c518ac89f9ecdb8329ad8bcd8431db" }, "pipfile-spec": 6, "requires": { @@ -18,19 +18,19 @@ "default": { "click": { "hashes": [ - "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a", - "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6" + "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", + "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" ], - "markers": "python_version >= '3.6'", - "version": "==8.0.1" + "markers": "python_version >= '3.7'", + "version": "==8.1.3" }, "flask": { "hashes": [ - "sha256:1c4c257b1892aec1398784c63791cbaa43062f1f7aeb555c4da961b20ee68f55", - "sha256:a6209ca15eb63fc9385f38e452704113d679511d9574d09b2cf9183ae7d20dc9" + "sha256:15972e5017df0575c3d6c090ba168b6db90259e620ac8d7ea813a396bad5b6cb", + "sha256:9013281a7402ad527f8fd56375164f3aa021ecfaff89bfe3825346c24f87e04c" ], "index": "pypi", - "version": "==2.0.1" + "version": "==2.1.3" }, "gunicorn": { "hashes": [ @@ -40,89 +40,148 @@ "index": "pypi", "version": "==20.1.0" }, + "importlib-metadata": { + "hashes": [ + "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670", + "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23" + ], + "markers": "python_version < '3.10'", + "version": "==4.12.0" + }, "itsdangerous": { "hashes": [ - "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c", - "sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0" + "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44", + "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a" ], - "markers": "python_version >= '3.6'", - "version": "==2.0.1" + "markers": "python_version >= '3.7'", + "version": "==2.1.2" }, "jinja2": { "hashes": [ - "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4", - "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4" + "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", + "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" ], - "markers": "python_version >= '3.6'", - "version": "==3.0.1" + "markers": "python_version >= '3.7'", + "version": "==3.1.2" }, "markupsafe": { "hashes": [ - "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298", - "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64", - "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b", - "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567", - "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff", - "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724", - "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74", - "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646", - "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35", - "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6", - "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6", - "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad", - "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26", - "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38", - "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac", - "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7", - "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6", - "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75", - "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f", - "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135", - "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8", - "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a", - "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a", - "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9", - "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864", - "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914", - "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18", - "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8", - "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2", - "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d", - "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b", - "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b", - "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f", - "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb", - "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833", - "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28", - "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415", - "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902", - "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d", - "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9", - "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d", - "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145", - "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066", - "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c", - "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1", - "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f", - "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53", - "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134", - "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85", - "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5", - "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94", - "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509", - "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", - "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" + "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", + "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", + "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", + "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", + "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", + "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", + "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", + "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", + "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", + "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", + "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", + "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", + "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", + "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", + "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", + "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", + "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", + "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", + "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", + "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", + "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", + "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", + "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", + "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", + "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", + "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", + "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", + "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", + "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", + "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", + "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", + "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", + "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", + "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", + "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", + "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", + "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", + "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", + "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", + "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" ], - "markers": "python_version >= '3.6'", - "version": "==2.0.1" + "markers": "python_version >= '3.7'", + "version": "==2.1.1" + }, + "pydantic": { + "hashes": [ + "sha256:02eefd7087268b711a3ff4db528e9916ac9aa18616da7bca69c1871d0b7a091f", + "sha256:059b6c1795170809103a1538255883e1983e5b831faea6558ef873d4955b4a74", + "sha256:0bf07cab5b279859c253d26a9194a8906e6f4a210063b84b433cf90a569de0c1", + "sha256:1542636a39c4892c4f4fa6270696902acb186a9aaeac6f6cf92ce6ae2e88564b", + "sha256:177071dfc0df6248fd22b43036f936cfe2508077a72af0933d0c1fa269b18537", + "sha256:18f3e912f9ad1bdec27fb06b8198a2ccc32f201e24174cec1b3424dda605a310", + "sha256:1dd8fecbad028cd89d04a46688d2fcc14423e8a196d5b0a5c65105664901f810", + "sha256:1ed987c3ff29fff7fd8c3ea3a3ea877ad310aae2ef9889a119e22d3f2db0691a", + "sha256:447d5521575f18e18240906beadc58551e97ec98142266e521c34968c76c8761", + "sha256:494f7c8537f0c02b740c229af4cb47c0d39840b829ecdcfc93d91dcbb0779892", + "sha256:4988c0f13c42bfa9ddd2fe2f569c9d54646ce84adc5de84228cfe83396f3bd58", + "sha256:4ce9ae9e91f46c344bec3b03d6ee9612802682c1551aaf627ad24045ce090761", + "sha256:5d93d4e95eacd313d2c765ebe40d49ca9dd2ed90e5b37d0d421c597af830c195", + "sha256:61b6760b08b7c395975d893e0b814a11cf011ebb24f7d869e7118f5a339a82e1", + "sha256:72ccb318bf0c9ab97fc04c10c37683d9eea952ed526707fabf9ac5ae59b701fd", + "sha256:79b485767c13788ee314669008d01f9ef3bc05db9ea3298f6a50d3ef596a154b", + "sha256:7eb57ba90929bac0b6cc2af2373893d80ac559adda6933e562dcfb375029acee", + "sha256:8bc541a405423ce0e51c19f637050acdbdf8feca34150e0d17f675e72d119580", + "sha256:969dd06110cb780da01336b281f53e2e7eb3a482831df441fb65dd30403f4608", + "sha256:985ceb5d0a86fcaa61e45781e567a59baa0da292d5ed2e490d612d0de5796918", + "sha256:9bcf8b6e011be08fb729d110f3e22e654a50f8a826b0575c7196616780683380", + "sha256:9ce157d979f742a915b75f792dbd6aa63b8eccaf46a1005ba03aa8a986bde34a", + "sha256:9f659a5ee95c8baa2436d392267988fd0f43eb774e5eb8739252e5a7e9cf07e0", + "sha256:a4a88dcd6ff8fd47c18b3a3709a89adb39a6373f4482e04c1b765045c7e282fd", + "sha256:a955260d47f03df08acf45689bd163ed9df82c0e0124beb4251b1290fa7ae728", + "sha256:a9af62e9b5b9bc67b2a195ebc2c2662fdf498a822d62f902bf27cccb52dbbf49", + "sha256:ae72f8098acb368d877b210ebe02ba12585e77bd0db78ac04a1ee9b9f5dd2166", + "sha256:b83ba3825bc91dfa989d4eed76865e71aea3a6ca1388b59fc801ee04c4d8d0d6", + "sha256:c11951b404e08b01b151222a1cb1a9f0a860a8153ce8334149ab9199cd198131", + "sha256:c320c64dd876e45254bdd350f0179da737463eea41c43bacbee9d8c9d1021f11", + "sha256:c8098a724c2784bf03e8070993f6d46aa2eeca031f8d8a048dff277703e6e193", + "sha256:d12f96b5b64bec3f43c8e82b4aab7599d0157f11c798c9f9c528a72b9e0b339a", + "sha256:e565a785233c2d03724c4dc55464559639b1ba9ecf091288dd47ad9c629433bd", + "sha256:f0f047e11febe5c3198ed346b507e1d010330d56ad615a7e0a89fae604065a0e", + "sha256:fe4670cb32ea98ffbf5a1262f14c3e102cccd92b1869df3bb09538158ba90fe6" + ], + "index": "pypi", + "version": "==1.9.1" + }, + "setuptools": { + "hashes": [ + "sha256:0d33c374d41c7863419fc8f6c10bfe25b7b498aa34164d135c622e52580c6b16", + "sha256:c04b44a57a6265fe34a4a444e965884716d34bae963119a76353434d6f18e450" + ], + "markers": "python_version >= '3.7'", + "version": "==63.2.0" + }, + "typing-extensions": { + "hashes": [ + "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02", + "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6" + ], + "markers": "python_version >= '3.7'", + "version": "==4.3.0" }, "werkzeug": { "hashes": [ - "sha256:1de1db30d010ff1af14a009224ec49ab2329ad2cde454c8a708130642d579c42", - "sha256:6c1ec500dcdba0baa27600f6a22f6333d8b662d22027ff9f6202e3367413caa8" + "sha256:1ce08e8093ed67d638d63879fd1ba3735817f7a80de3674d293f5984f25fb6e6", + "sha256:72a4b735692dd3135217911cbeaa1be5fa3f62bffb8745c5215420a03dc55255" ], - "markers": "python_version >= '3.6'", - "version": "==2.0.1" + "markers": "python_version >= '3.7'", + "version": "==2.1.2" + }, + "zipp": { + "hashes": [ + "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2", + "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009" + ], + "markers": "python_version >= '3.7'", + "version": "==3.8.1" } }, "develop": {} diff --git a/app/__init__.py b/app/__init__.py index 1198510..29dfc16 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,9 +1,9 @@ from flask import Flask, url_for, render_template, abort import os -import json from app.config import PANDOC_LINK, PANDOC_PATH, WHITELIST_PATH from app.hash_manager import hash_file_sha512 -import subprocess +from app.page_model import WikiPage +from typing import List app = Flask(__name__) @@ -13,7 +13,24 @@ def override_url_for(): return dict(url_for=dated_url_for) -#TODO: make instead of datetime hash of commit +def get_all_names(): + whitelist = WHITELIST_PATH + with open(whitelist, 'r') as f: + lines = f.read().splitlines() + return lines + + +def get_page(name: str) -> WikiPage: + if name not in get_all_names(): + raise Exception("Page doesn't exist!") + path = f'{PANDOC_PATH}/{name}' + with open(f'{path}/config.json', 'r') as f: + page = WikiPage.parse_raw(f.read()) + return page + + +def get_all_pages() -> List[WikiPage]: + return [get_page(name) for name in get_all_names()] def dated_url_for(endpoint, **values): @@ -25,53 +42,36 @@ def dated_url_for(endpoint, **values): return url_for(endpoint, **values) -def render_page(page): - path = f'{PANDOC_PATH}/{page}' - whitelist = WHITELIST_PATH - with open(whitelist, 'r') as f: - lines = f.read().splitlines() - if page not in lines: - raise Exception("Page doesn't exist!") - if not os.path.exists(f'{path}'): +def render_page(page: WikiPage): + if page.name not in get_all_names(): raise Exception("Page doesn't exist!") - in_filename = f'{path}/main.md' - out_filename = f'{path}/render.html' + in_filename = page.get_file('main.md') + out_filename = page.get_file('render.html') os.system(f'pandoc {in_filename} --to html --mathjax --output {out_filename}') print('Creating lock file') os.system(f'echo {hash_file_sha512(in_filename)} > {out_filename}.lock') -@app.route(f'/{PANDOC_LINK}/') -def get_pandoc_page(page): - path = f'{PANDOC_PATH}/{page}' - whitelist = WHITELIST_PATH - with open(whitelist, 'r') as f: - lines = f.read().splitlines() - if page not in lines: - print(f'Access to page not in list {page}') - return 'This page does not exist' - if not os.path.exists(f'{path}'): - # TODO: Add 404 handler - return 'This page does not exist' - with open(f'{path}/config.json') as f: - data = json.loads(f.read()) - if not os.path.exists(f'{path}/render.html') or not os.path.exists(f'{path}/render.html.lock'): - print(f'Rendered page or lockfile for {page} does not exist! Rendering {page}') +@app.route(f'/{PANDOC_LINK}/') +def get_pandoc_page(name: str): + page = get_page(name) + if not os.path.exists(page.get_file('render.html')) or not os.path.exists(page.get_file('render.html.lock')): + print(f'Rendered page or lockfile for {name} does not exist! Rendering {name}') render_page(page) else: - with open(f'{path}/render.html.lock', 'r') as f: + with open(page.get_file('render.html.lock'), 'r') as f: rendered_hash = f.read().strip() - current_hash = hash_file_sha512(f'{path}/main.md') + current_hash = hash_file_sha512(page.get_file('main.md')) if rendered_hash != current_hash: print(f'CURRENT: {current_hash}, RENDERED: {rendered_hash}') - print(f'Integrity test failed, rendering {page}!') + print(f'Integrity test failed, rendering {name}!') render_page(page) - template = data['template'] - with open(f'{path}/render.html', 'r') as f: + template = page.template + with open(page.get_file('render.html'), 'r') as f: inserted = f.read() - return render_template(template, markdown=inserted, config=data) + return render_template(template, markdown=inserted, config=page) @app.route('/') def index(): - return render_template('index.html') + return render_template('index.html', pages=get_all_pages(), PANDOC_LINK=PANDOC_LINK) diff --git a/app/page_model.py b/app/page_model.py new file mode 100644 index 0000000..dfba6bb --- /dev/null +++ b/app/page_model.py @@ -0,0 +1,14 @@ +from pydantic import BaseModel +from typing import List +from app.config import PANDOC_PATH + + +class WikiPage(BaseModel): + name: str + title: str + credits: List[str] + standalone: bool + template: str + + def get_file(self, filename: str) -> str: + return f'{PANDOC_PATH}/{self.name}/{filename}' diff --git a/app/static/css/pandoc.css b/app/static/css/pandoc.css index 64e53c0..f6cb6a3 100644 --- a/app/static/css/pandoc.css +++ b/app/static/css/pandoc.css @@ -40,7 +40,7 @@ a { /* BEGIN ALGORITHMICA OLD STYLE */ -body { +.pagebody { /* color: #444; */ font-family: "Times New Roman", Times, "Tinos", serif; font-size: 16px; @@ -53,7 +53,7 @@ body { padding-bottom: 25px; } -.credits { +.pagebody .credits { font-size: 14px; margin: 25px 10px -40px 15px; padding: 16px 50px 0 50px; @@ -62,26 +62,26 @@ body { color: black; } -.credits table { +.pagebody .credits table { border: none; margin-left: 46px; margin-bottom: 10px; } -.credits table td{ +.pagebody .credits table td{ border: none; padding: 0; padding-left: 1.5em; } -#header { +.pagebody #header { height: 55px; margin-top: -8px; margin-bottom: 20px; border-bottom: 1px solid #666; } -#links { +.pagebody #links { display: inline-block; text-align: right; font-size: 16px; @@ -90,27 +90,27 @@ body { margin-right: 12px; } -#links a { +.pagebody #links a { margin-left: 20px; } -#header a:hover { +.pagebody #header a:hover { color: #0645ad!important; } -#header a { +.pagebody #header a { color: #111 !important; display: inline-block; } -#logo { +.pagebody #logo { margin-top: 10px; font-size: 22px; height: 0; font-family: 'Garamond', serif; } -.contents { +.pagebody .contents { position: inline-block; float: left; position: relative; @@ -119,13 +119,13 @@ body { text-align: left; } -.contents ul { +.pagebody .contents ul { padding-left: 22px; margin-top: 10px; list-style-type: none; } -.contents li { +.pagebody .contents li { font-size: 8px; color: lightgrey; font-family: 'Open Sans', sans; @@ -135,16 +135,16 @@ body { white-space: pre-line; } -.contents li:hover { +.pagebody .contents li:hover { color: black; } -.contents li:first-letter { +.pagebody .contents li:first-letter { font-size: 13px; height: 0; } -.contents a { +.pagebody .contents a { font-family: "Times New Roman", Times, "Tinos", serif; font-size: 16px; line-height: 1em; @@ -152,16 +152,16 @@ body { width: 252px; } -.contents a:first-letter { +.pagebody .contents a:first-letter { font-size: 16px; /* the only way to fix */ } -.contents a:after { +.pagebody .contents a:after { content: "\A"; white-space: pre; } -.contents li:before { +.pagebody .contents li:before { content: '•'; display: inline-block; position: absolute; @@ -171,45 +171,45 @@ body { font-size: 18px; } -a { +.pagebody a { color: #0645ad; text-decoration: none; } -a:visited { +.pagebody a:visited { color: #0b0080; } -a:hover { +.pagebody a:hover { color: #06e; } -a:active { +.pagebody a:active { color: #faa700; } -a:focus { +.pagebody a:focus { outline: thin dotted; } -p { +.pagebody p { margin: 0.5em 0; } -img { +.pagebody img { max-width: 100%; } -.title { +.pagebody .title { display: none; } -h1 { +.pagebody h1 { text-align: center; margin-bottom: 0.8em !important; } -h1, h2, h3, h4, h5, h6 { +.pagebody h1, h2, h3, h4, h5, h6 { font-family: 'Garamond', serif; color: #111; line-height: 125%; @@ -218,54 +218,54 @@ h1, h2, h3, h4, h5, h6 { font-weight: normal; } -h2, h3 { +.pagebody h2, h3 { padding-bottom: 5px; border-bottom: 1px solid #eaecef; } -.contents h2, .contents h3 { +.pagebody .contents h2, .contents h3 { padding-bottom: 0; border-bottom: none; margin-top: 5px; } -h4, h5, h6 { +.pagebody h4, h5, h6 { font-weight: bold; } -h1 { +.pagebody h1 { font-size: 2.5em; margin-top: 0.8em; } -h2 { +.pagebody h2 { font-size: 2em; } -h3 { +.pagebody h3 { font-size: 1.5em; } -h4 { +.pagebody h4 { font-size: 1.2em; } -h5 { +.pagebody h5 { font-size: 1em; } -h6 { +.pagebody h6 { font-size: 0.9em; } -blockquote { +.pagebody blockquote { color: #666666; margin: 0; padding-left: 1em; border-left: 0.5em #EEE solid; } -hr { +.pagebody hr { display: block; width: 100%; height: 0px; @@ -275,101 +275,101 @@ hr { clear: both; } -pre, code, kbd, samp { +.pagebody pre, code, kbd, samp { color: #000; font-family: 'Inconsolata', monospace; } -pre { +.pagebody pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; } -b, strong { +.pagebody b, strong { font-weight: bold; } -dfn { +.pagebody dfn { font-style: italic; } -ins { +.pagebody ins { background: #ff9; color: #000; text-decoration: none; } -mark { +.pagebody mark { background: #ff0; color: #000; font-style: italic; font-weight: bold; } -sub, sup { +.pagebody sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } -sup { +.pagebody sup { top: -0.5em; } -sub { +.pagebody sub { bottom: -0.25em; } -ul, ol { +.pagebody ul, ol { margin: 1em 0; padding: 0 0 0 2em; } -li p:last-child { +.pagebody li p:last-child { margin-bottom: 0; } -li ul { +.pagebody li ul { padding-left: 18px; padding-top: 1px; } -ul ul, ol ol { +.pagebody ul ul, ol ol { margin: .3em 0; } -dl { +.pagebody dl { margin-bottom: 1em; } -dt { +.pagebody dt { font-weight: bold; margin-bottom: .8em; } -dd { +.pagebody dd { margin: 0 0 .8em 2em; } -dd:last-child { +.pagebody dd:last-child { margin-bottom: 0; } -img { +.pagebody img { border: 0; -ms-interpolation-mode: bicubic; vertical-align: middle; } -figure { +.pagebody figure { display: block; text-align: center; margin: 1em 0; } -img { +.pagebody img { border: none; margin: auto; display: block; @@ -377,13 +377,13 @@ img { max-height: 320px; } -figcaption { +.pagebody figcaption { font-size: 0.8em; font-style: italic; margin: 0 0 .8em; } -table { +.pagebody table { margin-bottom: 2em; border-bottom: 1px solid #ddd; border-right: 1px solid #ddd; @@ -391,21 +391,21 @@ table { border-collapse: collapse; } -table th { +.pagebody table th { padding: .2em 1em; background-color: #eee; border-top: 1px solid #ddd; border-left: 1px solid #ddd; } -table td { +.pagebody table td { padding: .2em 1em; border-top: 1px solid #ddd; border-left: 1px solid #ddd; vertical-align: top; } -.author { +.pagebody .author { display: block; width: 100%; text-align: right; @@ -417,7 +417,7 @@ table td { font-size: 0.8em; } -code:not([class]) { +.pagebody code:not([class]) { border: 1px solid #ddd !important; background-color: #f8f8f8 !important; border-radius: 3px !important; @@ -426,7 +426,7 @@ code:not([class]) { font-size: 0.85em; } -pre { +.pagebody pre { border: 1px solid #ddd !important; background-color: #f8f8f8 !important; border-radius: 3px !important; @@ -436,7 +436,7 @@ pre { } @media print { - body { + .pagebody { font-size: 12pt; width: 190mm; margin: 0; @@ -449,11 +449,11 @@ pre { display: none; } - pre, ul, ol { + .pagebody pre, ul, ol { page-break-inside: avoid; } - h1::after, h2::after, h3::after { + .pagebody h1::after, h2::after, h3::after { /* page-break-after: avoid; */ content: ""; display: block; @@ -470,7 +470,7 @@ pre { } */ - a, a:visited { + .pagebody a, a:visited { text-decoration: underline; } @@ -480,68 +480,25 @@ pre { } */ - p, h2, h3 { + .pagebody p, h2, h3 { orphans: 3; widows: 3; } } -/* -a[href^='http://sereja.me']:before { - content: url('http://sereja.me/favicon.ico'); - margin-right: 4px; -} -*/ - -a[href^='http://e-maxx.ru']:before { - content: ""; - display: inline-block; - position: relative; - top: 4px; - width: 20px; - height: 20px; - background: url('http://e-maxx.ru/favicon.ico') no-repeat; - background-size: 18px; -} - -/* -a[href^='https://algorithmica.org']:before { - content: ""; - display: inline-block; - position: relative; - top: 4px; - width: 20px; - height: 20px; - background: url('https://algorithmica.org/favicon.ico') no-repeat; - background-size: 18px; -} -*/ - -/* https://habrahabr.ru/favicon.ico */ - -a[href^='https://neerc.ifmo.ru']:before { +.pagebody a[href^='https://neerc.ifmo.ru']:before { content: url('https://neerc.ifmo.ru/favicon.ico'); margin-right: 4px; position: relative; top: 4px; } -a[href^='https://www.youtube.com']:before { - content: url('https://www.youtube.com/favicon.ico'); - margin-right: 4px; -} - -a[href^='https://codeforces.com']:before { +.pagebody a[href^='https://codeforces.com']:before { content: url('http://codeforces.com/favicon.ico'); margin-right: 4px; } -a[href^='https://www.topcoder.com/']:before { - content: url('https://s3.amazonaws.com/app.topcoder.com/favicon.ico'); - margin-right: 4px; -} - -a[href=''] { +.pagebody a[href=''] { color: black; cursor: default; } @@ -550,32 +507,29 @@ a[href=''] { /* BEGIN PANDOC EMBEDDED STYLE FOR CODE */ -code{white-space: pre-wrap;} -span.smallcaps{font-variant: small-caps;} -span.underline{text-decoration: underline;} -div.column{display: inline-block; vertical-align: top; width: 50%;} -div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} -ul.task-list{list-style: none;} -pre > code.sourceCode { white-space: pre; position: relative; } -pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } -pre > code.sourceCode > span:empty { height: 1.2em; } -.sourceCode { overflow: visible; } -code.sourceCode > span { color: inherit; text-decoration: inherit; } -div.sourceCode { margin: 1em 0; } -pre.sourceCode { margin: 0; } +.pagebody code{white-space: pre-wrap;} +.pagebody span.smallcaps{font-variant: small-caps;} +.pagebody span.underline{text-decoration: underline;} +.pagebody div.column{display: inline-block; vertical-align: top; width: 50%;} +.pagebody div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +.pagebody ul.task-list{list-style: none;} +.pagebody pre > code.sourceCode { white-space: pre; position: relative; } +.pagebody pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +.pagebody pre > code.sourceCode > span:empty { height: 1.2em; } +.pagebody .sourceCode { overflow: visible; } +.pagebody code.sourceCode > span { color: inherit; text-decoration: inherit; } +.pagebody div.sourceCode { margin: 1em 0; } +.pagebody pre.sourceCode { margin: 0; } @media screen { -div.sourceCode { overflow: auto; } +.pagebody div.sourceCode { overflow: auto; } } @media print { -pre > code.sourceCode { white-space: pre-wrap; } -pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +.pagebody pre > code.sourceCode { white-space: pre-wrap; } +.pagebody pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } } -pre.numberSource code - { counter-reset: source-line 0; } -pre.numberSource code > span - { position: relative; left: -4em; counter-increment: source-line; } -pre.numberSource code > span > a:first-child::before - { content: counter(source-line); +.pagebody pre.numberSource code { counter-reset: source-line 0; } +.pagebody pre.numberSource code > span { position: relative; left: -4em; counter-increment: source-line; } +.pagebody pre.numberSource code > span > a:first-child::before { content: counter(source-line); position: relative; left: -1em; text-align: right; vertical-align: baseline; border: none; display: inline-block; -webkit-touch-callout: none; -webkit-user-select: none; @@ -584,40 +538,39 @@ pre.numberSource code > span > a:first-child::before padding: 0 4px; width: 4em; color: #aaaaaa; } -pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; } -div.sourceCode - { } +.pagebody pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; } +.pagebody div.sourceCode { } @media screen { -pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +.pagebody pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } } -code span.al { color: #ff0000; font-weight: bold; } /* Alert */ -code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */ -code span.at { color: #7d9029; } /* Attribute */ -code span.bn { color: #40a070; } /* BaseN */ -code span.bu { } /* BuiltIn */ -code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */ -code span.ch { color: #4070a0; } /* Char */ -code span.cn { color: #880000; } /* Constant */ -code span.co { color: #60a0b0; font-style: italic; } /* Comment */ -code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */ -code span.do { color: #ba2121; font-style: italic; } /* Documentation */ -code span.dt { color: #902000; } /* DataType */ -code span.dv { color: #40a070; } /* DecVal */ -code span.er { color: #ff0000; font-weight: bold; } /* Error */ -code span.ex { } /* Extension */ -code span.fl { color: #40a070; } /* Float */ -code span.fu { color: #06287e; } /* Function */ -code span.im { } /* Import */ -code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */ -code span.kw { color: #007020; font-weight: bold; } /* Keyword */ -code span.op { color: #666666; } /* Operator */ -code span.ot { color: #007020; } /* Other */ -code span.pp { color: #bc7a00; } /* Preprocessor */ -code span.sc { color: #4070a0; } /* SpecialChar */ -code span.ss { color: #bb6688; } /* SpecialString */ -code span.st { color: #4070a0; } /* String */ -code span.va { color: #19177c; } /* Variable */ -code span.vs { color: #4070a0; } /* VerbatimString */ -code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */ +.pagebody code span.al { color: #ff0000; font-weight: bold; } /* Alert */ +.pagebody code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */ +.pagebody code span.at { color: #7d9029; } /* Attribute */ +.pagebody code span.bn { color: #40a070; } /* BaseN */ +.pagebody code span.bu { } /* BuiltIn */ +.pagebody code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */ +.pagebody code span.ch { color: #4070a0; } /* Char */ +.pagebody code span.cn { color: #880000; } /* Constant */ +.pagebody code span.co { color: #60a0b0; font-style: italic; } /* Comment */ +.pagebody code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */ +.pagebody code span.do { color: #ba2121; font-style: italic; } /* Documentation */ +.pagebody code span.dt { color: #902000; } /* DataType */ +.pagebody code span.dv { color: #40a070; } /* DecVal */ +.pagebody code span.er { color: #ff0000; font-weight: bold; } /* Error */ +.pagebody code span.ex { } /* Extension */ +.pagebody code span.fl { color: #40a070; } /* Float */ +.pagebody code span.fu { color: #06287e; } /* Function */ +.pagebody code span.im { } /* Import */ +.pagebody code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */ +.pagebody code span.kw { color: #007020; font-weight: bold; } /* Keyword */ +.pagebody code span.op { color: #666666; } /* Operator */ +.pagebody code span.ot { color: #007020; } /* Other */ +.pagebody code span.pp { color: #bc7a00; } /* Preprocessor */ +.pagebody code span.sc { color: #4070a0; } /* SpecialChar */ +.pagebody code span.ss { color: #bb6688; } /* SpecialString */ +.pagebody code span.st { color: #4070a0; } /* String */ +.pagebody code span.va { color: #19177c; } /* Variable */ +.pagebody code span.vs { color: #4070a0; } /* VerbatimString */ +.pagebody code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */ /* END PANDOC EMBEDDED STYLE FOR CODE */ diff --git a/app/templates/index.html b/app/templates/index.html index f94e87c..d58a9a2 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -1 +1,13 @@ -Wiki index page + + + + + + + Статьи: + {% for page in pages %} +
+ {{page.title}}(Авторы: {{', '.join(page.credits)}}) + {% endfor %} + +