From c54ea796afd9f29e9d53e3ffa92225586a401e85 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Mon, 13 Jan 2025 15:58:15 +0100 Subject: [PATCH 01/34] Create initial python project structure --- scripts/nc-cal-sync/.gitignore | 2 + scripts/nc-cal-sync/Pipfile | 13 ++ scripts/nc-cal-sync/Pipfile.lock | 373 +++++++++++++++++++++++++++++++ 3 files changed, 388 insertions(+) create mode 100644 scripts/nc-cal-sync/.gitignore create mode 100644 scripts/nc-cal-sync/Pipfile create mode 100644 scripts/nc-cal-sync/Pipfile.lock diff --git a/scripts/nc-cal-sync/.gitignore b/scripts/nc-cal-sync/.gitignore new file mode 100644 index 0000000..1c43c45 --- /dev/null +++ b/scripts/nc-cal-sync/.gitignore @@ -0,0 +1,2 @@ +/venv/ +__pycache__/ diff --git a/scripts/nc-cal-sync/Pipfile b/scripts/nc-cal-sync/Pipfile new file mode 100644 index 0000000..bd98874 --- /dev/null +++ b/scripts/nc-cal-sync/Pipfile @@ -0,0 +1,13 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +caldav = "*" +requests = "*" + +[dev-packages] + +[requires] +python_version = "3.12" diff --git a/scripts/nc-cal-sync/Pipfile.lock b/scripts/nc-cal-sync/Pipfile.lock new file mode 100644 index 0000000..4ac6957 --- /dev/null +++ b/scripts/nc-cal-sync/Pipfile.lock @@ -0,0 +1,373 @@ +{ + "_meta": { + "hash": { + "sha256": "e9cf623aa412fde5f5d9e5f5895fa1a99e1d24e25af6c551fb15ad671d0d0000" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.12" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "caldav": { + "hashes": [ + "sha256:4317131127d8793f740cff2fd256f369321fa49ad750f83d6f31780f7c16c67b", + "sha256:e75e84824092e33a9e03ac693de3d01133a3e044fd50a1c542c7f78d1aff0cb2" + ], + "index": "pypi", + "version": "==1.4.0" + }, + "certifi": { + "hashes": [ + "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", + "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db" + ], + "markers": "python_version >= '3.6'", + "version": "==2024.12.14" + }, + "charset-normalizer": { + "hashes": [ + "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537", + "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa", + "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a", + "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294", + "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b", + "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", + "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", + "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", + "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4", + "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", + "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2", + "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", + "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", + "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", + "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", + "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", + "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", + "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496", + "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", + "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", + "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e", + "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a", + "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4", + "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca", + "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78", + "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", + "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5", + "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", + "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", + "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", + "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765", + "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6", + "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", + "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", + "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", + "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd", + "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c", + "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", + "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", + "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", + "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770", + "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824", + "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f", + "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf", + "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487", + "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d", + "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd", + "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", + "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534", + "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", + "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", + "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", + "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd", + "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", + "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9", + "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", + "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", + "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d", + "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", + "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", + "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", + "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7", + "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", + "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", + "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8", + "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41", + "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", + "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", + "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", + "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", + "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", + "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", + "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", + "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", + "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", + "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", + "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", + "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e", + "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6", + "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", + "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", + "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e", + "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", + "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", + "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c", + "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", + "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", + "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089", + "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", + "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e", + "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", + "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616" + ], + "markers": "python_version >= '3.7'", + "version": "==3.4.1" + }, + "click": { + "hashes": [ + "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", + "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a" + ], + "markers": "python_version >= '3.7'", + "version": "==8.1.8" + }, + "icalendar": { + "hashes": [ + "sha256:43c2db8632959d634f4e48f6e6131e706bf2cdddad488cf0b72fda079b796bad", + "sha256:46c09b774a6e6948495dafcb166dc15135c8259d0ae25491f154cbc822714b69" + ], + "markers": "python_version >= '3.8'", + "version": "==6.1.0" + }, + "idna": { + "hashes": [ + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" + ], + "markers": "python_version >= '3.6'", + "version": "==3.10" + }, + "lxml": { + "hashes": [ + "sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e", + "sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229", + "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3", + "sha256:07da23d7ee08577760f0a71d67a861019103e4812c87e2fab26b039054594cc5", + "sha256:094cb601ba9f55296774c2d57ad68730daa0b13dc260e1f941b4d13678239e70", + "sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15", + "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002", + "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd", + "sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22", + "sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf", + "sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22", + "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832", + "sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727", + "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e", + "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30", + "sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f", + "sha256:1afe0a8c353746e610bd9031a630a95bcfb1a720684c3f2b36c4710a0a96528f", + "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51", + "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4", + "sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de", + "sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875", + "sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42", + "sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e", + "sha256:23e0553b8055600b3bf4a00b255ec5c92e1e4aebf8c2c09334f8368e8bd174d6", + "sha256:25f1b69d41656b05885aa185f5fdf822cb01a586d1b32739633679699f220391", + "sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc", + "sha256:2bc9fd5ca4729af796f9f59cd8ff160fe06a474da40aca03fcc79655ddee1a8b", + "sha256:2c226a06ecb8cdef28845ae976da407917542c5e6e75dcac7cc33eb04aaeb237", + "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4", + "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86", + "sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f", + "sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a", + "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8", + "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f", + "sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903", + "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03", + "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e", + "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99", + "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7", + "sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab", + "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d", + "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22", + "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492", + "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b", + "sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3", + "sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be", + "sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469", + "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f", + "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a", + "sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c", + "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a", + "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4", + "sha256:56b9861a71575f5795bde89256e7467ece3d339c9b43141dbdd54544566b3b94", + "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442", + "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b", + "sha256:5c54afdcbb0182d06836cc3d1be921e540be3ebdf8b8a51ee3ef987537455f84", + "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c", + "sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9", + "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1", + "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be", + "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367", + "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e", + "sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21", + "sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa", + "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16", + "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d", + "sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe", + "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83", + "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba", + "sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040", + "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763", + "sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8", + "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff", + "sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2", + "sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a", + "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b", + "sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce", + "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c", + "sha256:7d3d1ca42870cdb6d0d29939630dbe48fa511c203724820fc0fd507b2fb46577", + "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8", + "sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71", + "sha256:81b4e48da4c69313192d8c8d4311e5d818b8be1afe68ee20f6385d0e96fc9512", + "sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540", + "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f", + "sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2", + "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a", + "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce", + "sha256:8f0de2d390af441fe8b2c12626d103540b5d850d585b18fcada58d972b74a74e", + "sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2", + "sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27", + "sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1", + "sha256:9ada35dd21dc6c039259596b358caab6b13f4db4d4a7f8665764d616daf9cc1d", + "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1", + "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330", + "sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920", + "sha256:9fb81d2824dff4f2e297a276297e9031f46d2682cafc484f49de182aa5e5df99", + "sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff", + "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18", + "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff", + "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c", + "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179", + "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080", + "sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19", + "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d", + "sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70", + "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32", + "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a", + "sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2", + "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79", + "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3", + "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5", + "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f", + "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d", + "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3", + "sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b", + "sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753", + "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9", + "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957", + "sha256:cb83f8a875b3d9b458cada4f880fa498646874ba4011dc974e071a0a84a1b033", + "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb", + "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656", + "sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab", + "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b", + "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d", + "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd", + "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859", + "sha256:ea2e2f6f801696ad7de8aec061044d6c8c0dd4037608c7cab38a9a4d316bfb11", + "sha256:eafa2c8658f4e560b098fe9fc54539f86528651f61849b22111a9b107d18910c", + "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a", + "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005", + "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654", + "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80", + "sha256:f2901429da1e645ce548bf9171784c0f74f0718c3f6150ce166be39e4dd66c3e", + "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec", + "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7", + "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965", + "sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945", + "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8" + ], + "markers": "python_version >= '3.6'", + "version": "==5.3.0" + }, + "python-dateutil": { + "hashes": [ + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==2.9.0.post0" + }, + "pytz": { + "hashes": [ + "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", + "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725" + ], + "version": "==2024.2" + }, + "recurring-ical-events": { + "hashes": [ + "sha256:7ea75a560bf0526f7a8294dd93e324cc5379d09d520c48d0ccb4958e591dc2ff", + "sha256:a91c2de4350dc5da99ba3bad27232ea63f3ad2e2f22e9466718d770cb9a59317" + ], + "version": "==3.4.0" + }, + "requests": { + "hashes": [ + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.32.3" + }, + "six": { + "hashes": [ + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==1.17.0" + }, + "tzdata": { + "hashes": [ + "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", + "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd" + ], + "markers": "python_version >= '2'", + "version": "==2024.2" + }, + "urllib3": { + "hashes": [ + "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", + "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" + ], + "markers": "python_version >= '3.9'", + "version": "==2.3.0" + }, + "vobject": { + "hashes": [ + "sha256:0fbdb982065cf4d1843a5d5950c88510041c6de026bda49c3502721de1c6ac3d", + "sha256:ac44e5d7e2079d84c1d52c50a615b9bec4b1ba958608c4c7fe40cbf33247b38e" + ], + "version": "==0.9.9" + }, + "x-wr-timezone": { + "hashes": [ + "sha256:1e475d2dedcd2128550cd88b4b5773a224e936e1c9f22ff50104622180455265", + "sha256:37f3927ddc32970c330af97773dc12bf8e0d2deb9ede5c3c676dc13ed62feb11" + ], + "markers": "python_version >= '3.9'", + "version": "==2.0.0" + } + }, + "develop": {} +} From 7117042fd019f2622267b3e405fac094ccd9c734 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Mon, 13 Jan 2025 15:58:45 +0100 Subject: [PATCH 02/34] Create script to create NC app token --- .../calendar_synchronizer/__init__.py | 32 ++++++++++ .../calendar_synchronizer/__main__.py | 3 + .../nc-cal-sync/calendar_synchronizer/cli.py | 16 +++++ .../calendar_synchronizer/login.py | 61 +++++++++++++++++++ .../nc-cal-sync/calendar_synchronizer/sync.py | 22 +++++++ 5 files changed, 134 insertions(+) create mode 100644 scripts/nc-cal-sync/calendar_synchronizer/__init__.py create mode 100644 scripts/nc-cal-sync/calendar_synchronizer/__main__.py create mode 100644 scripts/nc-cal-sync/calendar_synchronizer/cli.py create mode 100644 scripts/nc-cal-sync/calendar_synchronizer/login.py create mode 100644 scripts/nc-cal-sync/calendar_synchronizer/sync.py diff --git a/scripts/nc-cal-sync/calendar_synchronizer/__init__.py b/scripts/nc-cal-sync/calendar_synchronizer/__init__.py new file mode 100644 index 0000000..bcedc8a --- /dev/null +++ b/scripts/nc-cal-sync/calendar_synchronizer/__init__.py @@ -0,0 +1,32 @@ +from . import cli + +from . import login, sync + +import logging + +_logMap = { + 0: logging.WARNING, + 1: logging.INFO, + 2: logging.DEBUG +} + +_runMap = { + 'login': login.run, + 'sync': sync.run, +} + +def main(): + args = cli.getArgs( + loginSpCb=login.buildSubparser, + syncSpCb=sync.buildSubparser + ) + logging.basicConfig() + _l = logging.getLogger(__name__) + _l.setLevel(_logMap.get(args.verbose, logging.DEBUG)) + + _l.debug('Parameters %s', args) + if args.mode in _runMap: + _runMap[args.mode](args) + else: + _l.error('Unknown mode %s', args.mode) + diff --git a/scripts/nc-cal-sync/calendar_synchronizer/__main__.py b/scripts/nc-cal-sync/calendar_synchronizer/__main__.py new file mode 100644 index 0000000..4b443c9 --- /dev/null +++ b/scripts/nc-cal-sync/calendar_synchronizer/__main__.py @@ -0,0 +1,3 @@ +import calendar_synchronizer + +calendar_synchronizer.main() diff --git a/scripts/nc-cal-sync/calendar_synchronizer/cli.py b/scripts/nc-cal-sync/calendar_synchronizer/cli.py new file mode 100644 index 0000000..27e1cba --- /dev/null +++ b/scripts/nc-cal-sync/calendar_synchronizer/cli.py @@ -0,0 +1,16 @@ +import argparse + +def getArgs(loginSpCb, syncSpCb): + parser = argparse.ArgumentParser() + parser.add_argument('-v', '--verbose', action='count', default=0, help='Increase the verbosity') + + subparsers = parser.add_subparsers(dest='mode') + + loginSubparser = subparsers.add_parser('login') + loginSpCb(loginSubparser) + + syncSubparser = subparsers.add_parser('sync') + syncSpCb(syncSubparser) + + # parser.add_argument("url", help="The URL to try and cache") + return parser.parse_args() diff --git a/scripts/nc-cal-sync/calendar_synchronizer/login.py b/scripts/nc-cal-sync/calendar_synchronizer/login.py new file mode 100644 index 0000000..6ee8720 --- /dev/null +++ b/scripts/nc-cal-sync/calendar_synchronizer/login.py @@ -0,0 +1,61 @@ +import os +import requests +import logging +import json + +def buildSubparser(subparser): + subparser.add_argument('--url', default='https://cloud.tsc-vfl.de') + +def run(args): + l = logging.getLogger(__name__) + l.debug('Login to %s', args.url) + + url = f'{args.url}/index.php/login/v2' + l.debug('Using login url %s', url) + + startRequest = requests.post(url) + startRequest.raise_for_status() + + data = startRequest.json() + + print('You need to login in the browser now to validate the login token.') + print('Please visit the following url:') + print(data['login']) + print() + print('After you have logged in, press enter to continue.') + + input() + + l.debug('Logging in') + intermediateToken = data['poll']['token'] + pollUrl = data['poll']['endpoint'] + + loginRequest = requests.post(pollUrl, data={'token': intermediateToken}) + loginRequest.raise_for_status() + + data = loginRequest.json() + + loginName = data['loginName'] + appPassword = data['appPassword'] + data = { + 'loginName': loginName, + 'appPassword': appPassword, + 'base': data['server'] + } + + with open('login.json', 'w') as f: + json.dump(data, f) + + l.info('Login successful') + +class LoginData: + def __init__(self, loginName, appPassword): + self.loginName = loginName + self.appPassword = appPassword + +def loadLoginData(): + with open('login.json', 'r') as f: + data = json.load(f) + + return LoginData(data['loginName'], data['appPassword']) + \ No newline at end of file diff --git a/scripts/nc-cal-sync/calendar_synchronizer/sync.py b/scripts/nc-cal-sync/calendar_synchronizer/sync.py new file mode 100644 index 0000000..809fc1c --- /dev/null +++ b/scripts/nc-cal-sync/calendar_synchronizer/sync.py @@ -0,0 +1,22 @@ +import logging, json + +from . import login + +_l = logging.getLogger(__name__) + +def buildSubparser(subparser): + subparser.add_argument('--schedule', default='../../data/schedule.json') + subparser.add_argument('--holidays', default='../../data/holidays.json') + +def run(args): + _l.info('Loading data from hard disc') + loginData = login.loadLoginData() + + with open(args.schedule, 'r') as f: + schedule = json.load(f) + + with open(args.holidays, 'r') as f: + holidays = json.load(f) + + _l.info('Data was read from hard disc') + From e9d7a871a3cccff51bd3eb1dc58bc8039f551612 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Mon, 13 Jan 2025 15:58:57 +0100 Subject: [PATCH 03/34] Exclude token from git --- scripts/nc-cal-sync/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/nc-cal-sync/.gitignore b/scripts/nc-cal-sync/.gitignore index 1c43c45..0572a39 100644 --- a/scripts/nc-cal-sync/.gitignore +++ b/scripts/nc-cal-sync/.gitignore @@ -1,2 +1,4 @@ /venv/ __pycache__/ + +/login.json From 338806ddaf3761efbf8ba74be8a402928acf4ddc Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Wed, 15 Jan 2025 19:02:15 +0100 Subject: [PATCH 04/34] Extract schedule into dedicated files --- data/holidays.yaml | 27 ++++++++++++++++ data/schedule.yaml | 80 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 data/holidays.yaml create mode 100644 data/schedule.yaml diff --git a/data/holidays.yaml b/data/holidays.yaml new file mode 100644 index 0000000..e0acd04 --- /dev/null +++ b/data/holidays.yaml @@ -0,0 +1,27 @@ +holidays: +- from: 2025-01-01 + to: 2025-01-05 +- from: 2025-04-14 + to: 2025-04-27 +- from: 2025-06-09 + to: 2025-06-22 +- from: 2025-07-31 + to: 2025-09-14 +- from: 2025-10-27 + to: 2025-11-02 +- from: 2025-12-22 + to: 2026-01-05 +feasts: +- 2025-01-01 +- 2025-01-06 +- 2025-04-18 +- 2025-04-21 +- 2025-05-01 +- 2025-05-29 +- 2025-06-09 +- 2025-06-19 +- 2025-10-03 +- 2025-11-01 +- 2025-12-25 +- 2025-12-26 + diff --git a/data/schedule.yaml b/data/schedule.yaml new file mode 100644 index 0000000..f2dbeef --- /dev/null +++ b/data/schedule.yaml @@ -0,0 +1,80 @@ +calendars: + test2: + id: "test1" + schedule: + - day: Mon + start: "17:15" + duration: 60 + title: "DS Kids 6" + age: "2025 - 2026" + # - day: Mon + # start: "18:15" + # duration: 60 + # title: "DS Adults 5" + # - day: Mon + # start: "19:15" + # duration: 90 + # title: "DS Contest Gruppe" + + # - day: Tue + # start: "16:30" + # duration: 60 + # title: "DS Kids 4" + # age: "2015-2028" + # - day: Tue + # start: "17:45" + # duration: 60 + # title: "DS Kids 0" + # age: "2015-2028" + # - day: Tue + # start: "18:45" + # duration: 90 + # title: "DS Adults 1" + + # - day: Wed + # start: "17:00" + # duration: 60 + # title: "DS Kids 2" + # age: "2015-2028" + # - day: Wed + # start: "18:00" + # duration: 60 + # title: "DS Teens 0" + # age: "2015-2028" + # - day: Wed + # start: "20:30" + # duration: 90 + # title: "Turnieraufbau Std" + + # - day: Thu + # start: "17:00" + # duration: 60 + # title: "DS Kids 5" + # age: "2015-2028" + # - day: Thu + # start: "18:30" + # duration: 60 + # title: "DS Kids 1" + # age: "2015-2028" + # - day: Thu + # start: "19:30" + # duration: 60 + # title: "DS Adults 3" + + # - day: Fri + # start: "16:30" + # duration: 60 + # title: "DS Minis 0" + # - day: Fri + # start: "19:00" + # duration: 90 + # title: "Tanzkreis 0" + # - day: Fri + # start: "20:30" + # duration: 60 + # title: "Diskofox" + + vorne: + # id: https://cloud.tsc-vfl.de/remote.php/dav/calendars/christianwolf/vh-vorne-regeltermine_shared_by_tsc + id: "vh-vorne-regeltermine_shared_by_tsc" + ignore: true From 3e204186a3e6c569fcad4cb002b7e1cf07b54459 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Wed, 15 Jan 2025 19:02:35 +0100 Subject: [PATCH 05/34] Install YAML parser in Python deps --- scripts/nc-cal-sync/Pipfile | 1 + scripts/nc-cal-sync/Pipfile.lock | 62 +++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/scripts/nc-cal-sync/Pipfile b/scripts/nc-cal-sync/Pipfile index bd98874..9d9558a 100644 --- a/scripts/nc-cal-sync/Pipfile +++ b/scripts/nc-cal-sync/Pipfile @@ -6,6 +6,7 @@ name = "pypi" [packages] caldav = "*" requests = "*" +pyyaml = "*" [dev-packages] diff --git a/scripts/nc-cal-sync/Pipfile.lock b/scripts/nc-cal-sync/Pipfile.lock index 4ac6957..502cc54 100644 --- a/scripts/nc-cal-sync/Pipfile.lock +++ b/scripts/nc-cal-sync/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "e9cf623aa412fde5f5d9e5f5895fa1a99e1d24e25af6c551fb15ad671d0d0000" + "sha256": "0976c7c1fc6571d991ea2c8a387c220b8bb9ecb2c86fd86a69214de581ee3c76" }, "pipfile-spec": 6, "requires": { @@ -313,6 +313,66 @@ ], "version": "==2024.2" }, + "pyyaml": { + "hashes": [ + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==6.0.2" + }, "recurring-ical-events": { "hashes": [ "sha256:7ea75a560bf0526f7a8294dd93e324cc5379d09d520c48d0ccb4958e591dc2ff", From 96ad8da1fb3a72e56311a4f94888e757e4453864 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Wed, 15 Jan 2025 19:02:48 +0100 Subject: [PATCH 06/34] Allow for level 5 logging --- scripts/nc-cal-sync/calendar_synchronizer/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/nc-cal-sync/calendar_synchronizer/__init__.py b/scripts/nc-cal-sync/calendar_synchronizer/__init__.py index bcedc8a..27c3191 100644 --- a/scripts/nc-cal-sync/calendar_synchronizer/__init__.py +++ b/scripts/nc-cal-sync/calendar_synchronizer/__init__.py @@ -7,7 +7,8 @@ import logging _logMap = { 0: logging.WARNING, 1: logging.INFO, - 2: logging.DEBUG + 2: logging.DEBUG, + 3: 5 } _runMap = { From 2614357a129b0c93b0ae21f98959b6353ef15b08 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Wed, 15 Jan 2025 19:03:52 +0100 Subject: [PATCH 07/34] Store base URL to allow switching to other NC installations --- scripts/nc-cal-sync/calendar_synchronizer/login.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/nc-cal-sync/calendar_synchronizer/login.py b/scripts/nc-cal-sync/calendar_synchronizer/login.py index 6ee8720..dfa07b4 100644 --- a/scripts/nc-cal-sync/calendar_synchronizer/login.py +++ b/scripts/nc-cal-sync/calendar_synchronizer/login.py @@ -49,13 +49,14 @@ def run(args): l.info('Login successful') class LoginData: - def __init__(self, loginName, appPassword): + def __init__(self, loginName, appPassword, base): self.loginName = loginName self.appPassword = appPassword + self.base = base def loadLoginData(): with open('login.json', 'r') as f: data = json.load(f) - return LoginData(data['loginName'], data['appPassword']) + return LoginData(data['loginName'], data['appPassword'], data['base']) \ No newline at end of file From 9148e1f46920ee94227771552f179498621985e0 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Wed, 15 Jan 2025 19:04:41 +0100 Subject: [PATCH 08/34] WIP Synchronization of local yaml with upstream server automation --- .../calendar_synchronizer/cal_helper.py | 46 +++ .../nc-cal-sync/calendar_synchronizer/sync.py | 275 +++++++++++++++++- 2 files changed, 313 insertions(+), 8 deletions(-) create mode 100644 scripts/nc-cal-sync/calendar_synchronizer/cal_helper.py diff --git a/scripts/nc-cal-sync/calendar_synchronizer/cal_helper.py b/scripts/nc-cal-sync/calendar_synchronizer/cal_helper.py new file mode 100644 index 0000000..5b27446 --- /dev/null +++ b/scripts/nc-cal-sync/calendar_synchronizer/cal_helper.py @@ -0,0 +1,46 @@ +import datetime as dt +import re, logging + +from .sync import Event + +class IcalHelper: + + _WEEKDAY_MAP = { + 'Mon': 0, + 'Tue': 1, + 'Wed': 2, + 'Thu': 3, + 'Fri': 4, + 'Sat': 5, + 'Sun': 6 + } + + def __init__(self): + self._l = logging.getLogger(__name__) + self.dDay = dt.timedelta(days=1) + self.firstDay = dt.datetime(year=dt.datetime.now().year, month=1, day=1) + self.reTime = re.compile(r'(\d{1,2}):(\d{2})') + + def getStart(self, event: Event, holidays): + self._getFirstWeekdayInYear(event.day) + self._getFirstOccurence(event, holidays) + pass + + def _getFirstWeekdayInYear(self, weekday): + candidate = self.firstDay + while candidate.weekday() != self._WEEKDAY_MAP[weekday]: + candidate += self.dDay + + self._l.log(5, 'First %s in year is %s', weekday, candidate) + + return candidate + + def _getSortedHolidays(self, holidays): + return sorted(holidays['holidays'], key=lambda h: h['from']) + + def _getSortedFeasts(self, holidays): + return sorted(holidays['feasts']) + + def _getFirstOccurence(self, event: Event, holidays): + firstWeekday = self._getFirstWeekdayInYear(event.day) + firstWeekday.tzinfo = dt.timezone.tzname('Europe/Berlin') diff --git a/scripts/nc-cal-sync/calendar_synchronizer/sync.py b/scripts/nc-cal-sync/calendar_synchronizer/sync.py index 809fc1c..437a2eb 100644 --- a/scripts/nc-cal-sync/calendar_synchronizer/sync.py +++ b/scripts/nc-cal-sync/calendar_synchronizer/sync.py @@ -1,22 +1,281 @@ -import logging, json +import logging, yaml, pprint, json, re +import hashlib +import caldav +import datetime as dt from . import login _l = logging.getLogger(__name__) def buildSubparser(subparser): - subparser.add_argument('--schedule', default='../../data/schedule.json') - subparser.add_argument('--holidays', default='../../data/holidays.json') + subparser.add_argument('--schedule', default='../../data/schedule.yaml') + subparser.add_argument('--holidays', default='../../data/holidays.yaml') + subparser.add_argument('-n', '--dry', action='store_true') + subparser.add_argument('--recreate-all', action='store_true') def run(args): - _l.info('Loading data from hard disc') + loginData, schedule, holidays = _loadRawData(args) + packedSchedule = _unpackSchedules(schedule) + fixedSchedule = _addHolidayExceptions(packedSchedule, holidays) + _synchonizeCalendars(args, fixedSchedule, loginData, holidays) + +def _loadRawData(args): + _l.info('Loading data from hard disk') loginData = login.loadLoginData() with open(args.schedule, 'r') as f: - schedule = json.load(f) + schedule = yaml.safe_load(f.read()) + + _l.log(5, 'Schedule data:\n%s', pprint.pformat(schedule, indent=4, width=100)) with open(args.holidays, 'r') as f: - holidays = json.load(f) - - _l.info('Data was read from hard disc') + holidays = yaml.safe_load(f.read()) + _l.log(5, 'Holidays data:\n%s', pprint.pformat(holidays, indent=4, width=100)) + + _l.info('Data was read from hard disk') + + return loginData, schedule, holidays + +class Event: + def __init__(self, day, start, duration, title): + self.day = day + self.start = start + self.duration = duration + self.title = title + self.age = None + self.external = False + self.description = '' + self.exceptions = [] + + def __repr__(self): + wAge = f' ({self.age})' if self.age is not None else '' + return f'Ev({self.title}{wAge}) [{self.day}, {self.start}, {self.duration}]' + + def getHash(self, holidays): + def fixHolidays(holidays): + def fixDate(d): + return d.strftime('%Y-%m-%d') + + def fixFeast(f): + return fixDate(f) + + def fixHoliday(h): + return { + 'from': fixDate(h['from']), + 'to': fixDate(h['to']), + } + + return { + **holidays, + 'feasts': [fixFeast(f) for f in holidays['feasts']], + 'holidays': [fixHoliday(h) for h in holidays['holidays']], + } + + data = { + 'day': self.day, + 'start': self.start, + 'duration': self.duration, + 'title': self.title, + 'age': self.age, + 'external': self.external, + 'description': self.description, + 'exceptions': self.exceptions, + "holidays": fixHolidays(holidays), + } + # pprint.pprint(data, indent=4, width=100) + hasher = hashlib.sha1() + hasher.update(json.dumps(data, sort_keys=True).encode('utf-8')) + return hasher.hexdigest() + + dDay = dt.timedelta(days=1) + + def addToCalendar(self, calendar: caldav.Calendar, holidays): + from . import cal_helper + + def getFirstTimeInYear(): + now = dt.datetime.now() + d = dt.datetime(year=now.year, month=1, day=1) + pass + + helper = cal_helper.IcalHelper() + helper.getStart(self, holidays) + + icalData = { + 'uid': self.getHash(holidays), + 'DTSTART': dt.datetime.now(), + 'DTEND': dt.datetime.now() + dt.timedelta(minutes=self.duration), + 'SUMMARY': self.title + } + # calendar.add_event(**icalData) + +def _unpackSchedules(schedule): + def packSingleCalendar(cal): + def parseSingleEvent(ev): + e = Event( + day=ev['day'], + start=ev['start'], + duration=ev['duration'], + title=ev['title'] + ) + + if 'age' in ev: + e.age = ev['age'] + if ev.get('extern', False): + e.external = True + if 'desc' in ev: + e.description = ev['desc'] + if 'exceptions' in ev: + raise Exception('Not yet implemented to have exceptions') + + return e + + _l.log(5, 'Unpacking calendar %s', cal) + ret = { **cal } + + if 'schedule' in ret: + ret['schedule'] = [ + parseSingleEvent(e) for e in ret['schedule'] + ] + + _l.log(5, 'Unpacked calendar %s', ret) + return ret + + ret = {} + + for calName in schedule['calendars']: + if schedule['calendars'][calName].get('ignore', False): + _l.info('Ignoring calendar %s', calName) + continue + + ret[calName] = packSingleCalendar(schedule['calendars'][calName]) + + _l.log(5, 'Unpacked schedule:\n%s', pprint.pformat(ret, indent=4, width=100)) + return ret + +def _addHolidayExceptions(schedule, holidays): + return schedule + +class CalendarSynchonizer: + def __init__(self, args, calId, calName, loginData): + self.args = args + self.calId = calId + self.calName = calName + self.loginData = loginData + self._calDav = None + + def _getUrl(self): + return f'{self.loginData.base}/remote.php/dav/calendars' + + def _getCalDav(self): + + if self._calDav is None: + self._calDav = caldav.DAVClient( + url=self._getUrl(), + username=self.loginData.loginName, + password=self.loginData.appPassword + ) + return self._calDav + + def _getCalendar(self): + cd = self._getCalDav() + return cd.principal().calendar(cal_id=self.calId) + + def synchonize(self, calendars, holidays): + downstreamEvents = self._getDownstreamEvents(calendars[self.calName]['schedule'], holidays) + _l.debug('Downstream events:\n%s', pprint.pformat(downstreamEvents, indent=4, width=100)) + + upstreamEvents = self._getUpstreamEvents() + _l.debug('Upstream events:\n%s', pprint.pformat(upstreamEvents, indent=4, width=100)) + + newEvents = self._getNewEvents(upstreamEvents, downstreamEvents) + _l.log(5, 'New events:\n%s', pprint.pformat(newEvents, indent=4, width=100)) + deletedEvents = self._getDeletedEvents(upstreamEvents, downstreamEvents) + _l.log(5, 'Events marked for deletion:\n%s', pprint.pformat(deletedEvents, indent=4, width=100)) + + self._deleteEvents(deletedEvents) + self._addEvents(newEvents, holidays) + + def _getUpstreamEvents(self): + _l.debug('Fetching upstream calendar entries') + cd = self._getCalDav() + + # principal = cd.principal() + # _l.log(5, 'Principal %s', principal) + + # calendar = principal.calendar(cal_id=self.calId) + # _l.log(5, 'Calendar %s', calendar) + + calendar = self._getCalendar() + + # children = calendar.children() + # _l.debug('Getting children for calendar %s:\n%s', self.calId, children) + + events = calendar.events() + + ret = {} + + for e in events: + uid = str(e.icalendar_component['uid']) + _l.log(5, 'Event with uid %s was found.', uid) + ret[uid] = e + + return ret + + def _getDownstreamEvents(self, schedule, holidays): + _l.debug('Preparing local calendar events') + + ret = {} + + for e in schedule: + uid = e.getHash(holidays) + _l.log(5, 'Event with uid %s was found.', uid) + ret[uid] = e + + return ret + + def _getNewEvents(self, upstreamEvents, downstreamEvents): + if self.args.recreate_all: + return downstreamEvents.values() + + upstreamUids = set(upstreamEvents.keys()) + downstreamUids = set(downstreamEvents.keys()) + newUids = downstreamUids - upstreamUids + + return [downstreamEvents[uid] for uid in newUids] + + def _getDeletedEvents(self, upstreamEvents, downstreamEvents): + if self.args.recreate_all: + return upstreamEvents.values() + + upstreamUids = set(upstreamEvents.keys()) + downstreamUids = set(downstreamEvents.keys()) + toDeleteUids = upstreamUids - downstreamUids + + return [upstreamEvents[uid] for uid in toDeleteUids] + + def _addEvents(self, newEvents, holidays): + cal = self._getCalendar() + + for e in newEvents: + _l.debug('Adding event %s', e) + if self.args.dry: + _l.info('Skipping add event %s (dry mode)', e) + else: + # e.save() + e.addToCalendar(cal, holidays) + + def _deleteEvents(self, oldEvents): + for e in oldEvents: + _l.debug('Deleting event %s', e) + if self.args.dry: + _l.info('Skipping delete event %s (dry mode)', e) + else: + e.delete() + +def _synchonizeCalendars(args, calendars, loginData, holidays): + for calName in calendars: + calendar = calendars[calName] + _l.info('Synching calendar %s', calName) + calendarSynchonizer = CalendarSynchonizer(args, calendar['id'], calName, loginData) + calendarSynchonizer.synchonize(calendars, holidays) From 5577cea3516c8eca01e1eca4501bb5f0edd4ad72 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Thu, 16 Jan 2025 15:40:33 +0100 Subject: [PATCH 09/34] Allow for debugging --- scripts/nc-cal-sync/calendar_synchronizer/debug.py | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 scripts/nc-cal-sync/calendar_synchronizer/debug.py diff --git a/scripts/nc-cal-sync/calendar_synchronizer/debug.py b/scripts/nc-cal-sync/calendar_synchronizer/debug.py new file mode 100644 index 0000000..2e34ccd --- /dev/null +++ b/scripts/nc-cal-sync/calendar_synchronizer/debug.py @@ -0,0 +1,10 @@ + +_listening = False + +def debugger(): + global _listening + if not _listening: + import debugpy + debugpy.listen(5678) + debugpy.wait_for_client() + _listening = True From db10fb13e24b5fb5e3a9958e1073fd4f8208acf2 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Thu, 16 Jan 2025 15:42:36 +0100 Subject: [PATCH 10/34] Enhance schedule --- data/schedule.yaml | 125 +++++++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 62 deletions(-) diff --git a/data/schedule.yaml b/data/schedule.yaml index f2dbeef..25bdb7d 100644 --- a/data/schedule.yaml +++ b/data/schedule.yaml @@ -7,72 +7,73 @@ calendars: duration: 60 title: "DS Kids 6" age: "2025 - 2026" - # - day: Mon - # start: "18:15" - # duration: 60 - # title: "DS Adults 5" - # - day: Mon - # start: "19:15" - # duration: 90 - # title: "DS Contest Gruppe" + - day: Mon + start: "18:15" + duration: 60 + title: "DS Adults 5" + extern: true + - day: Mon + start: "19:15" + duration: 90 + title: "DS Contest Gruppe" - # - day: Tue - # start: "16:30" - # duration: 60 - # title: "DS Kids 4" - # age: "2015-2028" - # - day: Tue - # start: "17:45" - # duration: 60 - # title: "DS Kids 0" - # age: "2015-2028" - # - day: Tue - # start: "18:45" - # duration: 90 - # title: "DS Adults 1" + - day: Tue + start: "16:30" + duration: 60 + title: "DS Kids 4" + age: "2015-2028" + - day: Tue + start: "17:45" + duration: 60 + title: "DS Kids 0" + age: "2015-2028" + - day: Tue + start: "18:45" + duration: 90 + title: "DS Adults 1" - # - day: Wed - # start: "17:00" - # duration: 60 - # title: "DS Kids 2" - # age: "2015-2028" - # - day: Wed - # start: "18:00" - # duration: 60 - # title: "DS Teens 0" - # age: "2015-2028" - # - day: Wed - # start: "20:30" - # duration: 90 - # title: "Turnieraufbau Std" + - day: Wed + start: "17:00" + duration: 60 + title: "DS Kids 2" + age: "2015-2028" + - day: Wed + start: "18:00" + duration: 60 + title: "DS Teens 0" + age: "2015-2028" + - day: Wed + start: "20:30" + duration: 90 + title: "Turnieraufbau Std" - # - day: Thu - # start: "17:00" - # duration: 60 - # title: "DS Kids 5" - # age: "2015-2028" - # - day: Thu - # start: "18:30" - # duration: 60 - # title: "DS Kids 1" - # age: "2015-2028" - # - day: Thu - # start: "19:30" - # duration: 60 - # title: "DS Adults 3" + - day: Thu + start: "17:00" + duration: 60 + title: "DS Kids 5" + age: "2015-2028" + - day: Thu + start: "18:30" + duration: 60 + title: "DS Kids 1" + age: "2015-2028" + - day: Thu + start: "19:30" + duration: 60 + title: "DS Adults 3" - # - day: Fri - # start: "16:30" - # duration: 60 - # title: "DS Minis 0" - # - day: Fri - # start: "19:00" - # duration: 90 - # title: "Tanzkreis 0" - # - day: Fri - # start: "20:30" - # duration: 60 - # title: "Diskofox" + - day: Fri + start: "16:30" + duration: 60 + title: "DS Minis 0" + - day: Fri + start: "19:00" + duration: 90 + title: "Tanzkreis 0" + - day: Fri + start: "20:30" + duration: 60 + title: "Diskofox" vorne: # id: https://cloud.tsc-vfl.de/remote.php/dav/calendars/christianwolf/vh-vorne-regeltermine_shared_by_tsc From b68394ec68bf0db0950557c8cfd2784f2eea1952 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Thu, 16 Jan 2025 15:43:06 +0100 Subject: [PATCH 11/34] Enable sychronization of events --- .../calendar_synchronizer/cal_helper.py | 86 +++++++++++++++++-- .../nc-cal-sync/calendar_synchronizer/sync.py | 73 ++++++++++++---- 2 files changed, 137 insertions(+), 22 deletions(-) diff --git a/scripts/nc-cal-sync/calendar_synchronizer/cal_helper.py b/scripts/nc-cal-sync/calendar_synchronizer/cal_helper.py index 5b27446..7dfb865 100644 --- a/scripts/nc-cal-sync/calendar_synchronizer/cal_helper.py +++ b/scripts/nc-cal-sync/calendar_synchronizer/cal_helper.py @@ -1,5 +1,6 @@ import datetime as dt import re, logging +import zoneinfo from .sync import Event @@ -15,21 +16,26 @@ class IcalHelper: 'Sun': 6 } + tzDE = zoneinfo.ZoneInfo('Europe/Berlin') + deltaWeek = dt.timedelta(weeks=1) + deltaDay = dt.timedelta(days=1) + firstDay = dt.date(year=dt.datetime.now().year, month=1, day=1) + def __init__(self): self._l = logging.getLogger(__name__) - self.dDay = dt.timedelta(days=1) - self.firstDay = dt.datetime(year=dt.datetime.now().year, month=1, day=1) self.reTime = re.compile(r'(\d{1,2}):(\d{2})') def getStart(self, event: Event, holidays): - self._getFirstWeekdayInYear(event.day) - self._getFirstOccurence(event, holidays) - pass + firstDay = self._getFirstOccurence(event, holidays) + + if firstDay is None: + return None, None + return firstDay, dt.datetime.combine(firstDay, self._getTime(event.start), tzinfo=self.tzDE) def _getFirstWeekdayInYear(self, weekday): candidate = self.firstDay while candidate.weekday() != self._WEEKDAY_MAP[weekday]: - candidate += self.dDay + candidate += self.deltaDay self._l.log(5, 'First %s in year is %s', weekday, candidate) @@ -40,7 +46,73 @@ class IcalHelper: def _getSortedFeasts(self, holidays): return sorted(holidays['feasts']) + + def _isFeast(self, candidate, feasts): + return candidate in feasts + + def _isHoliday(self, candidate, holidays): + for h in holidays: + if h['from'] <= candidate <= h['to']: + return True + + return False + + def _getLastHolidayException(self, holidays): + holidayList = list(self._getSortedHolidays(holidays)) + holidayList.reverse() + lastHoliday = holidayList[0] + lastHolidayDay = lastHoliday['to'] + + feastList = list(self._getSortedFeasts(holidays)) + feastList.reverse() + lastFeast = feastList[0] + lastFeastDay = lastFeast + + return max(lastHolidayDay, lastFeastDay) def _getFirstOccurence(self, event: Event, holidays): firstWeekday = self._getFirstWeekdayInYear(event.day) - firstWeekday.tzinfo = dt.timezone.tzname('Europe/Berlin') + + + candidate = firstWeekday + while candidate.year == firstWeekday.year: + if self._isFeast(candidate, holidays['feasts']): + self._l.log(5, 'Found feast %s', candidate) + candidate += self.deltaWeek + continue + + if self._isHoliday(candidate, holidays['holidays']): + self._l.log(5, 'Found holiday %s', candidate) + candidate += self.deltaWeek + continue + + self._l.log(5, 'Found first occurence %s', candidate) + return candidate + + return None + + # firstWeekday.tzinfo = dt.timezone.tzname('Europe/Berlin') + + def _getTime(self, startStr): + match = self.reTime.match(startStr) + return dt.time(int(match.group(1)), int(match.group(2))) + + def getHolidayExceptions(self, event: Event, startDay, holidays): + lastHolidayDay = self._getLastHolidayException(holidays) + + pointer = startDay + exeptions = [] + while pointer <= lastHolidayDay: + ex = dt.datetime.combine(pointer, self._getTime(event.start), tzinfo=self.tzDE) + + if self._isFeast(pointer, holidays['feasts']): + exeptions.append(ex) + + if self._isHoliday(pointer, holidays['holidays']) and not event.external: + exeptions.append(ex) + + pointer += self.deltaWeek + + if len(exeptions) > 0: + return exeptions + return None diff --git a/scripts/nc-cal-sync/calendar_synchronizer/sync.py b/scripts/nc-cal-sync/calendar_synchronizer/sync.py index 437a2eb..4e15b4a 100644 --- a/scripts/nc-cal-sync/calendar_synchronizer/sync.py +++ b/scripts/nc-cal-sync/calendar_synchronizer/sync.py @@ -1,9 +1,9 @@ import logging, yaml, pprint, json, re -import hashlib +import hashlib, uuid import caldav import datetime as dt -from . import login +from . import login, debug _l = logging.getLogger(__name__) @@ -50,7 +50,8 @@ class Event: def __repr__(self): wAge = f' ({self.age})' if self.age is not None else '' - return f'Ev({self.title}{wAge}) [{self.day}, {self.start}, {self.duration}]' + ext = 'Ext' if self.external else '' + return f'{ext}Ev({self.title}{wAge}) [{self.day}, {self.start}, {self.duration}]' def getHash(self, holidays): def fixHolidays(holidays): @@ -86,10 +87,22 @@ class Event: # pprint.pprint(data, indent=4, width=100) hasher = hashlib.sha1() hasher.update(json.dumps(data, sort_keys=True).encode('utf-8')) - return hasher.hexdigest() + first = hasher.hexdigest() + second = uuid.uuid4().hex + return f'{first}___{second}', first dDay = dt.timedelta(days=1) + _MAP_WEEKDAY_ICAL = { + 'Mon': 'MO', + 'Tue': 'TU', + 'Wed': 'WE', + 'Thu': 'TH', + 'Fri': 'FR', + 'Sat': 'SA', + 'Sun': 'SU', + } + def addToCalendar(self, calendar: caldav.Calendar, holidays): from . import cal_helper @@ -99,15 +112,44 @@ class Event: pass helper = cal_helper.IcalHelper() - helper.getStart(self, holidays) + startDay, start = helper.getStart(self, holidays) + + if start is None: + _l.warning('Could not get start time for event %s in the current year', self) + return + uid, uidFirst = self.getHash(holidays) icalData = { - 'uid': self.getHash(holidays), - 'DTSTART': dt.datetime.now(), - 'DTEND': dt.datetime.now() + dt.timedelta(minutes=self.duration), - 'SUMMARY': self.title + 'uid': uid, + 'DTSTART': start, + 'DTEND': start + dt.timedelta(minutes=self.duration), + 'SUMMARY': self.title, + 'RRULE': { + 'FREQ': 'DAILY', + 'BYDAY': self._MAP_WEEKDAY_ICAL[self.day] + } } - # calendar.add_event(**icalData) + # debug.debugger() + + holidayExceptions = helper.getHolidayExceptions(self, startDay, holidays) + if holidayExceptions is not None: + icalData['EXDATE'] = holidayExceptions + + desc = '' + if self.age is not None: + desc += f'Jahrgänge: {self.age}' + if len(self.description) > 0: + desc += '\n\n' + desc += self.description + if len(desc) > 0: + icalData['DESCRIPTION'] = desc + + _l.log(5, 'Adding event\n%s', pprint.pformat(icalData, indent=4, width=100)) + + ical = caldav.lib.vcal.create_ical(**icalData) + _l.log(5, 'Created event\n%s', pprint.pformat(ical, indent=4, width=100)) + _l.log(5, 'Created event\n%s', ical) + calendar.add_event(**icalData) def _unpackSchedules(schedule): def packSingleCalendar(cal): @@ -121,7 +163,7 @@ def _unpackSchedules(schedule): if 'age' in ev: e.age = ev['age'] - if ev.get('extern', False): + if ev.get('extern', False) or ev.get('external', False): e.external = True if 'desc' in ev: e.description = ev['desc'] @@ -216,7 +258,8 @@ class CalendarSynchonizer: ret = {} for e in events: - uid = str(e.icalendar_component['uid']) + uidRaw = str(e.icalendar_component['uid']) + uid = uidRaw.split('___', 1)[0] _l.log(5, 'Event with uid %s was found.', uid) ret[uid] = e @@ -228,9 +271,9 @@ class CalendarSynchonizer: ret = {} for e in schedule: - uid = e.getHash(holidays) - _l.log(5, 'Event with uid %s was found.', uid) - ret[uid] = e + uid, uidFirst = e.getHash(holidays) + _l.log(5, 'Event with uid part %s was found.', uidFirst) + ret[uidFirst] = e return ret From 294c537f3fa14b44a455dd7bf46188bbb6c49e78 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Thu, 16 Jan 2025 17:32:55 +0100 Subject: [PATCH 12/34] Create helper scripts to convert old calendar to new style. --- scripts/nc-cal-sync/helper/convert.sh | 23 +++++++++++++++++++++++ scripts/nc-cal-sync/helper/test.yq | 12 ++++++++++++ 2 files changed, 35 insertions(+) create mode 100755 scripts/nc-cal-sync/helper/convert.sh create mode 100644 scripts/nc-cal-sync/helper/test.yq diff --git a/scripts/nc-cal-sync/helper/convert.sh b/scripts/nc-cal-sync/helper/convert.sh new file mode 100755 index 0000000..b139fa5 --- /dev/null +++ b/scripts/nc-cal-sync/helper/convert.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "calendars:" +for r in vorne mitte hinten +do + echo " $r:" + echo " id: \"$r\"" + echo " ignore: true" + echo " schedule:" + echo -n " " + ( + echo '[' + prefix_comma='' + for d in Mo Di Mi Do Fr + do + echo -n "$prefix_comma" + prefix_comma=', ' + cat ../../data/calendar.yaml | yq -cj '.calendar.'"$r.$d"' | . as $dict | [keys[] | . as $key | $dict[$key] | to_entries | [ .[], {key: "day", value: "'"$d"'"}, {key: "start", value: $key}, {key: "age", value: ""}, {key: "extern", value: false}, {key: "duration", value: (($dict[$key].slots) * 15)} ] | from_entries | del(.slots)]' + done + echo ']' + ) | jq -cj '[ .[][] ]' + echo +done diff --git a/scripts/nc-cal-sync/helper/test.yq b/scripts/nc-cal-sync/helper/test.yq new file mode 100644 index 0000000..b50ac87 --- /dev/null +++ b/scripts/nc-cal-sync/helper/test.yq @@ -0,0 +1,12 @@ +.calendar.vorne.Mo | . as $dict | + keys[] | . as $key | + $dict[$key] | to_entries | + [ + .[], + {key: "day", value: "Mo"}, + {key: "start", value: $key}, + {key: "age", value: ""}, + {key: "extern", value: false}, + {key: "duration", value: (($dict[$key].slots) * 15)} + ] | + from_entries | del(.slots) From 634604972ce6103cddb6e79d7df71c922e91c79f Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Thu, 16 Jan 2025 17:33:13 +0100 Subject: [PATCH 13/34] Update schedule to real schedule --- data/schedule.yaml | 337 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 258 insertions(+), 79 deletions(-) diff --git a/data/schedule.yaml b/data/schedule.yaml index 25bdb7d..4db97cb 100644 --- a/data/schedule.yaml +++ b/data/schedule.yaml @@ -1,81 +1,260 @@ calendars: - test2: - id: "test1" - schedule: - - day: Mon - start: "17:15" - duration: 60 - title: "DS Kids 6" - age: "2025 - 2026" - - day: Mon - start: "18:15" - duration: 60 - title: "DS Adults 5" - extern: true - - day: Mon - start: "19:15" - duration: 90 - title: "DS Contest Gruppe" - - - day: Tue - start: "16:30" - duration: 60 - title: "DS Kids 4" - age: "2015-2028" - - day: Tue - start: "17:45" - duration: 60 - title: "DS Kids 0" - age: "2015-2028" - - day: Tue - start: "18:45" - duration: 90 - title: "DS Adults 1" - - - day: Wed - start: "17:00" - duration: 60 - title: "DS Kids 2" - age: "2015-2028" - - day: Wed - start: "18:00" - duration: 60 - title: "DS Teens 0" - age: "2015-2028" - - day: Wed - start: "20:30" - duration: 90 - title: "Turnieraufbau Std" - - - day: Thu - start: "17:00" - duration: 60 - title: "DS Kids 5" - age: "2015-2028" - - day: Thu - start: "18:30" - duration: 60 - title: "DS Kids 1" - age: "2015-2028" - - day: Thu - start: "19:30" - duration: 60 - title: "DS Adults 3" - - - day: Fri - start: "16:30" - duration: 60 - title: "DS Minis 0" - - day: Fri - start: "19:00" - duration: 90 - title: "Tanzkreis 0" - - day: Fri - start: "20:30" - duration: 60 - title: "Diskofox" - vorne: - # id: https://cloud.tsc-vfl.de/remote.php/dav/calendars/christianwolf/vh-vorne-regeltermine_shared_by_tsc - id: "vh-vorne-regeltermine_shared_by_tsc" - ignore: true + id: test1 + ignore: false + schedule: + - title: DS-Kids 6 + day: Mon + start: '17:15' + age: '' + extern: false + duration: 60 + - title: DS Adults 5 + day: Mon + start: '18:15' + age: '' + extern: false + duration: 60 + - title: DS Contest Gruppe + day: Mon + start: '19:15' + age: '' + extern: false + duration: 90 + + - title: DS Kids 4 + day: Tue + start: '16:30' + age: '' + extern: false + duration: 60 + - title: DS Kids 0 + day: Tue + start: '17:45' + age: '' + extern: false + duration: 60 + - title: DS Adults 1 + day: Tue + start: '18:45' + age: '' + extern: false + duration: 90 + + - title: DS Kids 2 + day: Wed + start: '17:00' + age: '' + extern: false + duration: 60 + - title: DS Teens 0 + day: Wed + start: '18:00' + age: '' + extern: false + duration: 60 + - title: Turnieraufbau Std + day: Wed + start: '20:30' + age: '' + extern: false + duration: 90 + + - title: DS Kids 5 + day: Thu + start: '17:00' + age: '' + extern: false + duration: 60 + - title: DS Kids 1 + day: Thu + start: '18:30' + age: '' + extern: false + duration: 60 + - title: DS Adults 3 + day: Thu + start: '19:30' + age: '' + extern: false + duration: 60 + + - title: DS Minis 0 + day: Fri + start: '16:30' + age: '' + extern: false + duration: 60 + - title: Tanzkreis 0 + day: Fri + start: '19:00' + age: '' + extern: false + duration: 90 + - title: Discofox + day: Fri + start: '20:30' + age: '' + extern: false + duration: 60 + + mitte: + id: test2 + ignore: false + schedule: + - title: DS Teens 2 + day: Mon + start: '17:30' + age: '' + extern: false + duration: 60 + - title: Ballet + day: Mon + start: '18:30' + age: '' + extern: false + duration: 90 + - title: Tanzkreis 1 + day: Mon + start: '20:00' + age: '' + extern: false + duration: 90 + + - title: Tanzkreis 2 + day: Tue + start: '20:00' + age: '' + extern: false + duration: 120 + + - title: DS Kids 7 + day: Wed + start: '18:00' + age: '' + extern: false + duration: 60 + - title: Tanzkreis 3 + day: Wed + start: '19:00' + age: '' + extern: false + duration: 90 + - title: Tanzkreis 4 + day: Wed + start: '20:30' + age: '' + extern: false + duration: 90 + + - title: DS Minis 1 + day: Thu + start: '16:45' + age: '' + extern: false + duration: 60 + - title: Tanzkreis 5 + day: Thu + start: '19:30' + age: '' + extern: false + duration: 90 + + - title: Tanzkreis 6 - Einsteiger + day: Fri + start: '18:30' + age: '' + extern: false + duration: 30 + - title: Tanzkreis 6 + day: Fri + start: '19:00' + age: '' + extern: false + duration: 90 + - title: Tanzkreis 9 + day: Fri + start: '20:30' + age: '' + extern: false + duration: 90 + hinten: + id: test3 + ignore: false + schedule: + - title: Ballet + day: Mon + start: '16:00' + age: '' + extern: true + duration: 90 + + - title: Turnier Latein + day: Tue + start: '19:00' + age: '' + extern: false + duration: 60 + - title: Turnier Standard + day: Tue + start: '20:00' + age: '' + extern: false + duration: 120 + + - title: Ballet + day: Wed + start: '10:30' + age: '' + extern: true + duration: 90 + - title: DS Kids 3 + day: Wed + start: '16:45' + age: '' + extern: false + duration: 60 + - title: DS Teens 1 + day: Wed + start: '18:00' + age: '' + extern: false + duration: 60 + - title: DS Adults 0 + day: Wed + start: '19:00' + age: '' + extern: false + duration: 60 + - title: Breitensport + day: Wed + start: '20:00' + age: '' + extern: false + duration: 90 + + - title: Kindertanz 8 (Turnieraufbau) + day: Thu + start: '18:00' + age: '' + extern: false + duration: 90 + + - title: Kindertanz 0 + day: Fri + start: '14:30' + age: '' + extern: false + duration: 60 + - title: Kindertanz 1 + day: Fri + start: '15:30' + age: '' + extern: false + duration: 60 + - title: Kindertanz 2 (Turnieraufbau) + day: Fri + start: '16:30' + age: '' + extern: false + duration: 150 From 8fcb7994eeeea616bff015aa2871dccca5d110cc Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Thu, 16 Jan 2025 17:55:00 +0100 Subject: [PATCH 14/34] Manually fix missing information --- data/schedule.yaml | 95 +++++++++++----------------------------------- 1 file changed, 23 insertions(+), 72 deletions(-) diff --git a/data/schedule.yaml b/data/schedule.yaml index 4db97cb..f8719c8 100644 --- a/data/schedule.yaml +++ b/data/schedule.yaml @@ -5,97 +5,80 @@ calendars: schedule: - title: DS-Kids 6 day: Mon - start: '17:15' - age: '' - extern: false + start: '17:00' + age: '2017 - 2019' duration: 60 - title: DS Adults 5 day: Mon start: '18:15' - age: '' - extern: false + age: 'ab 18' duration: 60 - title: DS Contest Gruppe day: Mon start: '19:15' - age: '' - extern: false + age: 'auf Anfrage' duration: 90 - title: DS Kids 4 day: Tue start: '16:30' - age: '' - extern: false + age: '2015 - 2017' duration: 60 - title: DS Kids 0 day: Tue start: '17:45' - age: '' - extern: false + age: '2011 - 2013' duration: 60 - title: DS Adults 1 day: Tue start: '18:45' - age: '' - extern: false + age: 'ab 18' duration: 90 - title: DS Kids 2 day: Wed start: '17:00' - age: '' - extern: false + age: '2010 - 2012' duration: 60 - title: DS Teens 0 day: Wed start: '18:00' - age: '' + age: '2008 - 2010' extern: false duration: 60 - title: Turnieraufbau Std day: Wed start: '20:30' - age: '' - extern: false duration: 90 - title: DS Kids 5 day: Thu start: '17:00' - age: '' - extern: false + age: '2010 - 2013' duration: 60 - title: DS Kids 1 day: Thu start: '18:30' - age: '' - extern: false + age: '2012 - 2014' duration: 60 - title: DS Adults 3 day: Thu start: '19:30' - age: '' - extern: false + age: 'ab 18' duration: 60 - title: DS Minis 0 day: Fri start: '16:30' - age: '' - extern: false + age: '2019 - 2020' duration: 60 - title: Tanzkreis 0 day: Fri start: '19:00' - age: '' - extern: false duration: 90 - title: Discofox day: Fri start: '20:30' - age: '' - extern: false duration: 60 mitte: @@ -105,79 +88,61 @@ calendars: - title: DS Teens 2 day: Mon start: '17:30' - age: '' - extern: false + age: '2006 - 09' duration: 60 - title: Ballet day: Mon start: '18:30' age: '' - extern: false + extern: true duration: 90 - title: Tanzkreis 1 day: Mon start: '20:00' - age: '' - extern: false duration: 90 - title: Tanzkreis 2 day: Tue start: '20:00' - age: '' - extern: false duration: 120 - title: DS Kids 7 day: Wed start: '18:00' - age: '' - extern: false + age: '2012 - 2015' duration: 60 - title: Tanzkreis 3 day: Wed start: '19:00' - age: '' - extern: false duration: 90 - title: Tanzkreis 4 day: Wed start: '20:30' - age: '' - extern: false duration: 90 - title: DS Minis 1 day: Thu start: '16:45' - age: '' - extern: false + age: '2020 - 2021' duration: 60 - title: Tanzkreis 5 day: Thu start: '19:30' - age: '' - extern: false duration: 90 - title: Tanzkreis 6 - Einsteiger day: Fri start: '18:30' - age: '' - extern: false duration: 30 - title: Tanzkreis 6 day: Fri start: '19:00' - age: '' - extern: false duration: 90 - title: Tanzkreis 9 day: Fri start: '20:30' - age: '' - extern: false duration: 90 + hinten: id: test3 ignore: false @@ -192,14 +157,10 @@ calendars: - title: Turnier Latein day: Tue start: '19:00' - age: '' - extern: false duration: 60 - title: Turnier Standard day: Tue start: '20:00' - age: '' - extern: false duration: 120 - title: Ballet @@ -211,50 +172,40 @@ calendars: - title: DS Kids 3 day: Wed start: '16:45' - age: '' - extern: false + age: '2014 - 2016' duration: 60 - title: DS Teens 1 day: Wed start: '18:00' - age: '' - extern: false + age: '2004 - 07' duration: 60 - title: DS Adults 0 day: Wed start: '19:00' - age: '' - extern: false + age: 'ab 18' duration: 60 - title: Breitensport day: Wed start: '20:00' - age: '' - extern: false duration: 90 - title: Kindertanz 8 (Turnieraufbau) day: Thu start: '18:00' - age: '' - extern: false duration: 90 - title: Kindertanz 0 day: Fri start: '14:30' - age: '' - extern: false + age: '2018 - 2020' duration: 60 - title: Kindertanz 1 day: Fri start: '15:30' - age: '' - extern: false + age: '2016 - 18' duration: 60 - title: Kindertanz 2 (Turnieraufbau) day: Fri start: '16:30' age: '' - extern: false duration: 150 From 69368dd8e8a3a38ed886fd8eae42c41dbbb4cf8c Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Thu, 16 Jan 2025 17:57:18 +0100 Subject: [PATCH 15/34] Integrate changes made on other branch --- data/schedule.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/schedule.yaml b/data/schedule.yaml index f8719c8..b07723c 100644 --- a/data/schedule.yaml +++ b/data/schedule.yaml @@ -3,9 +3,9 @@ calendars: id: test1 ignore: false schedule: - - title: DS-Kids 6 + - title: DS Kids 6 day: Mon - start: '17:00' + start: '17:10' age: '2017 - 2019' duration: 60 - title: DS Adults 5 From ca6b1c16db518276e523b41927be945cdc2633e6 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Fri, 17 Jan 2025 14:21:11 +0100 Subject: [PATCH 16/34] Create shortcode to draw table of offerings --- data/days.yml | 7 +++ .../shortcodes/tsc/calendar/table.html | 52 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 data/days.yml create mode 100644 themes/tsc_vfl/layouts/shortcodes/tsc/calendar/table.html diff --git a/data/days.yml b/data/days.yml new file mode 100644 index 0000000..ffb9f0b --- /dev/null +++ b/data/days.yml @@ -0,0 +1,7 @@ +Mon: Montag +Tue: Dienstag +Wed: Mittwoch +Thu: Donnerstag +Fri: Freitag +Sat: Samstag +Sun: Sonntag diff --git a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/table.html b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/table.html new file mode 100644 index 0000000..05367e1 --- /dev/null +++ b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/table.html @@ -0,0 +1,52 @@ +{{ $calendars := .Site.Data.schedule.calendars -}} +{{- $list := slice -}} +{{- range $room, $roomData := $calendars -}} + {{- if ($roomData.ignore | default false) -}}{{ continue }}{{- end -}} + {{- $roomName := $roomData.name | default $room -}} + {{/* warnf "%s " $room */}} + {{- range $roomData.schedule -}} + {{- $addData := dict "room" $roomName "weight" 0 -}} + {{- $addData = merge $addData . -}} + {{/* warnf "%#v" $addData */}} + {{- $list = $list | append $addData -}} + {{- end -}} +{{- end -}} +{{- $cat := .Get "category" -}} +{{- $showAge := .Get "showAge" | default false -}} +{{- $list = sort $list "start" -}} +{{- $list = sort $list "title" -}} +{{- $list = sort $list "weight" -}} +{{/* warnf "%#v" $list */}} + + + + + {{ if $showAge }}{{ end }} + + + + + + + {{ range $list -}} + {{- if ne .class $cat }}{{ continue }}{{ end -}} + {{/* warnf "%#v" . */}} + + + {{ if $showAge }}{{ end }} + + + + + {{- end}} + +
GruppeJahrgangTagZeitOrt
+ {{ .title }}{{ with .subtitle }} - {{ . }}{{ end }} + {{ .age }}{{ index site.Data.days .day }} + {{- $startTimeStr := printf "2025-01-02T%s:00" .start -}} + {{- $startTime := time.AsTime $startTimeStr -}} + {{- $duration := time.Duration "minute" .duration -}} + {{- $endTime := $startTime.Add $duration}} + {{/* warnf "Start %s, duration %s, %s" $startTime $duration $endTime */}} + {{- $startTime.Format "15:04"}} - {{ $endTime.Format "15:04" }} + {{ .room }}
From 14818a892d14a9d4436033a28a57b991e9348470 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Fri, 17 Jan 2025 14:22:44 +0100 Subject: [PATCH 17/34] Migrate schedule tables to new format (mostly) --- content/page/angebote/breitensport/index.md | 4 +- content/page/angebote/dancestyles/index.md | 27 ++--------- content/page/angebote/discofox/index.md | 4 +- content/page/angebote/kinder/index.md | 7 +-- content/page/angebote/tanzkreise/index.md | 12 +---- data/schedule.yaml | 52 +++++++++++++++++++-- 6 files changed, 56 insertions(+), 50 deletions(-) diff --git a/content/page/angebote/breitensport/index.md b/content/page/angebote/breitensport/index.md index 11f68d8..2021b85 100644 --- a/content/page/angebote/breitensport/index.md +++ b/content/page/angebote/breitensport/index.md @@ -14,9 +14,7 @@ Mit unserer Breitensportgruppe sprechen wie diejenigen an, die zwar (noch) keine   ## Trainingszeit Breitensport -| Breitensport Standard | Tag | Zeit | Ort | -|-----------------------|-------------|----------------|-----------| -| Breitensport Standard | Mittwoch | 20:00 - 21:30 | VH Hinten | +{{}} {{% tsc/link-offers %}} diff --git a/content/page/angebote/dancestyles/index.md b/content/page/angebote/dancestyles/index.md index ae84075..95530d1 100644 --- a/content/page/angebote/dancestyles/index.md +++ b/content/page/angebote/dancestyles/index.md @@ -22,36 +22,15 @@ Und wann bist Du dabei? ## Trainingszeiten Dance-Styles Adults -|Dance Styles | Alter | Tag | Zeit | Ort | -|--------------------|---------|------------|---------------|-----------| -| D-S Adults 0 | ab 18 | Mittwoch | 19:00 - 20:00 | VH Hinten | -| D-S Adults 1 | ab 18 | Dienstag | 18:45 - 20:15 | VH Vorn | -| D-S Adults 3 | ab 18 | Donnerstag | 19:30 - 20:30 | VH Vorn | -| D-S Adults 5 | ab 18 | Montag | 18:15 - 19:15 | VH Vorn | -| D-S Contest Gruppe | Anfrage | Montag | 19:15 - 20:45 | VH Vorn | +{{< tsc/calendar/table category="DSAdults" showAge="true" >}} ## Trainingszeiten Dance-Styles Teens -|Dance-Styles Teens | Jahrgang | Tag | Zeit | Ort | -|-------------------|-----------|----------|---------------|------------| -| D-S Teens 0 | 2008 - 10 | Mittwoch | 18:00 - 19:00 | VH Vorn | -| D-S Teens 1 | 2004 - 07 | Mittwoch | 18:00 - 19:00 | VH Hinten | -| D-S Teens 2 | 2006 - 09 | Montag | 17:30 - 18:30 | VH Mitte | +{{< tsc/calendar/table category="DSTeens" showAge="true" >}} ## Trainingszeiten Dance-Styles Kids -|Dance-Styles Kids | Jahrgang | Tag | Zeit | Ort | -|---------------------|-----------|------------|---------------|-----------| -| D-S Minis 0 | 2019 - 20 | Freitag | 16:30 - 17:30 | VH Vorn | -| D-S Minis 1 | 2020 - 21 | Donnerstag | 16:45 - 17:45 | VH Mitte | -| D-S Kids 0 | 2011 - 13 | Dienstag | 17:45 - 18:45 | VH Vorn | -| D-S Kids 1 | 2012 - 14 | Donnerstag | 18:30 - 19:30 | VH Vorn | -| D-S Kids 2 | 2010 - 12 | Mittwoch | 17:00 - 18:00 | VH Vorn | -| D-S Kids 3 | 2014 - 16 | Mittwoch | 16:45 - 17:45 | VH Hinten | -| D-S-Kids 4 | 2015 - 17 | Dienstag | 16:30 - 17:30 | VH Vorn | -| D-S Kids 5 | 2010 - 13 | Donnerstag | 17:00 - 18:00 | VH Vorn | -| D-S-Kids 6 | 2017 - 19 | Montag | 17:00 - 18:00 | VH Vorn | -| D-S Kids 7 | 2012 - 15 | Mittwoch | 18:00 - 19:00 | VH Mitte | +{{< tsc/calendar/table category="DSKids" showAge="true" >}} Interesse an Standard- und Lateintanzkursen für Kinder und Jugendliche? Im Bereich Kinder/Jugend findest du weitere Angebote. diff --git a/content/page/angebote/discofox/index.md b/content/page/angebote/discofox/index.md index 0a6fc3d..b131cd1 100644 --- a/content/page/angebote/discofox/index.md +++ b/content/page/angebote/discofox/index.md @@ -18,8 +18,6 @@ Wer schon Discofox tanzen kann, lernt bestimmt die eine oder andere tolle neue F ## Trainingszeit Discofox -|Discofox | Tag | Zeit | Ort | -|---|---|---|---| -|Discofox | Freitag | 20:30 - 21:30 | VH Vorn | +{{< tsc/calendar/table category="Discofox" >}} {{% tsc/link-offers %}} diff --git a/content/page/angebote/kinder/index.md b/content/page/angebote/kinder/index.md index 05b24af..a67f30a 100644 --- a/content/page/angebote/kinder/index.md +++ b/content/page/angebote/kinder/index.md @@ -20,12 +20,7 @@ Für manchen ist es bereits eine gute Erfahrung, um später in einer der größe ## Trainingszeiten Kinder- / Jugendgruppen, Standard und Latein -| Kinder | Jahrgang | Tag | Zeit | Ort | -|----------------------------------------|-----------|------------|---------------|------------| -| Kindertanz 0 | 2018 - 20 | Freitag | 14:30 - 15:30 | VH Hinten | -| Kindertanz 1 | 2016 - 18 | Freitag | 15:30 - 16:30 | VH Hinten | -| Kindertanz 2 Turnieraufbau Kinder | | Freitag | 16:30 - 19:00 | VH Hinten | -| Kindertanz 8 Turnieraufb. Latein Ki/Ju | | Donnerstag | 18:00 - 19:30 | VH Hinten | +{{< tsc/calendar/table category="Kinder" showAge="true" >}} Weitere spannende Angebote für Kinder und Teens findet ihr bei unseren Dance-Stylern. diff --git a/content/page/angebote/tanzkreise/index.md b/content/page/angebote/tanzkreise/index.md index b826b95..e9ccea3 100644 --- a/content/page/angebote/tanzkreise/index.md +++ b/content/page/angebote/tanzkreise/index.md @@ -17,16 +17,6 @@ Interessiert? Na, dann schauen Sie doch einfach einmal vorbei! ## Trainingszeiten Tanzkreise -| Tanzkreise | Tag | Zeit | Ort | -|-------------|-------------|---------------|----------| -| Tanzkreis 0 | Freitag | 19:00 - 20:30 | VH Vorn | -| Tanzkreis 1 | Montag | 20:00 - 21:30 | VH Mitte | -| Tanzkreis 2 | Dienstag | 20:00 - 22:00 | VH Mitte | -| Tanzkreis 3 | Mittwoch | 19:00 - 20:30 | VH Mitte | -| Tanzkreis 4 | Mittwoch | 20:30 - 22:00 | VH Mitte | -| Tanzkreis 5 | Donnerstag | 19:30 - 21:00 | VH Mitte | -| Tanzkreis 6 Einsteiger | Freitag | 18:30 - 19:00 | VH Mitte | -| Tanzkreis 6 | Freitag | 19:00 - 20:30 | VH Mitte | -| Tanzkreis 9 | Freitag | 20:30 - 22:00 | VH Mitte | +{{< tsc/calendar/table category="Tanzkreise" >}} {{% tsc/link-offers %}} diff --git a/data/schedule.yaml b/data/schedule.yaml index b07723c..06e5620 100644 --- a/data/schedule.yaml +++ b/data/schedule.yaml @@ -2,149 +2,182 @@ calendars: vorne: id: test1 ignore: false + name: VH Vorn schedule: - title: DS Kids 6 day: Mon start: '17:10' age: '2017 - 2019' duration: 60 + class: DSKids - title: DS Adults 5 day: Mon start: '18:15' age: 'ab 18' duration: 60 + class: DSAdults - title: DS Contest Gruppe day: Mon start: '19:15' age: 'auf Anfrage' duration: 90 + class: DSAdults - title: DS Kids 4 day: Tue start: '16:30' age: '2015 - 2017' duration: 60 + class: DSKids - title: DS Kids 0 day: Tue start: '17:45' age: '2011 - 2013' duration: 60 + class: DSKids - title: DS Adults 1 day: Tue start: '18:45' age: 'ab 18' duration: 90 + class: DSAdults - title: DS Kids 2 day: Wed start: '17:00' age: '2010 - 2012' duration: 60 + class: DSKids - title: DS Teens 0 day: Wed start: '18:00' age: '2008 - 2010' extern: false duration: 60 + class: DSTeens - title: Turnieraufbau Std day: Wed start: '20:30' duration: 90 + class: Turnier - title: DS Kids 5 day: Thu start: '17:00' age: '2010 - 2013' duration: 60 + class: DSKids - title: DS Kids 1 day: Thu start: '18:30' age: '2012 - 2014' duration: 60 + class: DSKids - title: DS Adults 3 day: Thu start: '19:30' age: 'ab 18' duration: 60 + class: DSAdults - title: DS Minis 0 + weight: -1 day: Fri start: '16:30' age: '2019 - 2020' duration: 60 + class: DSKids - title: Tanzkreis 0 day: Fri start: '19:00' duration: 90 + class: Tanzkreise - title: Discofox day: Fri start: '20:30' duration: 60 + class: Discofox mitte: id: test2 + name: VH Mitte ignore: false schedule: - title: DS Teens 2 day: Mon start: '17:30' - age: '2006 - 09' + age: '2006 - 2009' duration: 60 + class: DSTeens - title: Ballet day: Mon start: '18:30' age: '' extern: true duration: 90 + # class: DSKids - title: Tanzkreis 1 day: Mon start: '20:00' duration: 90 + class: Tanzkreise - title: Tanzkreis 2 day: Tue start: '20:00' duration: 120 + class: Tanzkreise - title: DS Kids 7 day: Wed start: '18:00' age: '2012 - 2015' duration: 60 + class: DSKids - title: Tanzkreis 3 day: Wed start: '19:00' duration: 90 + class: Tanzkreise - title: Tanzkreis 4 day: Wed start: '20:30' duration: 90 + class: Tanzkreise - title: DS Minis 1 + weight: -1 day: Thu start: '16:45' age: '2020 - 2021' duration: 60 + class: DSKids - title: Tanzkreis 5 day: Thu start: '19:30' duration: 90 + class: Tanzkreise - - title: Tanzkreis 6 - Einsteiger + - title: Tanzkreis 6 + subtitle: Einsteiger day: Fri start: '18:30' duration: 30 + class: Tanzkreise - title: Tanzkreis 6 day: Fri start: '19:00' duration: 90 + class: Tanzkreise - title: Tanzkreis 9 day: Fri start: '20:30' duration: 90 + class: Tanzkreise hinten: id: test3 + name: VH Hinten ignore: false schedule: - title: Ballet @@ -153,15 +186,18 @@ calendars: age: '' extern: true duration: 90 + # class: DSKids - title: Turnier Latein day: Tue start: '19:00' duration: 60 + class: Turnier - title: Turnier Standard day: Tue start: '20:00' duration: 120 + class: Turnier - title: Ballet day: Wed @@ -169,43 +205,53 @@ calendars: age: '' extern: true duration: 90 + # class: DSKids - title: DS Kids 3 day: Wed start: '16:45' age: '2014 - 2016' duration: 60 + class: DSKids - title: DS Teens 1 day: Wed start: '18:00' - age: '2004 - 07' + age: '2004 - 2007' duration: 60 + class: DSTeens - title: DS Adults 0 day: Wed start: '19:00' age: 'ab 18' duration: 60 + class: DSAdults - title: Breitensport + subtitle: Standard day: Wed start: '20:00' duration: 90 + class: Breitensport - title: Kindertanz 8 (Turnieraufbau) day: Thu start: '18:00' duration: 90 + class: Kinder - title: Kindertanz 0 day: Fri start: '14:30' age: '2018 - 2020' duration: 60 + class: Kinder - title: Kindertanz 1 day: Fri start: '15:30' age: '2016 - 18' duration: 60 + class: Kinder - title: Kindertanz 2 (Turnieraufbau) day: Fri start: '16:30' age: '' duration: 150 + class: Kinder From e4ad157a54c18e4cedaa2ad31adb9f819369c3c0 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Fri, 17 Jan 2025 14:23:27 +0100 Subject: [PATCH 18/34] Correct timing of DS kids 6 --- data/schedule.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/schedule.yaml b/data/schedule.yaml index 06e5620..57b5a62 100644 --- a/data/schedule.yaml +++ b/data/schedule.yaml @@ -6,7 +6,7 @@ calendars: schedule: - title: DS Kids 6 day: Mon - start: '17:10' + start: '17:00' age: '2017 - 2019' duration: 60 class: DSKids From ca6250bbf692a172142ddc30d884763767974711 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Fri, 17 Jan 2025 15:36:01 +0100 Subject: [PATCH 19/34] Allow for multiple categories in tables --- content/page/angebote/turniersport/_index.md | 11 ++--------- data/schedule.yaml | 13 +++++++++---- .../layouts/shortcodes/tsc/calendar/table.html | 7 +++++-- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/content/page/angebote/turniersport/_index.md b/content/page/angebote/turniersport/_index.md index 875fa23..037dd02 100644 --- a/content/page/angebote/turniersport/_index.md +++ b/content/page/angebote/turniersport/_index.md @@ -22,16 +22,9 @@ Darüber hinaus können unsere Tänzer zu fast jeder Zeit noch frei trainieren - [unsere Turnierpaare]({{< relref "paare" >}}) ## Trainingszeiten Turniertanz -| Turniertanz | Tag | Zeit | Ort | -|---------------------------------------------|---------|-----------------|---------| -| Turnieraufbau Latein | Di | 19:00 - 20:00 | VH Neu | -| Turnier Standard | Di | 20:00 - 22:00 | VH Neu | -| Turnieraufbau Standard | Mi | 20:30 - 22:00 | VH Vorn | -| Turnieraufbau Kinder Jugend inkl. Basic | Mi | 16:30 - 18:00 | VH Neu | -| Turnieraufbau Kinder Jugend inkl. Basic | Do | 18:00 - 19:30 | VH Neu | -| Turnieraufbau Kinder Jugend inkl. Basic | Fr | 16:00 - 17:00 | VH Neu | -  +{{< tsc/calendar/table category="Turnier" >}} + {{% tsc/link-offers %}} ## Sportverwaltung und weitere Links diff --git a/data/schedule.yaml b/data/schedule.yaml index 57b5a62..8afa8e1 100644 --- a/data/schedule.yaml +++ b/data/schedule.yaml @@ -56,6 +56,7 @@ calendars: duration: 60 class: DSTeens - title: Turnieraufbau Std + weight: -1 day: Wed start: '20:30' duration: 90 @@ -189,11 +190,13 @@ calendars: # class: DSKids - title: Turnier Latein + weight: -1 day: Tue start: '19:00' duration: 60 class: Turnier - title: Turnier Standard + weight: -1 day: Tue start: '20:00' duration: 120 @@ -231,11 +234,12 @@ calendars: duration: 90 class: Breitensport - - title: Kindertanz 8 (Turnieraufbau) + - title: Kindertanz 8 + subtitle: Turnieraufbau day: Thu start: '18:00' duration: 90 - class: Kinder + class: [Kinder, Turnier] - title: Kindertanz 0 day: Fri @@ -249,9 +253,10 @@ calendars: age: '2016 - 18' duration: 60 class: Kinder - - title: Kindertanz 2 (Turnieraufbau) + - title: Kindertanz 2 + subtitle: Turnieraufbau day: Fri start: '16:30' age: '' duration: 150 - class: Kinder + class: [Kinder, Turnier] diff --git a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/table.html b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/table.html index 05367e1..a556df7 100644 --- a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/table.html +++ b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/table.html @@ -12,6 +12,7 @@ {{- end -}} {{- end -}} {{- $cat := .Get "category" -}} +{{/* warnf "%#v" $cat */}} {{- $showAge := .Get "showAge" | default false -}} {{- $list = sort $list "start" -}} {{- $list = sort $list "title" -}} @@ -29,8 +30,10 @@ {{ range $list -}} - {{- if ne .class $cat }}{{ continue }}{{ end -}} - {{/* warnf "%#v" . */}} + {{- $cats := slice .class -}} + {{- if eq (printf "%T" .class) "[]interface {}" }}{{ $cats = .class }}{{ end -}} + {{- if not (in $cats $cat) }}{{ continue }}{{ end -}} + {{/* warnf "%T %#v" .class . */}} {{ .title }}{{ with .subtitle }} - {{ . }}{{ end }} From d9c7cc86e685987a305d11d06e2690f8193d3ea2 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Fri, 17 Jan 2025 17:00:13 +0100 Subject: [PATCH 20/34] Fix typo in Schedule data file --- data/schedule.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/data/schedule.yaml b/data/schedule.yaml index 8afa8e1..3338ba2 100644 --- a/data/schedule.yaml +++ b/data/schedule.yaml @@ -52,7 +52,6 @@ calendars: day: Wed start: '18:00' age: '2008 - 2010' - extern: false duration: 60 class: DSTeens - title: Turnieraufbau Std @@ -250,7 +249,7 @@ calendars: - title: Kindertanz 1 day: Fri start: '15:30' - age: '2016 - 18' + age: '2016 - 2018' duration: 60 class: Kinder - title: Kindertanz 2 From 48a5b852a1dfcb5ba00bbe13a1eb26a1107886d0 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Fri, 17 Jan 2025 17:24:39 +0100 Subject: [PATCH 21/34] Switch to dart SCSS --- themes/tsc_vfl/assets/css/main.scss | 22 +++++++++---------- .../tsc_vfl/layouts/partials/page/head.html | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/themes/tsc_vfl/assets/css/main.scss b/themes/tsc_vfl/assets/css/main.scss index 2a765bd..1e7f722 100644 --- a/themes/tsc_vfl/assets/css/main.scss +++ b/themes/tsc_vfl/assets/css/main.scss @@ -342,15 +342,16 @@ h1 { // height: 250px; display: none; - @include media-large { - display: flex; - } - padding: 0 10px; border-right: 20px solid $color-red; border-left: 20px solid $color-red; position: relative; + @include media-large { + display: flex; + } + + > img { width: calc(100% - 20px); @@ -525,15 +526,15 @@ h1 { .person { width: 100%; - @include media-large { - width: calc(50% - #{$gap-columns-persons} / 2); - } - height: 80px; // margin: 10px 25px 10px 0; display: flex; + @include media-large { + width: calc(50% - #{$gap-columns-persons} / 2); + } + > .image { flex: 60px 0 0; @@ -664,12 +665,11 @@ h1 { padding: 30px 5% 0; box-sizing: border-box; + border-top: 1px solid $color-hor-line; + @include media-large { display: none; } - - border-top: 1px solid $color-hor-line; - .level-1 { width: 100%; diff --git a/themes/tsc_vfl/layouts/partials/page/head.html b/themes/tsc_vfl/layouts/partials/page/head.html index 3546ad2..262eb32 100644 --- a/themes/tsc_vfl/layouts/partials/page/head.html +++ b/themes/tsc_vfl/layouts/partials/page/head.html @@ -11,7 +11,7 @@ {{ end }} {{ end }} {{ with .Keywords }}{{ end }} - {{ $options := (dict "targetPath" "main.css" "outputStyle" "compressed" "enableSourceMap" (not hugo.IsProduction)) }} + {{ $options := (dict "targetPath" "main.css" "outputStyle" "compressed" "enableSourceMap" (not hugo.IsProduction) "transpiler" "dartsass") }} {{ $scss := resources.Get "css/main.scss" | css.Sass $options }} {{ $title := print .Site.Title " | " .Title }} From 7fd921b66e20503b892d43854a9335b4785a2849 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Fri, 17 Jan 2025 17:27:44 +0100 Subject: [PATCH 22/34] Extract responsivity helpers in include --- themes/tsc_vfl/assets/css/_responsive.scss | 19 ++++++++++ themes/tsc_vfl/assets/css/main.scss | 41 +++++++++------------- 2 files changed, 35 insertions(+), 25 deletions(-) create mode 100644 themes/tsc_vfl/assets/css/_responsive.scss diff --git a/themes/tsc_vfl/assets/css/_responsive.scss b/themes/tsc_vfl/assets/css/_responsive.scss new file mode 100644 index 0000000..162825d --- /dev/null +++ b/themes/tsc_vfl/assets/css/_responsive.scss @@ -0,0 +1,19 @@ + +@mixin media-large { + @media screen and (min-width: 700px) { + @content; + } +} + +@mixin mouse-available { + @media screen and (pointer: fine) { + @content; + } +} + +@mixin mouse-available { + @media screen and (pointer: fine) { + @content; + } +} + diff --git a/themes/tsc_vfl/assets/css/main.scss b/themes/tsc_vfl/assets/css/main.scss index 1e7f722..3e00473 100644 --- a/themes/tsc_vfl/assets/css/main.scss +++ b/themes/tsc_vfl/assets/css/main.scss @@ -1,3 +1,5 @@ +@use 'responsive.scss' as r; + /* Variables */ $total-width: 95%; $color-red: #cd1013; @@ -23,17 +25,6 @@ $color-vh-hinten: #0082c9; } } -@mixin media-large { - @media screen and (min-width: 700px) { - @content; - } -} - -@mixin mouse-available { - @media screen and (pointer: fine) { - @content; - } -} /* main styling */ @@ -78,7 +69,7 @@ h1 { width: $left-menu-width; - @include media-large { + @include r.media-large { display: flex; } @@ -166,7 +157,7 @@ h1 { .calendar-manual { font-size: xx-small; - @include media-large { + @include r.media-large { font-size: small; } @@ -347,7 +338,7 @@ h1 { border-left: 20px solid $color-red; position: relative; - @include media-large { + @include r.media-large { display: flex; } @@ -407,7 +398,7 @@ h1 { font: 1.5em 'Open Sans Condensed', sans-serif; display: none; - @include media-large { + @include r.media-large { display: block; } @@ -531,7 +522,7 @@ h1 { // margin: 10px 25px 10px 0; display: flex; - @include media-large { + @include r.media-large { width: calc(50% - #{$gap-columns-persons} / 2); } @@ -588,7 +579,7 @@ h1 { margin-right: 2px; flex-direction: column; - @include media-large{ + @include r.media-large{ flex-direction: row; } @@ -597,7 +588,7 @@ h1 { display: block; height: 190px; - @include media-large{ + @include r.media-large{ flex: 33% 1 0; } @@ -667,7 +658,7 @@ h1 { border-top: 1px solid $color-hor-line; - @include media-large { + @include r.media-large { display: none; } @@ -717,7 +708,7 @@ h1 { @include menu-style; - @include media-large { + @include r.media-large { display: none; } } @@ -749,7 +740,7 @@ h1 { grid-template-columns: 1fr; gap: 15px; - @include media-large { + @include r.media-large { &.cols-2 { grid-template-columns: 1fr 1fr; } @@ -788,7 +779,7 @@ h1 { max-width: 70%; } - @include media-large { + @include r.media-large { display: flex; align-items: start; @@ -852,7 +843,7 @@ h1 { margin: 5px 0; align-items: baseline; - @include mouse-available { + @include r.mouse-available { margin: 0; } @@ -870,7 +861,7 @@ h1 { display: block; padding: 6.5px 0; - @include mouse-available { + @include r.mouse-available { padding: 3px 0; } } @@ -921,7 +912,7 @@ table.time { } } - @include media-large { + @include r.media-large { display: table; tr { From cee3597e258eaf221e70d700298cf74d9109b7c1 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Sun, 19 Jan 2025 10:33:57 +0100 Subject: [PATCH 23/34] WIP create calendar --- content/page/info/raumbelegung/index.md | 2 + themes/tsc_vfl/assets/css/_colors.scss | 9 + themes/tsc_vfl/assets/css/_schedule.scss | 223 ++++++++++++++++++ themes/tsc_vfl/assets/css/main.scss | 170 +++---------- .../layouts/partials/tsc/calendar/list.html | 18 ++ .../shortcodes/tsc/calendar/schedule.html | 118 +++++++++ .../shortcodes/tsc/calendar/table.html | 18 +- 7 files changed, 403 insertions(+), 155 deletions(-) create mode 100644 themes/tsc_vfl/assets/css/_colors.scss create mode 100644 themes/tsc_vfl/assets/css/_schedule.scss create mode 100644 themes/tsc_vfl/layouts/partials/tsc/calendar/list.html create mode 100644 themes/tsc_vfl/layouts/shortcodes/tsc/calendar/schedule.html diff --git a/content/page/info/raumbelegung/index.md b/content/page/info/raumbelegung/index.md index 9073d85..6bece4d 100644 --- a/content/page/info/raumbelegung/index.md +++ b/content/page/info/raumbelegung/index.md @@ -26,6 +26,8 @@ Weitere Infos zur Reservierung findest du unterhalb der Kalender. ## Raumbelegung - planmäßig +{{< tsc/calendar/schedule 10 22 "Mon" "Tue" "Wed" >}} + {{< tsc/show-calendar 10 22 "Mo" "Di" "Mi" >}} {{< tsc/show-calendar 10 22 "Do" "Fr" >}} diff --git a/themes/tsc_vfl/assets/css/_colors.scss b/themes/tsc_vfl/assets/css/_colors.scss new file mode 100644 index 0000000..7666b62 --- /dev/null +++ b/themes/tsc_vfl/assets/css/_colors.scss @@ -0,0 +1,9 @@ +$color-red: #cd1013; + +$color-background-mobile-menu: #f5f5f5; +$color-background-mobile-menu-header: #e0e0e0; +$color-hor-line: #a5a5a5; + +$color-vh-vorne: #ddcb55; +$color-vh-mitte: #c98879; +$color-vh-hinten: #0082c9; diff --git a/themes/tsc_vfl/assets/css/_schedule.scss b/themes/tsc_vfl/assets/css/_schedule.scss new file mode 100644 index 0000000..94a34e1 --- /dev/null +++ b/themes/tsc_vfl/assets/css/_schedule.scss @@ -0,0 +1,223 @@ +@use './responsive.scss' as r; +@use './colors.scss' as *; + +.calendar-schedule { + display: grid; + + .header { + display: contents; + font-weight: bold; + div { + justify-self: center; + } + .rooms { + display: flex; + width: 100%; + + div { + flex: 1 0 0; + text-align: center; + } + } + + .first-row { + grid-row: 1; + } + .second-row { + grid-row: 2; + } + } + + .times { + display: contents; + div { + height: 60px; + } + } + + .cal-main-content { + grid-row: 3 / 100; + position: relative; + + &.day-0 { + grid-column: 2; + } + &.day-1 { + grid-column: 3; + } + &.day-2 { + grid-column: 4; + } + // grid-column: 2; + + .event { + position: absolute; + + width: 30%; + // height: 100%; + box-sizing: border-box; + padding: 1px 0; + overflow: hidden; + + --fg-color: black; + + &.room-vorne { + --bg-color: var(--color-vhvorne); + left: 2.5%; + } + &.room-mitte { + --bg-color: var(--color-vhmitte); + left: 35% + } + &.room-hinten { + --bg-color: var(--color-vhhinten); + --fg-color: white; + left: 67.5%; + } + + div { + width: 100%; + height: 100%; + box-sizing: border-box; + padding: 3px; + border-radius: 4px; + + color: var(--fg-color); + background-color: var(--bg-color); + } + } + } + + .background { + display: contents; + + > * { + grid-column: 1 / -1; + min-height: 10px; + } + } +} + +.calendar-grid-2-days { + grid-template-columns: auto repeat(2, 1fr) auto; + + .cal-main-content { + // grid-column-end: span 2; + } +} + +.calendar-grid-3-days { + grid-template-columns: auto repeat(3, 1fr) auto; + + .cal-main-content { + // grid-column-end: span 3; + } +} + +// Legacy styling +.calendar-manual { + font-size: xx-small; + + @include r.media-large { + font-size: small; + } + + tr { + height: 20px; + + &.first-min { + border-top: solid lightgray 1px; + } + + &:nth-of-type(n) { + background-color: unset; + } + + .time { + vertical-align: top; + } + + .time:last-of-type, .first-col-of-room { + border-left: solid lightgray 1px; + } + + .day-title { + text-align: center; + } + } + + .calendar-block { + position: relative; + + .calendar-block-entity { + position: absolute; + top: 0; + left: 0; + width: 100%; + padding: 1.5px; + box-sizing: border-box; + + + &.height-1 { + height: 20px; + } + + &.height-2 { + height: 40px; + } + + &.height-3 { + height: 60px; + } + + &.height-4 { + height: 80px; + } + + &.height-5 { + height: 100px; + } + + &.height-6 { + height: 120px; + } + + &.height-7 { + height: 140px; + } + + &.height-8 { + height: 160px; + } + + &.height-9 { + height: 180px; + } + + &.height-10 { + height: 200px; + } + + .room-block { + width: 100%; + height: 100%; + box-sizing: border-box; + padding: 3px; + overflow: hidden; + } + + .room-vorne { + background-color: var(--color-vhvorne); + } + + .room-mitte { + background-color: var(--color-vhmitte); + } + + .room-hinten { + background-color: var(--color-vhhinten); + color: white; + } + } + } +} diff --git a/themes/tsc_vfl/assets/css/main.scss b/themes/tsc_vfl/assets/css/main.scss index 3e00473..7240868 100644 --- a/themes/tsc_vfl/assets/css/main.scss +++ b/themes/tsc_vfl/assets/css/main.scss @@ -1,16 +1,11 @@ @use 'responsive.scss' as r; +@use './schedule.scss'; +@use './colors.scss' as *; /* Variables */ $total-width: 95%; -$color-red: #cd1013; -$color-background-mobile-menu: #f5f5f5; -$color-background-mobile-menu-header: #e0e0e0; -$color-hor-line: #a5a5a5; $gap-columns-persons: 25px; $left-menu-width: 180px; -$color-vh-vorne: #ddcb55; -$color-vh-mitte: #c98879; -$color-vh-hinten: #0082c9; /* Mixins */ @@ -129,138 +124,10 @@ h1 { max-width: 100%; hyphens: auto; - table { - width: 100%; - border-collapse: collapse; - - td, th { - padding: 5px; - border: none; - text-align: left; - } - - tr { - background-color: #dedede; - - &:nth-of-type(2n) { - background-color: #f7f7f7; - } - } - - thead > tr { - background-color: $color-red; - color: white; - text-align: left; - } - } - - .calendar-manual { - font-size: xx-small; - - @include r.media-large { - font-size: small; - } - - tr { - height: 20px; - - &.first-min { - border-top: solid lightgray 1px; - } - - &:nth-of-type(n) { - background-color: unset; - } - - .time { - vertical-align: top; - } - - .time:last-of-type, .first-col-of-room { - border-left: solid lightgray 1px; - } - - .day-title { - text-align: center; - } - } - - .calendar-block { - position: relative; - - .calendar-block-entity { - position: absolute; - top: 0; - left: 0; - width: 100%; - padding: 1.5px; - box-sizing: border-box; - - - &.height-1 { - height: 20px; - } - - &.height-2 { - height: 40px; - } - - &.height-3 { - height: 60px; - } - - &.height-4 { - height: 80px; - } - - &.height-5 { - height: 100px; - } - - &.height-6 { - height: 120px; - } - - &.height-7 { - height: 140px; - } - - &.height-8 { - height: 160px; - } - - &.height-9 { - height: 180px; - } - - &.height-10 { - height: 200px; - } - - .room-block { - width: 100%; - height: 100%; - box-sizing: border-box; - padding: 3px; - overflow: hidden; - } - - .room-vorne { - background-color: var(--color-vhvorne); - } - - .room-mitte { - background-color: var(--color-vhmitte); - } - - .room-hinten { - background-color: var(--color-vhhinten); - color: white; - } - } - } - } + + // @include schedule.legacy; + .float-right { float: right; margin: 7px 0 7px 15px; @@ -299,6 +166,33 @@ h1 { } +table { + width: 100%; + border-collapse: collapse; + + td, th { + padding: 5px; + border: none; + text-align: left; + } + + tr { + background-color: #dedede; + + &:nth-of-type(2n) { + background-color: #f7f7f7; + } + } + + thead > tr { + background-color: $color-red; + color: white; + text-align: left; + } +} + +// @include schedule.legacy; + #header { border-bottom: 2px solid rgba(173, 173, 173, 50%); margin: 0 auto 30px; diff --git a/themes/tsc_vfl/layouts/partials/tsc/calendar/list.html b/themes/tsc_vfl/layouts/partials/tsc/calendar/list.html new file mode 100644 index 0000000..86cbb9b --- /dev/null +++ b/themes/tsc_vfl/layouts/partials/tsc/calendar/list.html @@ -0,0 +1,18 @@ +{{ $calendars := site.Data.schedule.calendars -}} +{{- $list := slice -}} +{{- range $room, $roomData := $calendars -}} + {{- if ($roomData.ignore | default false) -}}{{ continue }}{{- end -}} + {{- $roomName := $roomData.name | default $room -}} + {{/* warnf "%s " $room */}} + {{- range $roomData.schedule -}} + {{- $addData := dict "room" $roomName "roomId" $room "weight" 0 -}} + {{- $addData = merge $addData . -}} + {{/* warnf "%#v" $addData */}} + {{- $list = $list | append $addData -}} + {{- end -}} +{{- end -}} +{{- $list = sort $list "start" -}} +{{- $list = sort $list "title" -}} +{{- $list = sort $list "weight" -}} +{{/* warnf "%#v" $list */}} +{{- return $list -}} diff --git a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/schedule.html b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/schedule.html new file mode 100644 index 0000000..d53dc92 --- /dev/null +++ b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/schedule.html @@ -0,0 +1,118 @@ +{{- $start := .Get 0 -}} +{{- $end := .Get 1 -}} +{{- $days := after 2 .Params -}} +{{- $numDays := len $days -}} +{{- $calendar := $.Site.Data.calendar.calendar -}} +{{- $listSchedule := partialCached "tsc/calendar/list" . }} +
+
+
+ {{ range $days }} +
{{ . }}
+ {{ end }} +
+
+ {{ range $days }} +
+
Vorne
+
Mitte
+
Hinten
+
+ {{ end }} +
+
+
+ {{ range (seq $start $end) }} +
{{ printf "%2d:00" . }}
+
{{ printf "%2d:00" . }}
+ {{ end }} +
+ {{ range $id, $day := $days }} +
+ {{ range $listSchedule }} + {{- if ne .day $day }}{{ continue }}{{ end }} + {{- $sTime := time.AsTime (printf "2025-01-02T%s:00" .start) -}} + {{- $hours := int ($sTime.Format "15") -}} + {{- $minutes := int ($sTime.Format "4") -}} + {{/* warnf "%T" $hours */}} + {{ $hours = add $hours (sub 0 $start) (div $minutes 60.0) }} + {{/* print $hours */}} + {{/* $hours = $hours - 0 + ($minutes / 60.0) */}} + {{- $top := mul $hours 60 -}} + {{- $height := mul (div .duration 60.0) 60 -}} + {{- $style := printf "top: %1.0fpx; height: %1.0fpx;" $top $height -}} + {{/* warnf "%s" $style */}} +
+
+ {{ .title }} +
+
+ {{ end }} +
+ {{ end }} +
+ {{ range $idx, $val := (seq $start $end)}} +
+ {{ end }} +
+
+ + + + {{ range $days }} + + {{ end }} + + + + + {{ range $days }} + + + + {{ end }} + + + {{ range seq $start $end }} + {{ $hour := . }} + {{ range seq 0 15 45 }} + {{ $firstMin := "" }} + {{ if eq . 0 }} + {{ $firstMin = "first-min" }} + {{ end }} + + {{ $time := printf "%2d:%02d" $hour . }} + {{ if or (eq . 0) (eq . 30) }} + + {{ end }} + {{ range $days }} + {{ $day := . }} + {{ $firstRoom := true }} + {{ range slice "vorne" "mitte" "hinten" }} + {{ $room := . }} + {{ $addClass := "" }} + {{ if $firstRoom }} + {{ $addClass = "first-col-of-room" }} + {{ $firstRoom = false }} + {{ end }} + {{ with index (index (index $calendar .) $day) $time }} + + {{ else }} + + {{ end }} + {{ end }} + {{ end }} + {{ if or (eq . 0) (eq . 30) }} + {{ $time := printf "%2d.%02d" $hour . }} + + {{ end }} + + {{ end }} + {{ end }} +
{{ . }}
vornemittehinten
{{ $time }} +
+
+ {{ .title }} +
+
+
{{ $time }}
diff --git a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/table.html b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/table.html index a556df7..ecf0edc 100644 --- a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/table.html +++ b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/table.html @@ -1,23 +1,7 @@ -{{ $calendars := .Site.Data.schedule.calendars -}} -{{- $list := slice -}} -{{- range $room, $roomData := $calendars -}} - {{- if ($roomData.ignore | default false) -}}{{ continue }}{{- end -}} - {{- $roomName := $roomData.name | default $room -}} - {{/* warnf "%s " $room */}} - {{- range $roomData.schedule -}} - {{- $addData := dict "room" $roomName "weight" 0 -}} - {{- $addData = merge $addData . -}} - {{/* warnf "%#v" $addData */}} - {{- $list = $list | append $addData -}} - {{- end -}} -{{- end -}} +{{- $list := partialCached "tsc/calendar/list" . -}} {{- $cat := .Get "category" -}} {{/* warnf "%#v" $cat */}} {{- $showAge := .Get "showAge" | default false -}} -{{- $list = sort $list "start" -}} -{{- $list = sort $list "title" -}} -{{- $list = sort $list "weight" -}} -{{/* warnf "%#v" $list */}} From 9f8f8a96df8f71a88879488b2d799875455f14c0 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Sun, 19 Jan 2025 11:31:05 +0100 Subject: [PATCH 24/34] WIP first working solution (untested and not optimized) --- content/page/info/raumbelegung/index.md | 4 +- themes/tsc_vfl/assets/css/_responsive.scss | 5 - themes/tsc_vfl/assets/css/_schedule.scss | 76 ++++++++++--- .../shortcodes/tsc/calendar/schedule.html | 101 ++++++------------ 4 files changed, 98 insertions(+), 88 deletions(-) diff --git a/content/page/info/raumbelegung/index.md b/content/page/info/raumbelegung/index.md index 6bece4d..cd9baa3 100644 --- a/content/page/info/raumbelegung/index.md +++ b/content/page/info/raumbelegung/index.md @@ -19,7 +19,6 @@ Um die Verfügbarkeit für alle Mitglieder transparent zu halten und Überschnei Weitere Infos zur Reservierung findest du unterhalb der Kalender. -{{< tsc/iframe >}}https://cloud.tsc-vfl.de/index.php/apps/calendar/embed/d5KikZAZJfJxMHyK-RyoP44ym84oa5NFm-8DBYtgZwmkDsdemr/listYear/now{{< /tsc/iframe >}} {{}} @@ -29,6 +28,9 @@ Weitere Infos zur Reservierung findest du unterhalb der Kalender. {{< tsc/calendar/schedule 10 22 "Mon" "Tue" "Wed" >}} {{< tsc/show-calendar 10 22 "Mo" "Di" "Mi" >}} + +{{< tsc/calendar/schedule 10 22 "Thu" "Fri" >}} + {{< tsc/show-calendar 10 22 "Do" "Fr" >}} diff --git a/themes/tsc_vfl/assets/css/_responsive.scss b/themes/tsc_vfl/assets/css/_responsive.scss index 162825d..d086a8f 100644 --- a/themes/tsc_vfl/assets/css/_responsive.scss +++ b/themes/tsc_vfl/assets/css/_responsive.scss @@ -11,9 +11,4 @@ } } -@mixin mouse-available { - @media screen and (pointer: fine) { - @content; - } -} diff --git a/themes/tsc_vfl/assets/css/_schedule.scss b/themes/tsc_vfl/assets/css/_schedule.scss index 94a34e1..ae22b3c 100644 --- a/themes/tsc_vfl/assets/css/_schedule.scss +++ b/themes/tsc_vfl/assets/css/_schedule.scss @@ -1,9 +1,19 @@ @use './responsive.scss' as r; @use './colors.scss' as *; +$calendar-height-row: 60px; + .calendar-schedule { display: grid; + font-size: xx-small; + + @include r.media-large { + & { + font-size: x-small; + } + } + .header { display: contents; font-weight: bold; @@ -19,13 +29,6 @@ text-align: center; } } - - .first-row { - grid-row: 1; - } - .second-row { - grid-row: 2; - } } .times { @@ -35,6 +38,57 @@ } } + .table-row { + height: $calendar-height-row; + + border-top: solid lightgray 1px; + } + + .main-entry { + position: relative; + + .event { + position: absolute; + z-index: 1; + + top: calc($calendar-height-row * var(--minutes) / 60.0); + height: calc($calendar-height-row * var(--duration) / 60.0); + + width: 30%; + box-sizing: border-box; + padding: 1px 0; + // overflow: hidden; + + --fg-color: black; + + &.room-vorne { + --bg-color: var(--color-vhvorne); + left: 2.5%; + } + &.room-mitte { + --bg-color: var(--color-vhmitte); + left: 35% + } + &.room-hinten { + --bg-color: var(--color-vhhinten); + --fg-color: white; + left: 67.5%; + } + + div { + width: 100%; + height: 100%; + box-sizing: border-box; + padding: 3px; + border-radius: 4px; + + color: var(--fg-color); + background-color: var(--bg-color); + } + + } + } + .cal-main-content { grid-row: 3 / 100; position: relative; @@ -88,14 +142,6 @@ } } - .background { - display: contents; - - > * { - grid-column: 1 / -1; - min-height: 10px; - } - } } .calendar-grid-2-days { diff --git a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/schedule.html b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/schedule.html index d53dc92..d62bd30 100644 --- a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/schedule.html +++ b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/schedule.html @@ -21,7 +21,39 @@ {{ end }}
-
+ {{ range (seq $start $end) }} + {{- $currentHour := string . -}} + {{- $addClass := "" -}} + {{- $firstRow := eq . $start -}} + {{- if eq . $start }}{{ $addClass = "first-main-row"}}{{ end -}} + {{ warnf "Current hour: %s (%T)" $currentHour $currentHour }} +
{{ printf "%2d:00" . }}
+ {{- range $id, $day := $days }} +
+ {{- range $listSchedule }} + {{- if ne .day $day }}{{ continue }}{{ end -}} + {{- $sTime := time.AsTime (printf "2025-01-02T%s:00" .start) -}} + {{- $evHour := $sTime.Format "15" -}} + {{- if ne $currentHour $evHour }}{{ continue }}{{ end -}} + {{- $hours := int ($sTime.Format "15") -}} + {{- $minutes := int ($sTime.Format "4") -}} + {{/* warnf "%T" $hours */}} + {{/* $hours = add $hours (sub 0 $start) (div $minutes 60.0) */}} + {{/* print $hours */}} + {{/* $hours = $hours - 0 + ($minutes / 60.0) */}} + {{- $style := printf "--duration: %d; --minutes: %d;" .duration $minutes -}} + {{/* warnf "%s" $style */}} +
+
+ {{ .title }} +
+
+ {{ end -}} +
+ {{ end -}} +
{{ printf "%2d:00" . }}
+ {{ end }} +
-
- - - {{ range $days }} - - {{ end }} - - - - - {{ range $days }} - - - - {{ end }} - - - {{ range seq $start $end }} - {{ $hour := . }} - {{ range seq 0 15 45 }} - {{ $firstMin := "" }} - {{ if eq . 0 }} - {{ $firstMin = "first-min" }} - {{ end }} - - {{ $time := printf "%2d:%02d" $hour . }} - {{ if or (eq . 0) (eq . 30) }} - - {{ end }} - {{ range $days }} - {{ $day := . }} - {{ $firstRoom := true }} - {{ range slice "vorne" "mitte" "hinten" }} - {{ $room := . }} - {{ $addClass := "" }} - {{ if $firstRoom }} - {{ $addClass = "first-col-of-room" }} - {{ $firstRoom = false }} - {{ end }} - {{ with index (index (index $calendar .) $day) $time }} - - {{ else }} - - {{ end }} - {{ end }} - {{ end }} - {{ if or (eq . 0) (eq . 30) }} - {{ $time := printf "%2d.%02d" $hour . }} - - {{ end }} - - {{ end }} - {{ end }} -
{{ . }}
vornemittehinten
{{ $time }} -
-
- {{ .title }} -
-
-
{{ $time }}
From 9d21f14959104b7c04f60a3d84a22163d2856468 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Mon, 20 Jan 2025 09:08:41 +0100 Subject: [PATCH 25/34] Clean up code a bit and remove old implementation --- content/page/info/raumbelegung/index.md | 6 +- themes/tsc_vfl/assets/css/_schedule.scss | 203 ++---------------- .../shortcodes/tsc/calendar/schedule.html | 50 +---- .../layouts/shortcodes/tsc/show-calendar.html | 64 ------ 4 files changed, 32 insertions(+), 291 deletions(-) delete mode 100644 themes/tsc_vfl/layouts/shortcodes/tsc/show-calendar.html diff --git a/content/page/info/raumbelegung/index.md b/content/page/info/raumbelegung/index.md index cd9baa3..0b35c00 100644 --- a/content/page/info/raumbelegung/index.md +++ b/content/page/info/raumbelegung/index.md @@ -27,11 +27,7 @@ Weitere Infos zur Reservierung findest du unterhalb der Kalender. {{< tsc/calendar/schedule 10 22 "Mon" "Tue" "Wed" >}} -{{< tsc/show-calendar 10 22 "Mo" "Di" "Mi" >}} - -{{< tsc/calendar/schedule 10 22 "Thu" "Fri" >}} - -{{< tsc/show-calendar 10 22 "Do" "Fr" >}} +{{< tsc/calendar/schedule 14 22 "Thu" "Fri" >}} ## Regeln für die Belegung der Tanzsäle diff --git a/themes/tsc_vfl/assets/css/_schedule.scss b/themes/tsc_vfl/assets/css/_schedule.scss index ae22b3c..592b0f7 100644 --- a/themes/tsc_vfl/assets/css/_schedule.scss +++ b/themes/tsc_vfl/assets/css/_schedule.scss @@ -1,16 +1,19 @@ @use './responsive.scss' as r; @use './colors.scss' as *; -$calendar-height-row: 60px; .calendar-schedule { + $calendar-height-row: 60px; + + $border-style: solid lightgray 1px; + display: grid; font-size: xx-small; @include r.media-large { & { - font-size: x-small; + font-size: small; } } @@ -18,7 +21,9 @@ $calendar-height-row: 60px; display: contents; font-weight: bold; div { - justify-self: center; + width: 100%; + text-align: center; + box-sizing: border-box; } .rooms { display: flex; @@ -29,24 +34,31 @@ $calendar-height-row: 60px; text-align: center; } } - } - - .times { - display: contents; - div { - height: 60px; + .main-column { + border-right: $border-style; } } .table-row { height: $calendar-height-row; + box-sizing: border-box; - border-top: solid lightgray 1px; + border-top: $border-style; + } + + .times-left { + border-right: $border-style; + } + .times-left, .times-right{ + width: 100%; + padding: 0 5px; } .main-entry { position: relative; + border-right: $border-style; + .event { position: absolute; z-index: 1; @@ -55,62 +67,8 @@ $calendar-height-row: 60px; height: calc($calendar-height-row * var(--duration) / 60.0); width: 30%; - box-sizing: border-box; padding: 1px 0; - // overflow: hidden; - - --fg-color: black; - - &.room-vorne { - --bg-color: var(--color-vhvorne); - left: 2.5%; - } - &.room-mitte { - --bg-color: var(--color-vhmitte); - left: 35% - } - &.room-hinten { - --bg-color: var(--color-vhhinten); - --fg-color: white; - left: 67.5%; - } - - div { - width: 100%; - height: 100%; - box-sizing: border-box; - padding: 3px; - border-radius: 4px; - - color: var(--fg-color); - background-color: var(--bg-color); - } - - } - } - - .cal-main-content { - grid-row: 3 / 100; - position: relative; - - &.day-0 { - grid-column: 2; - } - &.day-1 { - grid-column: 3; - } - &.day-2 { - grid-column: 4; - } - // grid-column: 2; - - .event { - position: absolute; - - width: 30%; - // height: 100%; box-sizing: border-box; - padding: 1px 0; overflow: hidden; --fg-color: black; @@ -139,131 +97,16 @@ $calendar-height-row: 60px; color: var(--fg-color); background-color: var(--bg-color); } + } } - } .calendar-grid-2-days { grid-template-columns: auto repeat(2, 1fr) auto; - - .cal-main-content { - // grid-column-end: span 2; - } } .calendar-grid-3-days { grid-template-columns: auto repeat(3, 1fr) auto; - - .cal-main-content { - // grid-column-end: span 3; - } } -// Legacy styling -.calendar-manual { - font-size: xx-small; - - @include r.media-large { - font-size: small; - } - - tr { - height: 20px; - - &.first-min { - border-top: solid lightgray 1px; - } - - &:nth-of-type(n) { - background-color: unset; - } - - .time { - vertical-align: top; - } - - .time:last-of-type, .first-col-of-room { - border-left: solid lightgray 1px; - } - - .day-title { - text-align: center; - } - } - - .calendar-block { - position: relative; - - .calendar-block-entity { - position: absolute; - top: 0; - left: 0; - width: 100%; - padding: 1.5px; - box-sizing: border-box; - - - &.height-1 { - height: 20px; - } - - &.height-2 { - height: 40px; - } - - &.height-3 { - height: 60px; - } - - &.height-4 { - height: 80px; - } - - &.height-5 { - height: 100px; - } - - &.height-6 { - height: 120px; - } - - &.height-7 { - height: 140px; - } - - &.height-8 { - height: 160px; - } - - &.height-9 { - height: 180px; - } - - &.height-10 { - height: 200px; - } - - .room-block { - width: 100%; - height: 100%; - box-sizing: border-box; - padding: 3px; - overflow: hidden; - } - - .room-vorne { - background-color: var(--color-vhvorne); - } - - .room-mitte { - background-color: var(--color-vhmitte); - } - - .room-hinten { - background-color: var(--color-vhhinten); - color: white; - } - } - } -} diff --git a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/schedule.html b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/schedule.html index d62bd30..c7e41c6 100644 --- a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/schedule.html +++ b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/schedule.html @@ -6,28 +6,27 @@ {{- $listSchedule := partialCached "tsc/calendar/list" . }}
-
+
{{ range $days }} -
{{ . }}
+
{{ . }}
{{ end }} -
-
+
+
{{ range $days }} -
+
Vorne
Mitte
Hinten
{{ end }} -
+
{{ range (seq $start $end) }} {{- $currentHour := string . -}} {{- $addClass := "" -}} {{- $firstRow := eq . $start -}} {{- if eq . $start }}{{ $addClass = "first-main-row"}}{{ end -}} - {{ warnf "Current hour: %s (%T)" $currentHour $currentHour }} -
{{ printf "%2d:00" . }}
+
{{ printf "%2d:00" . }}
{{- range $id, $day := $days }}
{{- range $listSchedule }} @@ -37,10 +36,6 @@ {{- if ne $currentHour $evHour }}{{ continue }}{{ end -}} {{- $hours := int ($sTime.Format "15") -}} {{- $minutes := int ($sTime.Format "4") -}} - {{/* warnf "%T" $hours */}} - {{/* $hours = add $hours (sub 0 $start) (div $minutes 60.0) */}} - {{/* print $hours */}} - {{/* $hours = $hours - 0 + ($minutes / 60.0) */}} {{- $style := printf "--duration: %d; --minutes: %d;" .duration $minutes -}} {{/* warnf "%s" $style */}}
@@ -51,35 +46,6 @@ {{ end -}}
{{ end -}} -
{{ printf "%2d:00" . }}
+
{{ printf "%2d:00" . }}
{{ end }} -
diff --git a/themes/tsc_vfl/layouts/shortcodes/tsc/show-calendar.html b/themes/tsc_vfl/layouts/shortcodes/tsc/show-calendar.html deleted file mode 100644 index 5b307ea..0000000 --- a/themes/tsc_vfl/layouts/shortcodes/tsc/show-calendar.html +++ /dev/null @@ -1,64 +0,0 @@ -{{ $start := .Get 0 }} -{{ $end := .Get 1}} -{{ $days := after 2 .Params }} -{{ $calendar := $.Site.Data.calendar.calendar }} - - - - {{ range $days }} - - {{ end }} - - - - - {{ range $days }} - - - - {{ end }} - - - {{ range seq $start $end }} - {{ $hour := . }} - {{ range seq 0 15 45 }} - {{ $firstMin := "" }} - {{ if eq . 0 }} - {{ $firstMin = "first-min" }} - {{ end }} - - {{ $time := printf "%2d:%02d" $hour . }} - {{ if or (eq . 0) (eq . 30) }} - - {{ end }} - {{ range $days }} - {{ $day := . }} - {{ $firstRoom := true }} - {{ range slice "vorne" "mitte" "hinten" }} - {{ $room := . }} - {{ $addClass := "" }} - {{ if $firstRoom }} - {{ $addClass = "first-col-of-room" }} - {{ $firstRoom = false }} - {{ end }} - {{ with index (index (index $calendar .) $day) $time }} - - {{ else }} - - {{ end }} - {{ end }} - {{ end }} - {{ if or (eq . 0) (eq . 30) }} - {{ $time := printf "%2d.%02d" $hour . }} - - {{ end }} - - {{ end }} - {{ end }} -
{{ . }}
vornemittehinten
{{ $time }} -
-
- {{ .title }} -
-
-
{{ $time }}
From 9ffc10b7e3c371eca9f6384a4c9c177e525dadbe Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Mon, 20 Jan 2025 09:09:21 +0100 Subject: [PATCH 26/34] Revert bug in WIP commit 9f8f8a96 --- content/page/info/raumbelegung/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/content/page/info/raumbelegung/index.md b/content/page/info/raumbelegung/index.md index 0b35c00..7eca2c9 100644 --- a/content/page/info/raumbelegung/index.md +++ b/content/page/info/raumbelegung/index.md @@ -19,6 +19,7 @@ Um die Verfügbarkeit für alle Mitglieder transparent zu halten und Überschnei Weitere Infos zur Reservierung findest du unterhalb der Kalender. +{{< tsc/iframe >}}https://cloud.tsc-vfl.de/index.php/apps/calendar/embed/d5KikZAZJfJxMHyK-RyoP44ym84oa5NFm-8DBYtgZwmkDsdemr/listYear/now{{< /tsc/iframe >}} {{}} From 4f58efec81d4aea6ba04beb5daac633af32b148b Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Mon, 20 Jan 2025 12:40:09 +0100 Subject: [PATCH 27/34] Make "Raumbelegung" a branch bundle --- content/page/info/raumbelegung/{index.md => _index.md} | 1 + 1 file changed, 1 insertion(+) rename content/page/info/raumbelegung/{index.md => _index.md} (99%) diff --git a/content/page/info/raumbelegung/index.md b/content/page/info/raumbelegung/_index.md similarity index 99% rename from content/page/info/raumbelegung/index.md rename to content/page/info/raumbelegung/_index.md index 7eca2c9..ca916be 100644 --- a/content/page/info/raumbelegung/index.md +++ b/content/page/info/raumbelegung/_index.md @@ -11,6 +11,7 @@ aliases: --- Hier finden Sie die Übersicht zur aktuellen Belegung unserer Tanzsäle. + ## Raumbelegung - außerplanmäßig Außerhalb der Trainings- und Kurszeiten können die Räume für spezielle (Gruppen-) Trainings gebucht werden. From 8950c22db02e2689921995d3cf70dff2a7671a69 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Mon, 20 Jan 2025 12:40:23 +0100 Subject: [PATCH 28/34] Set default language to DE --- hugo.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/hugo.yaml b/hugo.yaml index 8a0bc62..0344833 100644 --- a/hugo.yaml +++ b/hugo.yaml @@ -1,5 +1,6 @@ baseURL: https://tanzsportclub.vfl-sindelfingen.de/ languageCode: de +defaultContentLanguage: de title: TSC im VfL Sindelfingen e.V. theme: tsc_vfl relativeUrls: true From b112a13c7e8f5e4a50c3e43e3edf60f4c73e1ba5 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Mon, 20 Jan 2025 12:41:37 +0100 Subject: [PATCH 29/34] Create list of all configured room occupations --- content/page/info/raumbelegung/liste.md | 13 ++++++ .../layouts/shortcodes/tsc/calendar/list.html | 40 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 content/page/info/raumbelegung/liste.md create mode 100644 themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html diff --git a/content/page/info/raumbelegung/liste.md b/content/page/info/raumbelegung/liste.md new file mode 100644 index 0000000..6de9491 --- /dev/null +++ b/content/page/info/raumbelegung/liste.md @@ -0,0 +1,13 @@ +--- +title: Raumbelegungs Liste +date: 2025-01-20T09:02:00 +draft: false +build: + list: local + # render: never +--- + +Auf dieser Seite werden die Angebote des Vereins noch einmal zusammen gefasst. +Dies dient der internen Kontrolle im Verein. + +{{< tsc/calendar/list >}} diff --git a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html new file mode 100644 index 0000000..714d1e4 --- /dev/null +++ b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html @@ -0,0 +1,40 @@ +{{- $list := partialCached "tsc/calendar/list" . -}} +{{- $list = sort $list "weight" -}} +{{- $list = sort $list "start" -}} +{{- $list = sort $list "class" -}} +{{- $list = sort $list "title" -}} + + + + + + + + + + + + + {{ range $list -}} + + + + + + + + + {{- end}} + +
GruppeKategorieJahrgangTagZeitOrt
+ {{ .title }}{{ with .subtitle }} - {{ . }}{{ end }} + + {{ with .class }}{{ . }}{{ end }} + {{ with .age }}{{ . }}{{ end }}{{ index site.Data.days .day }} + {{- $startTimeStr := printf "2025-01-02T%s:00" .start -}} + {{- $startTime := time.AsTime $startTimeStr -}} + {{- $duration := time.Duration "minute" .duration -}} + {{- $endTime := $startTime.Add $duration}} + {{/* warnf "Start %s, duration %s, %s" $startTime $duration $endTime */}} + {{- $startTime.Format "15:04"}} - {{ $endTime.Format "15:04" }} + {{ .room }}
From 8d6ae5f445829558001252b3d7065aec8861b9a8 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Mon, 20 Jan 2025 12:43:03 +0100 Subject: [PATCH 30/34] Drop old calendar data file --- data/calendar.yaml | 145 --------------------------------------------- 1 file changed, 145 deletions(-) delete mode 100644 data/calendar.yaml diff --git a/data/calendar.yaml b/data/calendar.yaml deleted file mode 100644 index 946656d..0000000 --- a/data/calendar.yaml +++ /dev/null @@ -1,145 +0,0 @@ -calendar: - vorne: - Mo: - "17:00": - title: DS-Kids 6 - slots: 4 - "18:15": - title: DS Adults 5 - slots: 4 - "19:15": - title: DS Contest Gruppe - slots: 6 - Di: - "16:30": - title: DS Kids 4 - slots: 4 - "17:45": - title: DS Kids 0 - slots: 4 - "18:45": - title: DS Adults 1 - slots: 6 - Mi: - "17:00": - title: DS Kids 2 - slots: 4 - "18:00": - title: DS Teens 0 - slots: 4 - "20:30": - title: Turnieraufbau Std - slots: 6 - Do: - "17:00": - title: DS Kids 5 - slots: 4 - "18:30": - title: DS Kids 1 - slots: 4 - "19:30": - title: DS Adults 3 - slots: 4 - Fr: - "16:30": - title: DS Minis 0 - slots: 4 - "19:00": - title: Tanzkreis 0 - slots: 6 - "20:30": - title: Discofox - slots: 4 - # Sa: {} - # So: {} - mitte: - Mo: - "17:30": - title: DS Teens 2 - slots: 4 - "18:30": - title: Ballet - slots: 6 - "20:00": - title: Tanzkreis 1 - slots: 6 - Di: - "20:00": - title: Tanzkreis 2 - slots: 8 - Mi: - "18:00": - title: DS Kids 7 - slots: 4 - "19:00": - title: Tanzkreis 3 - slots: 6 - "20:30": - title: Tanzkreis 4 - slots: 6 - Do: - "16:45": - title: DS Minis 1 - slots: 4 - "19:30": - title: Tanzkreis 5 - slots: 6 - Fr: - "18:30": - title: Tanzkreis 6 - Einsteiger - slots: 2 - "19:00": - title: Tanzkreis 6 - slots: 6 - "20:30": - title: Tanzkreis 9 - slots: 6 - Sa: {} - So: {} - hinten: - Mo: - "16:00": - title: Ballet - slots: 6 - # "18:15": - # title: DS Adults 5 - # slots: 4 - Di: - "19:00": - title: Turnier Latein - slots: 4 - "20:00": - title: Turnier Standard - slots: 8 - Mi: - "10:30": - title: Ballet - slots: 6 - "16:45": - title: DS Kids 3 - slots: 4 - "18:00": - title: DS Teens 1 - slots: 4 - "19:00": - title: DS Adults 0 - slots: 4 - "20:00": - title: Breitensport - slots: 6 - Do: - "18:00": - title: Kindertanz 8 (Turnieraufbau) - slots: 6 - Fr: - "14:30": - title: Kindertanz 0 - slots: 4 - "15:30": - title: Kindertanz 1 - slots: 4 - "16:30": - title: Kindertanz 2 (Turnieraufbau) - slots: 10 - Sa: {} - So: {} From e3549c3ff49e0fb6de8e24618d985c0560cf2305 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Mon, 20 Jan 2025 13:27:43 +0100 Subject: [PATCH 31/34] Include external marker for list of appointments --- themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html | 1 + 1 file changed, 1 insertion(+) diff --git a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html index 714d1e4..1b29d31 100644 --- a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html +++ b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html @@ -19,6 +19,7 @@ {{ .title }}{{ with .subtitle }} - {{ . }}{{ end }} + {{ if (.extern | default false) }}(ext.){{ end }} {{ with .class }}{{ . }}{{ end }} From fd8cb30b4a5cece27bfb28e119a7456c323d5ef1 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Mon, 20 Jan 2025 13:51:21 +0100 Subject: [PATCH 32/34] Group list by class --- .../layouts/shortcodes/tsc/calendar/list.html | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html index 1b29d31..30dfec6 100644 --- a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html +++ b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html @@ -3,6 +3,9 @@ {{- $list = sort $list "start" -}} {{- $list = sort $list "class" -}} {{- $list = sort $list "title" -}} +{{- $cals := apply $list "index" "." "class" -}} +{{- $cals = uniq $cals -}} +{{ warnf "%s" $cals}} @@ -39,3 +42,42 @@ {{- end}}
+ +{{ range $cals }} +{{- $class := . -}} +

Class {{ with . }}{{ . }}{{else}}nil{{end}}

+ + + + + + + + + + + + + {{ range $list -}} + {{- if ne .class $class }}{{ continue }}{{ end }} + + + + + + + + {{- end}} + +
GruppeJahrgangTagZeitOrt
+ {{ .title }}{{ with .subtitle }} - {{ . }}{{ end }} + {{ if (.extern | default false) }}(ext.){{ end }} + {{ with .age }}{{ . }}{{ end }}{{ index site.Data.days .day }} + {{- $startTimeStr := printf "2025-01-02T%s:00" .start -}} + {{- $startTime := time.AsTime $startTimeStr -}} + {{- $duration := time.Duration "minute" .duration -}} + {{- $endTime := $startTime.Add $duration}} + {{/* warnf "Start %s, duration %s, %s" $startTime $duration $endTime */}} + {{- $startTime.Format "15:04"}} - {{ $endTime.Format "15:04" }} + {{ .room }}
+{{ end }} From bdf6a8794f695feebdfe0a01ce0746e482dc21b7 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Mon, 20 Jan 2025 13:58:35 +0100 Subject: [PATCH 33/34] Switch to live calendar ids --- data/schedule.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/schedule.yaml b/data/schedule.yaml index 3338ba2..fc41a07 100644 --- a/data/schedule.yaml +++ b/data/schedule.yaml @@ -1,6 +1,6 @@ calendars: vorne: - id: test1 + id: "vh-vorne-regeltermine_shared_by_tsc" ignore: false name: VH Vorn schedule: @@ -99,7 +99,7 @@ calendars: class: Discofox mitte: - id: test2 + id: "vh-mitte-regeltermine_shared_by_tsc" name: VH Mitte ignore: false schedule: @@ -176,7 +176,7 @@ calendars: class: Tanzkreise hinten: - id: test3 + id: "vh-hinten-regeltermine_shared_by_tsc" name: VH Hinten ignore: false schedule: From 6d562769478b23703c8644622514357049ad5cce Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Mon, 20 Jan 2025 14:07:14 +0100 Subject: [PATCH 34/34] Prevent debugging warning in output --- themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html index 30dfec6..cf8e880 100644 --- a/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html +++ b/themes/tsc_vfl/layouts/shortcodes/tsc/calendar/list.html @@ -5,7 +5,7 @@ {{- $list = sort $list "title" -}} {{- $cals := apply $list "index" "." "class" -}} {{- $cals = uniq $cals -}} -{{ warnf "%s" $cals}} +{{/* warnf "%s" $cals */}}