Compare commits
587 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bb8e1c0f6e | |||
| cf94020210 | |||
|
8fa7acd918
|
|||
|
b18d378577
|
|||
|
579e4f09f5
|
|||
|
35c7f56b80
|
|||
|
9d37fbead5
|
|||
|
07d132575a
|
|||
|
00d542ca59
|
|||
|
11c1a1eb78
|
|||
|
4158a776fd
|
|||
|
c4a86060b7
|
|||
| aa8adfc6a4 | |||
| aa1bdd6996 | |||
|
3a8f82b12a
|
|||
|
6c9284b8f6
|
|||
|
2a20a1b4eb
|
|||
|
f3c13b1aee
|
|||
|
c997ad4b47
|
|||
|
d5d8937365
|
|||
|
ceb9b51756
|
|||
|
f163ed3a2f
|
|||
|
bdea5cf182
|
|||
|
280833253c
|
|||
|
cefd8640b5
|
|||
|
5a25087d32
|
|||
|
bde2e88273
|
|||
|
597aaf413a
|
|||
|
a5e3ac6308
|
|||
|
83ce4792e2
|
|||
|
9c645fdb0e
|
|||
|
7f706ccd2a
|
|||
|
2e7acb7a9a
|
|||
|
9e2fab0ea2
|
|||
|
189324b87e
|
|||
|
9f81ae0b8a
|
|||
|
167dd77107
|
|||
|
cc8adf3f84
|
|||
|
73aee17ae3
|
|||
|
2f0e4b2d83
|
|||
|
b67cbd6503
|
|||
|
32ba9c11f7
|
|||
|
b9992c7c57
|
|||
|
346cb433ac
|
|||
|
5279c588d5
|
|||
|
e84236c84b
|
|||
|
8f4dfc992e
|
|||
|
1766cc23d6
|
|||
|
044444eaa8
|
|||
|
16c9b610ce
|
|||
|
65118b6abe
|
|||
|
75226f8314
|
|||
|
1a4676d85d
|
|||
|
08a216f447
|
|||
|
31b7026867
|
|||
|
961f021d27
|
|||
|
158e816ed0
|
|||
|
42cb584ef4
|
|||
|
1eabf809f0
|
|||
|
bb5b013d31
|
|||
|
a366769fb9
|
|||
|
19c49b4a00
|
|||
|
3d07547f80
|
|||
|
fc8ca571fb
|
|||
|
6fd4a0599c
|
|||
|
f782d20e56
|
|||
|
0a77f46fe1
|
|||
|
ed720af80b
|
|||
|
f8acc4b815
|
|||
| da1113341a | |||
| cd31bd4476 | |||
| 77e5d336eb | |||
| 403afdc472 | |||
| 86816489e3 | |||
| c38c502598 | |||
| 3d843667ad | |||
| 617a799ad8 | |||
| 0be8e51af4 | |||
| 381f67189a | |||
| 2e56c7aed4 | |||
| 5b7a04dc69 | |||
| 485110bf43 | |||
| 3498cb7d8e | |||
| ed3f307b9b | |||
| 7070a12e16 | |||
| 6bda1a91bd | |||
| 559b7ec03b | |||
| 602ae1f396 | |||
| f3c439d038 | |||
| 2b3a9dd6ec | |||
| 59b071d8be | |||
| f732582d0d | |||
| de72342018 | |||
| b54bbda71f | |||
|
20bab54235
|
|||
|
c3d8ce017d
|
|||
|
02cfe9feaa
|
|||
|
4d4ec78ea3
|
|||
|
a74ea31356
|
|||
|
0653672a17
|
|||
|
8a1ff1a265
|
|||
|
c1802e7cf2
|
|||
|
84de16fc25
|
|||
|
23b8e91a6c
|
|||
|
da8afe735c
|
|||
|
b6697e5750
|
|||
|
ece3c8ab80
|
|||
|
7297c83cea
|
|||
|
74662af3ef
|
|||
|
32e147fd02
|
|||
|
d5c28d4e0f
|
|||
|
f1b3c63311
|
|||
| a4ebe6ded0 | |||
| 2930f9863f | |||
| e7b66b4bc6 | |||
| c62f4d4705 | |||
| 814e5bc6c7 | |||
|
f57edf60c1
|
|||
| a29d3fe803 | |||
| 8bcadd1d2d | |||
| 8a82e2795c | |||
| 4ee8b73044 | |||
| 6580cfe546 | |||
|
a0f9e71d46
|
|||
| 6e4a79ed3d | |||
| ce99b309f8 | |||
| 37445f42b5 | |||
| 9717c11af5 | |||
| 2cab4df4b1 | |||
| 18c8426246 | |||
|
4890a0af04
|
|||
| 7bf2c31db3 | |||
| 13a6df92ce | |||
|
f87c6820d7
|
|||
|
592c6d46c4
|
|||
| 9d9d99e6ba | |||
| 216e153f89 | |||
| d528df5f99 | |||
| faf93cc45a | |||
| 1aa4f4fc8a | |||
| f1958d9afc | |||
| 7f269f05d6 | |||
| 7e158c9fc3 | |||
| d79cd3ad37 | |||
| f5a6868301 | |||
| 310246dd20 | |||
| 151a0d44f6 | |||
| 10c70e89f6 | |||
| 318e9cfe6b | |||
| 1f60b80b98 | |||
| 517f39eee9 | |||
| 2f6553225a | |||
| 1eb84eaec8 | |||
| 3e1a21741f | |||
| da6c1963f8 | |||
| 0da5d44ea1 | |||
| 133c4e269d | |||
| 850c8da95a | |||
| 1ae6356aa5 | |||
| fa4fa9ad7d | |||
| d43e5faf3c | |||
| 57055c9c6f | |||
| 5fbc1dbc00 | |||
| e364a5fee0 | |||
| a4a6553329 | |||
|
ae81d269fa
|
|||
| 31d9a955df | |||
| 6bd3ce7731 | |||
| 9f45271b18 | |||
| 567962c947 | |||
| 7defd8b388 | |||
| a7f2c4f2d3 | |||
| 847fe67534 | |||
| 79854aee6f | |||
| 699876405c | |||
| a734fe6bd3 | |||
| c33736a501 | |||
| 3a39ca0f73 | |||
| d8f8aafdd9 | |||
| 79ffb1fff5 | |||
| 29c4c67645 | |||
| 98da6ada23 | |||
| 1c1656c3bc | |||
| c489f303ea | |||
| fc0286c277 | |||
| f4407fde4a | |||
| 9f11d442fe | |||
| 1bc41124c0 | |||
| 72fb9e9915 | |||
| b555f915a0 | |||
| 4b9957e9c5 | |||
| b42214b404 | |||
| fcef05d439 | |||
| 0f8b15715b | |||
| 8a79d9d016 | |||
| f507b0cddd | |||
| 0b25f8d54a | |||
| 4f504e9456 | |||
| 1f32c03d86 | |||
| fc6d5d5f8e | |||
| 1cde0a2a93 | |||
| 65c0bad9b0 | |||
| 9fa6066724 | |||
| a506dc44cc | |||
| a80114be7a | |||
| ab6edd92e1 | |||
| 6070cf4bd3 | |||
| fdd1d12e9e | |||
| 6cae4cb0e2 | |||
| 15c9431c10 | |||
| 500ea63c77 | |||
| bbe51e702b | |||
| ab1bbdd3df | |||
| 893f57c9b7 | |||
| 184d40266b | |||
| 516287ee85 | |||
| 3335f5958e | |||
| a7d7ce4da0 | |||
| 1711ce2e5d | |||
| 31e104a150 | |||
| c57276b779 | |||
| 9e7436684c | |||
| a500b5eecc | |||
| fb5b66f12b | |||
| e7f9799285 | |||
| 25212940dd | |||
| a1d56570b1 | |||
| 15f2154f6a | |||
| 6b81b0785f | |||
| 6b243ad91b | |||
| 63e49417a7 | |||
| 6c891b3f79 | |||
| a4ce890a36 | |||
| 2ba0266fca | |||
| 9f3812b8a5 | |||
| a9ee7cd6f7 | |||
| 1c4eb5cfe4 | |||
| 9162ee70a7 | |||
| bdbab5be9e | |||
| 0d87d37c72 | |||
| 728f8a6179 | |||
| 8fd03c9824 | |||
| fdbbaee175 | |||
| 9dad49738c | |||
| 0336236fda | |||
| 9a5e444041 | |||
| cfeba9f8da | |||
| 9691433917 | |||
| db6af95063 | |||
| cd1792c130 | |||
| dc99df21c2 | |||
| ecf40334e4 | |||
| e1686cd8c5 | |||
| 06bfa81d6e | |||
| 5ade47f6dd | |||
| 7b237f1656 | |||
| 80198d0d98 | |||
| 3c24435688 | |||
| b50a4a7ad4 | |||
| 523b30d6f5 | |||
| 06e530061d | |||
| c0c324217c | |||
| 9b3735ea75 | |||
| 9997b8fca9 | |||
| 27986e0b1d | |||
| fe129fe1b0 | |||
| e08b23be05 | |||
| 089b34833b | |||
| 995b8d7ae7 | |||
| d248c94a3d | |||
| d3584dae44 | |||
| a45eaab050 | |||
| c6795dc1bf | |||
| d1734e8762 | |||
| 69582db88f | |||
| 66eb6f0907 | |||
| 74e86ded33 | |||
| ea7c33cb8e | |||
| 5ad772fc26 | |||
| 39126936b0 | |||
| c549890b7e | |||
| 09d5ebc249 | |||
| ead8f3a19c | |||
| c3ada63c69 | |||
| eb39821f20 | |||
| 59463ebdfb | |||
| d1612e2804 | |||
| 07c1a90845 | |||
| d0613a8734 | |||
| dd2ca22bba | |||
| 69ed1df0d1 | |||
| 386b0bfcbf | |||
| 2b3d6d7026 | |||
| b29106bcbe | |||
| 6cc8e5e0da | |||
| 221f61c496 | |||
| f37919c850 | |||
| d3234d0204 | |||
| 6d13f47815 | |||
| e54142021a | |||
| cc2241f71a | |||
| cb9283be16 | |||
| 22a08bfb04 | |||
| 2f22451fa6 | |||
| 7dc892b757 | |||
| 7b08ea6a22 | |||
| fc35b804e4 | |||
| 376c7ad890 | |||
| 9f7ef8bdb1 | |||
| d4bdad8d5e | |||
| 7669566f81 | |||
| 023b53fa95 | |||
| 17ef9288ef | |||
| a600f8170a | |||
| 1540292458 | |||
| 3dc3b37044 | |||
| 52a50017c6 | |||
| fbcae7b67d | |||
| 69dcc15bea | |||
| 31a7470b37 | |||
| 79e413d194 | |||
| 307eba4218 | |||
| 5ef3bc68a0 | |||
| 5205a3f095 | |||
| 309e308518 | |||
| 90297af982 | |||
| e1e053af27 | |||
| e72bd066be | |||
| 474895c2a3 | |||
| 1066f42861 | |||
| 928647e6cc | |||
| 47c8ac90cb | |||
| 618c7c3eef | |||
| 2c2d1ab446 | |||
| 88e258a0fb | |||
| 29a41f5ad8 | |||
| 13518f7fff | |||
| 90ece46dd7 | |||
| d92e53f0b7 | |||
| b965da0a6c | |||
| a63bc3e6a9 | |||
| 1147c1a7af | |||
| 34668cb0ea | |||
| adab82964d | |||
| 21390d8ce8 | |||
| 6601ec041e | |||
| 4445f659a7 | |||
| 202f2ce12a | |||
| 734a3b023f | |||
| be5b1d7b81 | |||
| cb3949f6e8 | |||
| f5c088fdc1 | |||
| 6c7241a2ac | |||
| 8dcc899c34 | |||
| 32cc4ec27f | |||
| 29ac0ece7e | |||
| 3117f466b5 | |||
| 9fec2d56f4 | |||
| e60195d431 | |||
| 54467ab9b9 | |||
| 30c8aa2032 | |||
| d984dfb89c | |||
| 63200f863b | |||
| 2a3f0d7be7 | |||
| 5412414ce1 | |||
| ebe3ce0e1e | |||
| 43fb843b17 | |||
| 3ccaf69549 | |||
| ec69d5f724 | |||
| 6777048dac | |||
| 3832d3fde0 | |||
| 32f9653a6d | |||
| 48d79f2635 | |||
| 54428c2bab | |||
| 4ca408b8fe | |||
| 550161bba2 | |||
| f6174706f8 | |||
| c2374d999d | |||
| 66504057b2 | |||
| f3b95fe641 | |||
| b016d27adb | |||
| d44cf95736 | |||
| cf058dc7a9 | |||
| 9f935cd810 | |||
| e88411eea4 | |||
| 0bce2053cf | |||
| 1d65cab11d | |||
| 8f2299cee5 | |||
| ba0fe09d06 | |||
| 73efba625b | |||
| f2b75c81c1 | |||
| 060d37c040 | |||
| 24b6af1799 | |||
| edde8b6927 | |||
| 528ea62f38 | |||
| 87c6523f35 | |||
| a4b01d1259 | |||
| f811286e52 | |||
| c38932046a | |||
| f2a14f3791 | |||
| 53af8dae44 | |||
| 1db31b9e56 | |||
| af97383e01 | |||
| c12f38f133 | |||
| e7f11aee54 | |||
| 98f882233c | |||
| 5e10d53c36 | |||
| fe1e012db3 | |||
| e93b07f890 | |||
| 46eed1c223 | |||
| 1e973c31b2 | |||
| 84b6b60a37 | |||
| 774f2754a0 | |||
| 89ce6773a8 | |||
| 1f2de139eb | |||
| 4efe0aaefa | |||
| 05dee57ded | |||
| 2d850c719d | |||
| 0d0305cf04 | |||
| 02f54c4458 | |||
| 39dfafd538 | |||
| 6162e2662c | |||
| 8a47ad96de | |||
| 61e7c73901 | |||
| e98084aaf4 | |||
| 9f38e2af1a | |||
| 8b148fe0e3 | |||
| ebedc31fb6 | |||
| 25da4a80f2 | |||
| b914590ea8 | |||
| 5dd2260948 | |||
| 6f2ab1ac00 | |||
| 689428241c | |||
| 0b0707eafe | |||
| c4c5389fe8 | |||
| 32aa9e077c | |||
| 56e6766520 | |||
| 49048fc973 | |||
| b1623f9da1 | |||
| 1ea96f5c0d | |||
| 2ee9a98277 | |||
| cf95f90f5e | |||
| 68f3bdb097 | |||
| 7dbce0bd24 | |||
| 1f47b3849e | |||
| ede224c2f2 | |||
| c6cd02486d | |||
| 518ee8baf2 | |||
| 5981eea827 | |||
| f890b07d54 | |||
| d18315aa39 | |||
| 1258b68ef0 | |||
| 689975f262 | |||
| bb965aadd2 | |||
| 9241a0404a | |||
| ee42e932e9 | |||
| 3d3903eadc | |||
| 1ce3490ff0 | |||
| 53aec5edf5 | |||
| 6364325198 | |||
| 6574bd576e | |||
| 9068042a7e | |||
| eb62ce4d99 | |||
| 8a12ee1843 | |||
| 53d97b5ccd | |||
| 60ef214e1b | |||
| c1def5fd7d | |||
| e5dcb07659 | |||
| 446d966e80 | |||
| 7e3d256f93 | |||
| 751967c5fa | |||
| e1b2f00a38 | |||
| eb1adc0311 | |||
| 1da1785e46 | |||
| 68bba332f1 | |||
| 9d22f444b4 | |||
| 731663e4c0 | |||
| d047a99fd3 | |||
| 473cd000d0 | |||
| c8ac8f7297 | |||
| c7d4c6c524 | |||
| 2be094c905 | |||
| 1abb7813a8 | |||
| efb0e3d711 | |||
| d8f5dd4ad9 | |||
| 56f71eb9ab | |||
| 89c2a59fd6 | |||
| b30889dcca | |||
| 7cd78ac3bb | |||
| f7506d57da | |||
| aef3488c80 | |||
| e6ad3fb47a | |||
| 34e09667e5 | |||
| d4794ce85f | |||
| 24678ffb11 | |||
| 93aaffd500 | |||
| a2703988f0 | |||
| d89625558b | |||
| a3c68c3c79 | |||
| 3d2f07418d | |||
| c885e71ba0 | |||
| acad759bb0 | |||
| faff3a2a8d | |||
| 0a2c08eb9b | |||
| cd150d73c5 | |||
| 8c8af74783 | |||
| 980e5ba9ac | |||
| 434d25cac5 | |||
| 615b66da39 | |||
| 8feb9cc1ad | |||
| d0577fe62c | |||
| 2fccac4f2d | |||
| c0a892789e | |||
| 980d4018c2 | |||
| bc573a53c7 | |||
| 4f1d3ee6b3 | |||
| cbe73d9505 | |||
| bfee784bc4 | |||
| 871ffc9182 | |||
| 6e8c8b22c2 | |||
| c7b297eeb9 | |||
| 9ffaf26f1d | |||
| db2ade9da0 | |||
| 60cadc9284 | |||
| 772dd62a55 | |||
| 399d54b1c3 | |||
| b8f71db554 | |||
| 305b4e7064 | |||
| d9ff461877 | |||
| d19bd1d08b | |||
| 1543363b10 | |||
| d56dfcab46 | |||
| 9d7a0d686f | |||
| 5a241a84a5 | |||
| ee000d2d67 | |||
| b1266aa448 | |||
| 1650328ccd | |||
| f39389ead4 | |||
| a4787387dd | |||
| a92f0af57a | |||
| 07d3e47735 | |||
| 3e4c2d0ab1 | |||
| f83384d15f | |||
| 4cd3f90459 | |||
| 6d1bf247c5 | |||
| d7885ddfe6 | |||
| 5b5023e696 | |||
| 0ea3b934dd | |||
| e0fcf5f265 | |||
| fab5827ebb | |||
| 963973bc6b | |||
| 328a2a31e6 | |||
| 8519c00a57 | |||
| 66114f36f9 | |||
| 6c3ac94804 | |||
| b14c37c22b | |||
| 29f0afa31f | |||
| 10fdc27b2b | |||
| 2c1bc0a2cb | |||
| 70db345b12 | |||
| 3655883c9f | |||
| 32c6721ff0 | |||
| 1f13604613 | |||
| 72b3a1f535 | |||
| 2949aba2bb | |||
| 8ac5b801ef | |||
| 2b5c561369 | |||
| f91d62e69f | |||
| a4181b98ac | |||
| b6970d3f03 | |||
| e4e8b0972b | |||
| c18b49e992 | |||
| 6922cbeb23 | |||
| 41f72b647f | |||
| 9653716ff5 | |||
| 2aa0839120 | |||
| fdf6e29990 | |||
| b19ef0e25b | |||
| 4ac73d0113 | |||
| 28397845a0 | |||
| 976da028e5 | |||
| 66c160ec40 | |||
| dc84fc0133 | |||
| 89ffb4cd12 | |||
| e6657a95cd | |||
| 2fc2dc4da5 | |||
| a1a3d12409 |
@@ -0,0 +1,3 @@
|
||||
# The formattening
|
||||
c5d308654744e116090e9ba165a968b8bf66006c
|
||||
da8afe735c62e1f8ee9ad5f71291d87102fe126b
|
||||
@@ -0,0 +1,2 @@
|
||||
*.sh text eol=lf
|
||||
*.bat text eol=crlf
|
||||
@@ -0,0 +1,8 @@
|
||||
*.sqlite
|
||||
/cache
|
||||
/config.php
|
||||
/result
|
||||
/test.sql
|
||||
/vendor/
|
||||
/www/simplesaml
|
||||
composer.phar
|
||||
@@ -0,0 +1,34 @@
|
||||
Peder Bergebakken Sundt <pederbs@pvv.ntnu.no> Peder Bergebakken Sundt <pbsds@hotmail.com>
|
||||
Peder Bergebakken Sundt <pederbs@pvv.ntnu.no> Peder B. Sundt <pbsds@hotmail.com>
|
||||
Peder Bergebakken Sundt <pederbs@pvv.ntnu.no> Peder Bergebakken Sundt <pederbs@misantropy.pvv.ntnu.no>
|
||||
|
||||
Felix Albrigtsen <felixalb@pvv.ntnu.no> Felix Albrigtsen <felixalbrigtsen@gmail.com>
|
||||
Felix Albrigtsen <felixalb@pvv.ntnu.no> Felix Albrigtsen <felix@albrigtsen.it>
|
||||
|
||||
Eirik Wittersø <eirikwit@pvv.ntnu.no> Eirik <eirikw@live.no>
|
||||
Eirik Wittersø <eirikwit@pvv.ntnu.no> Eirik Wittersø <eirikw@LIVE.no>
|
||||
Eirik Wittersø <eirikwit@pvv.ntnu.no> Eirik Wittersø <eirikw@live.no>
|
||||
|
||||
Jørn Åne <yorinad@pvv.ntnu.no> Jørn Åne <git@jornane.no>
|
||||
Jørn Åne <yorinad@pvv.ntnu.no> Jørn Åne <yorinad@pvv.ntnu.no>
|
||||
|
||||
Markus Wang Halvorsen <markuswh@pvv.ntnu.no> Markus <markus@halvorsenfamilien.com>
|
||||
Markus Wang Halvorsen <markuswh@pvv.ntnu.no> halworsen <mwh@halvorsenfamilien.com>
|
||||
Markus Wang Halvorsen <markuswh@pvv.ntnu.no> Markus <markus@halvorsenfamilien.com>
|
||||
|
||||
Adrian Gunnar Lauterer <adriangl@pvv.ntnu.no> Adrian Gunnar Lauterer <adrian@lauterer.it>
|
||||
|
||||
Bjørnar Ørjansen Kaarevik <bjornoka@pvv.ntnu.no> Bjørnar Ørjansen Kaarevik <bjrnarkaarevik@gmail.com>
|
||||
Bjørnar Ørjansen Kaarevik <bjornoka@pvv.ntnu.no> Bjornar Orjansen Kaarevik <bjornoka@eirin.pvv.ntnu.no>
|
||||
|
||||
Øystein Kristoffer Tveit <oysteikt@pvv.ntnu.no> h7x4 <h7x4@nani.wtf>
|
||||
Øystein Kristoffer Tveit <oysteikt@pvv.ntnu.no> Oystein Kristoffer Tveit <oysteikt@pvv.ntnu.no>
|
||||
|
||||
Vegard Bieker Matthey <vegardbm@pvv.ntnu.no> Vegard Matthey <VegardMatthey@protonmail.com>
|
||||
Vegard Bieker Matthey <vegardbm@pvv.ntnu.no> Vegard Bieker Matthey <VegardMatthey@protonmail.com>
|
||||
|
||||
Torstein Nordgård-Hansen <torsteno@pvv.ntnu.no> Torstein N-H <torsteinnh@gmail.com>
|
||||
Torstein Nordgård-Hansen <torsteno@pvv.ntnu.no> Torstein N-H <38429890+torsteinnh@users.noreply.github.com>
|
||||
|
||||
Amalie Erdal Mansåker <amalieem@pvv.ntnu.no> Amalie Mansåker <amalie.mansaker@gmail.com>
|
||||
Amalie Erdal Mansåker <amalieem@pvv.ntnu.no> amalieem <99425692+amalieem@users.noreply.github.com>
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
$finder = (new PhpCsFixer\Finder())
|
||||
->ignoreDotFiles(false)
|
||||
->ignoreVCSIgnored(true)
|
||||
->in([
|
||||
'inc',
|
||||
'src',
|
||||
'dist',
|
||||
])
|
||||
->exclude([
|
||||
'vendor',
|
||||
])
|
||||
->append([
|
||||
__DIR__ . '/config.php',
|
||||
__DIR__ . '/.php-cs-fixer',
|
||||
])
|
||||
;
|
||||
|
||||
return (new PhpCsFixer\Config())
|
||||
->setRiskyAllowed(true)
|
||||
->setRules([
|
||||
'@PER-CS' => true,
|
||||
'@PER-CS:risky' => true,
|
||||
'@PhpCsFixer' => true,
|
||||
'@PhpCsFixer:risky' => true,
|
||||
'@Symfony' => true,
|
||||
'@Symfony:risky' => true,
|
||||
|
||||
'@PHP7x0Migration' => true,
|
||||
'@PHP7x0Migration:risky' => true,
|
||||
'@PHP7x1Migration' => true,
|
||||
'@PHP7x1Migration:risky' => true,
|
||||
'@PHP7x3Migration' => true,
|
||||
'@PHP7x4Migration' => true,
|
||||
'@PHP7x4Migration:risky' => true,
|
||||
'@PHP8x0Migration' => true,
|
||||
'@PHP8x0Migration:risky' => true,
|
||||
'@PHP8x1Migration' => true,
|
||||
'@PHP8x1Migration:risky' => true,
|
||||
'@PHP8x2Migration' => true,
|
||||
'@PHP8x2Migration:risky' => true,
|
||||
'@PHP8x3Migration' => true,
|
||||
'@PHP8x3Migration:risky' => true,
|
||||
'@PHP8x4Migration' => true,
|
||||
'@PHP8x4Migration:risky' => true,
|
||||
'@PHP8x5Migration' => true,
|
||||
'@PHP8x5Migration:risky' => true,
|
||||
|
||||
'strict_param' => true,
|
||||
'array_syntax' => ['syntax' => 'short'],
|
||||
'braces_position' => [
|
||||
'functions_opening_brace' => 'same_line',
|
||||
'classes_opening_brace' => 'same_line',
|
||||
],
|
||||
'simplified_if_return' => true,
|
||||
'simplified_null_return' => true,
|
||||
'yoda_style' => false,
|
||||
|
||||
// TODO: fix these
|
||||
'psr_autoloading' => false,
|
||||
])
|
||||
->setFinder($finder)
|
||||
->setIndent(" ")
|
||||
->setLineEnding("\n")
|
||||
;
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Kasper Rynning-Tønnesen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,118 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kasperrt;
|
||||
|
||||
class OAuth2 {
|
||||
|
||||
private $client_id;
|
||||
private $client_secret;
|
||||
private $redirect_uri;
|
||||
private $scope;
|
||||
private $access_token;
|
||||
private $url;
|
||||
private $URL_AUTH;
|
||||
private $URL_TOKEN;
|
||||
private $auth_type;
|
||||
private $session;
|
||||
private $grant_type;
|
||||
private $response_type;
|
||||
|
||||
public function __construct($params){
|
||||
|
||||
/* REQUIRED */
|
||||
$this->client_id = $params["client_id"];
|
||||
$this->client_secret = $params["client_secret"];
|
||||
$this->redirect_uri = $params["redirect_uri"];
|
||||
$this->URL_AUTH = $params["auth"] . "?";
|
||||
$this->URL_TOKEN = $params["token"] . "?";
|
||||
|
||||
/* OPTIONAL */
|
||||
$this->auth_type = isset($params["authorization_type"]) ? $params["authorization_type"] : "Bearer";
|
||||
$this->session = isset($params["session"]) ? $params["session"] : false;
|
||||
$this->verify_ssl_peer = isset($params["verify"]) ? ($params["verify"] ? 1 : 0) : 1;
|
||||
$this->verify_ssl_host = $this->verify_ssl_peer === 1 ? 2 : 0;
|
||||
$this->grant_type = isset($params["grant_type"]) ? $params["grant_type"] : "authorization_code";
|
||||
$this->response_type = isset($params["response_type"]) ? $params["response_type"] : "code";
|
||||
}
|
||||
|
||||
public function get_access_token(
|
||||
$state = mysql_real_escape_string($_GET['state']),
|
||||
$code = mysql_real_escape_string($_GET['code'])) {
|
||||
if($this->session && $state) {
|
||||
if($_SESSION['state'] != $state) {
|
||||
die('States does not match');
|
||||
}
|
||||
}
|
||||
|
||||
$access_token = $this->get_oauth_token($code);
|
||||
return $access_token;
|
||||
}
|
||||
|
||||
private function get_oauth_token($code) {
|
||||
$params = array(
|
||||
'grant_type' => $this->grant_type,
|
||||
'client_id' => $this->client_id,
|
||||
'client_secret' => $this->client_secret,
|
||||
'code' => $code,
|
||||
'redirect_uri' => $this->redirect_uri,
|
||||
);
|
||||
|
||||
$url_params = http_build_query($params);
|
||||
$url = $this->URL_TOKEN . $url_params;
|
||||
|
||||
$result = curl_exec($this->create_curl($url, false, $params));
|
||||
$result_obj = json_decode($result, true);
|
||||
$access_token = $result_obj['access_token'];
|
||||
|
||||
return $access_token;
|
||||
}
|
||||
|
||||
public function get_identity($access_token, $identity_url) {
|
||||
if(!$access_token || !$identity_url) throw new Exception("Missing either \$access_token or \$identity_url in get_identity function.");
|
||||
$params = array(
|
||||
'access_token' => $access_token,
|
||||
);
|
||||
$url_params = http_build_query($params);
|
||||
$url = $identity_url . "?" . $url_params;
|
||||
$result = curl_exec($this->create_curl($url, array('Authorization: ' . $this->auth_type . ' ' . $access_token), false));
|
||||
$result_obj = json_decode($result, true);
|
||||
|
||||
return $result_obj;
|
||||
}
|
||||
|
||||
public function redirect($state = false) {
|
||||
if(!$state) $state = uniqid('', true);
|
||||
$params = array(
|
||||
'client_id' => $this->client_id,
|
||||
'response_type' => $this->response_type,
|
||||
'redirect_uri' => $this->redirect_uri,
|
||||
'state' => $state,
|
||||
);
|
||||
|
||||
if($this->session) $_SESSION['state'] = $state;
|
||||
|
||||
$url = $this->URL_AUTH . http_build_query($params);
|
||||
|
||||
header("Location: $url");
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
private function create_curl($url, $header, $extended) {
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
if ($header){
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
|
||||
}
|
||||
if ($extended) {
|
||||
curl_setopt($curl, CURLOPT_POST, 1);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $extended);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verify_ssl_peer);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verify_ssl_host);
|
||||
}
|
||||
return $curl;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,56 +1,11 @@
|
||||
# General Authorization Code Flow OAuth2-Client
|
||||
|
||||
This client is made for Authorization Code Flow and Bearer as authorization option for now.
|
||||
# Programvareverkstedets nettside
|
||||
|
||||
To use this general OAuth2 client-class, include it with
|
||||
```
|
||||
require_once('OAuth2Client.php');
|
||||
$oauth2 = new OAuth2([
|
||||
"client_id" => $client_id,
|
||||
"client_secret" => $client_secret,
|
||||
"redirect_uri" => $redirect_uri,
|
||||
"auth" => $auth,
|
||||
"token" => $token,
|
||||
"authorization_type" => $authorization_type,
|
||||
"session" => $session,
|
||||
"verify" => $verify,
|
||||
"grant_type" => $grant_type,
|
||||
"response_type" => $response_type
|
||||
]);
|
||||
```
|
||||
A website created with the latest and greatest web technologies.
|
||||
May contain blackjack and other things one tends to include in awesome projects.
|
||||
|
||||
```(string) $client_id``` is client id of the OAuth2 application
|
||||
```(string) $client_secret``` is client secret of the OAuth2 application
|
||||
```(string) $redirect_uri``` is the specified redirect-uri for the OAuth2 application
|
||||
```(string) $auth``` is the full url for authorization
|
||||
```(string) $token``` is the full token url
|
||||
See [Getting Started](./docs/getting-started.md) for help to hack on the project.
|
||||
|
||||
Optional -
|
||||
## Hosting
|
||||
|
||||
```(string) $authorization_type``` defaults to Bearer
|
||||
```(boolean) $session``` specifies whether the state is to be saved in _SESSION storage, defaults to false
|
||||
```(boolean) $verify``` is whether to verify SSL of host and peer, defaults to true
|
||||
```(string) $grant_type``` defaults to 'authorization_code'
|
||||
```(string) $response_type``` defaults to "code"
|
||||
|
||||
|
||||
To start the redirect phase
|
||||
|
||||
```$oauth2->redirect($state);``` ($state defaults to false)
|
||||
|
||||
|
||||
To get access token
|
||||
|
||||
```$oauth2->get_access_token();``` returns the access_token.
|
||||
|
||||
|
||||
(Optional value is $state, to check up against _SESSION variables)
|
||||
|
||||
|
||||
To get identity
|
||||
|
||||
```$oauth->get_identity($access_token, $user_url);```
|
||||
|
||||
```(string) $user_url``` is the endpoint for fetching info, example: https://auth.dataporten.no/userinfo
|
||||
|
||||
returns the identity-object as returned from the OAuth2-provider.
|
||||

|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "kasperrt/oauth2-client",
|
||||
"description": "OAuth2 Client with Bearer tokens",
|
||||
"license": "MIT",
|
||||
"keywords": ["authentication"],
|
||||
"homepage": "https://github.com/kasperrt/oauth2-client",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Kasper Rynning-Tønnesen",
|
||||
"homepage": "https://kasperrt.no"
|
||||
"name": "programvareverkstedet/nettsiden",
|
||||
"description": "Programvareverkstedets nettside",
|
||||
"license": "proprietary",
|
||||
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"simplesamlphp/composer-module-installer": true,
|
||||
"simplesamlphp/composer-xmlprovider-installer": true
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"simplesamlphp/simplesamlphp": "^2.2.1",
|
||||
"erusev/parsedown": "^1.7.4"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"classmap": [""]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$DB_DSN = 'sqlite:' . __DIR__ . \DIRECTORY_SEPARATOR . 'pvv.sqlite';
|
||||
$DB_USER = null;
|
||||
$DB_PASS = null;
|
||||
|
||||
$DOOR_SECRET = 'changeme';
|
||||
|
||||
$GALLERY_DIR = __DIR__ . \DIRECTORY_SEPARATOR . 'www' . \DIRECTORY_SEPARATOR . 'galleri' . \DIRECTORY_SEPARATOR . 'bilder' . \DIRECTORY_SEPARATOR . 'gallery';
|
||||
$GALLERY_SERVER_PATH = '/images/gallery/';
|
||||
|
||||
$SLIDESHOW_DIR = __DIR__ . \DIRECTORY_SEPARATOR . 'www' . \DIRECTORY_SEPARATOR . 'galleri' . \DIRECTORY_SEPARATOR . 'bilder' . \DIRECTORY_SEPARATOR . 'slideshow';
|
||||
$SLIDESHOW_SERVER_PATH = '/images/slideshow/';
|
||||
|
||||
$SAML_COOKIE_SALT = 'changeme';
|
||||
$SAML_COOKIE_SECURE = false;
|
||||
$SAML_TRUSTED_DOMAINS = ['localhost:1080'];
|
||||
$SAML_ADMIN_PASSWORD = 'changeme';
|
||||
$SAML_ADMIN_NAME = 'PVV Drift';
|
||||
$SAML_ADMIN_EMAIL = 'drift@pvv.ntnu.no';
|
||||
|
||||
$CACHE_DIRECTORY = __DIR__ . \DIRECTORY_SEPARATOR . 'cache';
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$configFile = getenv('PVV_CONFIG_FILE');
|
||||
require_once $configFile;
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
$config = [
|
||||
// This is used by the service provider to contact the identity provider
|
||||
'default-sp' => [
|
||||
'saml:SP',
|
||||
'entityID' => 'http://localhost:1080/simplesaml/sp',
|
||||
'idp' => 'http://localhost:1080/simplesaml/idp',
|
||||
],
|
||||
|
||||
// This is used by the identity provider to authenticate users
|
||||
'example-userpass' => [
|
||||
'exampleauth:UserPass',
|
||||
'users' => [
|
||||
'user:user' => [
|
||||
'uid' => ['user'],
|
||||
'group' => ['users'],
|
||||
'cn' => 'Ole Petter',
|
||||
'mail' => 'user+test@pvv.ntnu.no',
|
||||
],
|
||||
'admin:admin' => [
|
||||
'uid' => ['admin'],
|
||||
'group' => ['admin'],
|
||||
'cn' => 'Admin Adminsson',
|
||||
'mail' => 'admin+test@pvv.ntnu.no',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
// This is also used by the identity provider to authenticate IDP admins
|
||||
// See http://localhost:1080/simplesaml/admin/
|
||||
'admin' => [
|
||||
'core:AdminPassword',
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$metadata['http://localhost:1080/simplesaml/idp'] = [
|
||||
'host' => '__DEFAULT__',
|
||||
'privatekey' => 'localhost.pem',
|
||||
'certificate' => 'localhost.crt',
|
||||
'auth' => 'example-userpass',
|
||||
];
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$metadata['https://idp.pvv.ntnu.no/'] = [
|
||||
'metadata-set' => 'saml20-idp-remote',
|
||||
'entityid' => 'https://idp.pvv.ntnu.no/',
|
||||
'SingleSignOnService' => [
|
||||
0 => [
|
||||
'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
|
||||
'Location' => 'https://idp.pvv.ntnu.no/simplesaml/saml2/idp/SSOService.php',
|
||||
],
|
||||
],
|
||||
'SingleLogoutService' => [
|
||||
0 => [
|
||||
'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
|
||||
'Location' => 'https://idp.pvv.ntnu.no/simplesaml/saml2/idp/SingleLogoutService.php',
|
||||
],
|
||||
],
|
||||
'certData' => 'MIIDpTCCAo2gAwIBAgIJAJIgibrB7NvsMA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAk5PMR4wHAYDVQQKDBVQcm9ncmFtdmFyZXZlcmtzdGVkZXQxGDAWBgNVBAMMD2lkcC5wdnYubnRudS5ubzEgMB4GCSqGSIb3DQEJARYRZHJpZnRAcHZ2Lm50bnUubm8wHhcNMTcxMTEzMjI0NTQyWhcNMjcxMTEzMjI0NTQyWjBpMQswCQYDVQQGEwJOTzEeMBwGA1UECgwVUHJvZ3JhbXZhcmV2ZXJrc3RlZGV0MRgwFgYDVQQDDA9pZHAucHZ2Lm50bnUubm8xIDAeBgkqhkiG9w0BCQEWEWRyaWZ0QHB2di5udG51Lm5vMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAveLujCsgVCRA360y5yezy8FcSPhaqodggDqY12UTkYOMQLBFaph6uUL4oCUlXZqxScrAYVRt9yw+7BYpcm0p51VZzVCsfMxRVkn+O1eUvsaXq3f13f87QHKYP2f0uqkGf5PvnKIdSaI/ix8WJhD8XT+h0OkHEcaBvUtSG7zbEhvG21WPHwgw2rvZSneArQ8tOitZC0u8VXSfdhtf6ynRseo0xC95634UwQAZivhQ2v4A6Tp57QG5DCXIJ9/z3PkINx3KB/hOeh0EP6Dpbp+7V0/t9778E3whpm4llrH144kzROhA7EgUgkZOjAVjxGCYlcj3xQPnnItihVOZ5B5qLwIDAQABo1AwTjAdBgNVHQ4EFgQUPLhrB+Qb/Kzz7Car9GJkKmEkz6swHwYDVR0jBBgwFoAUPLhrB+Qb/Kzz7Car9GJkKmEkz6swDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAd+4E6t0j8/p8rbZE8y/gZ9GsiRhxkR4l6JbMRUfEpqHKi415qstChRcP2Lo3Yd5qdmj9tLDWoPsqet1QgyTTmQTgUmPhhMOQDqSh90LuqEJseKWafXGS/SfWLH6MWVmzDV5YofJEw2ThPiU58GiS06OLS2poq1eAesa2LQ22J8yYisXM4sxImIFte+LYQ1+1evfBWcvU1vrGsQ0VLJHdef9WoXp1swUFhq4Zk0c7gjHiB1CFVlExAAlk9L6W3CVXmKIYlf4eUnEBGkC061Ir42+uhAMWO9Y/L1NEuboTyd2KAI/6JdKdzpmfk7zPVxWlNxNCZ7OPNuvOKp6VlpB2EA==',
|
||||
'NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient',
|
||||
];
|
||||
|
||||
function getCertData(string $path): string
|
||||
{
|
||||
$cert = file_get_contents($path);
|
||||
$cert = str_replace("-----BEGIN CERTIFICATE-----", "", $cert);
|
||||
$cert = str_replace("-----END CERTIFICATE-----", "", $cert);
|
||||
$cert = str_replace(["\r", "\n"], "", $cert);
|
||||
return $cert;
|
||||
}
|
||||
|
||||
$metadata['http://localhost:1080/simplesaml/idp'] = [
|
||||
'metadata-set' => 'saml20-idp-remote',
|
||||
'entityid' => 'https://localhost:1080/simplesaml/idp',
|
||||
'SingleSignOnService' => [
|
||||
0 => [
|
||||
'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
|
||||
'Location' => 'http://localhost:1080/simplesaml/saml2/idp/SSOService.php',
|
||||
],
|
||||
],
|
||||
'SingleLogoutService' => [
|
||||
0 => [
|
||||
'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
|
||||
'Location' => 'http://localhost:1080/simplesaml/saml2/idp/SingleLogoutService.php',
|
||||
],
|
||||
],
|
||||
'certData' => getCertData(__DIR__ . '/../cert/localhost.crt'),
|
||||
'NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient',
|
||||
];
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
$metadata['http://localhost:1080/simplesaml/sp'] = [
|
||||
'AssertionConsumerService' => [
|
||||
[
|
||||
'Location' => 'http://localhost:1080/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp',
|
||||
'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
|
||||
],
|
||||
],
|
||||
'SingleLogoutService' => [
|
||||
[
|
||||
'Location' => 'http://localhost:1080/simplesaml/module.php/saml/sp/saml2-logout.php/default-sp',
|
||||
'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
$config = [
|
||||
|
||||
/* This is the name of this authentication source, and will be used to access it later. */
|
||||
'default-sp' => [
|
||||
'saml:SP',
|
||||
'entityID' => 'https://www.pvv.ntnu.no/simplesaml/',
|
||||
'idp' => 'https://idp.pvv.ntnu.no/',
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
$metadata['https://idp.pvv.ntnu.no/'] = [
|
||||
'metadata-set' => 'saml20-idp-remote',
|
||||
'entityid' => 'https://idp.pvv.ntnu.no/',
|
||||
'SingleSignOnService' => [
|
||||
0 => [
|
||||
'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
|
||||
'Location' => 'https://idp.pvv.ntnu.no/simplesaml/saml2/idp/SSOService.php',
|
||||
],
|
||||
],
|
||||
'SingleLogoutService' => [
|
||||
0 => [
|
||||
'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
|
||||
'Location' => 'https://idp.pvv.ntnu.no/simplesaml/saml2/idp/SingleLogoutService.php',
|
||||
],
|
||||
],
|
||||
'certData' => 'MIIDpTCCAo2gAwIBAgIJAJIgibrB7NvsMA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAk5PMR4wHAYDVQQKDBVQcm9ncmFtdmFyZXZlcmtzdGVkZXQxGDAWBgNVBAMMD2lkcC5wdnYubnRudS5ubzEgMB4GCSqGSIb3DQEJARYRZHJpZnRAcHZ2Lm50bnUubm8wHhcNMTcxMTEzMjI0NTQyWhcNMjcxMTEzMjI0NTQyWjBpMQswCQYDVQQGEwJOTzEeMBwGA1UECgwVUHJvZ3JhbXZhcmV2ZXJrc3RlZGV0MRgwFgYDVQQDDA9pZHAucHZ2Lm50bnUubm8xIDAeBgkqhkiG9w0BCQEWEWRyaWZ0QHB2di5udG51Lm5vMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAveLujCsgVCRA360y5yezy8FcSPhaqodggDqY12UTkYOMQLBFaph6uUL4oCUlXZqxScrAYVRt9yw+7BYpcm0p51VZzVCsfMxRVkn+O1eUvsaXq3f13f87QHKYP2f0uqkGf5PvnKIdSaI/ix8WJhD8XT+h0OkHEcaBvUtSG7zbEhvG21WPHwgw2rvZSneArQ8tOitZC0u8VXSfdhtf6ynRseo0xC95634UwQAZivhQ2v4A6Tp57QG5DCXIJ9/z3PkINx3KB/hOeh0EP6Dpbp+7V0/t9778E3whpm4llrH144kzROhA7EgUgkZOjAVjxGCYlcj3xQPnnItihVOZ5B5qLwIDAQABo1AwTjAdBgNVHQ4EFgQUPLhrB+Qb/Kzz7Car9GJkKmEkz6swHwYDVR0jBBgwFoAUPLhrB+Qb/Kzz7Car9GJkKmEkz6swDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAd+4E6t0j8/p8rbZE8y/gZ9GsiRhxkR4l6JbMRUfEpqHKi415qstChRcP2Lo3Yd5qdmj9tLDWoPsqet1QgyTTmQTgUmPhhMOQDqSh90LuqEJseKWafXGS/SfWLH6MWVmzDV5YofJEw2ThPiU58GiS06OLS2poq1eAesa2LQ22J8yYisXM4sxImIFte+LYQ1+1evfBWcvU1vrGsQ0VLJHdef9WoXp1swUFhq4Zk0c7gjHiB1CFVlExAAlk9L6W3CVXmKIYlf4eUnEBGkC061Ir42+uhAMWO9Y/L1NEuboTyd2KAI/6JdKdzpmfk7zPVxWlNxNCZ7OPNuvOKp6VlpB2EA==',
|
||||
'NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient',
|
||||
];
|
||||
@@ -0,0 +1,74 @@
|
||||
CREATE TABLE events (
|
||||
`id` INTEGER PRIMARY KEY AUTO_INCREMENT,
|
||||
`name` TEXT NOT NULL,
|
||||
`start` INTEGER,
|
||||
`stop` INTEGER,
|
||||
`organiser` TEXT,
|
||||
`location` TEXT,
|
||||
`description` TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE project_group (
|
||||
`id` INTEGER PRIMARY KEY AUTO_INCREMENT,
|
||||
`title` TEXT NOT NULL,
|
||||
`description_en` TEXT NOT NULL,
|
||||
`description_no` TEXT NOT NULL,
|
||||
`gitea_link` TEXT NOT NULL,
|
||||
`wiki_link` TEXT
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
project_group (title, description_en, description_no, gitea_link, wiki_link)
|
||||
VALUES
|
||||
(
|
||||
'Projects',
|
||||
'Projects developed by members of PVV.',
|
||||
'Prosjekter utviklet av medlemmer i PVV.',
|
||||
'https://git.pvv.ntnu.no/Projects',
|
||||
'https://wiki.pvv.ntnu.no/wiki/Programvareutvikling'
|
||||
);
|
||||
|
||||
CREATE TABLE project (
|
||||
`id` INTEGER PRIMARY KEY AUTO_INCREMENT,
|
||||
`group_id` INTEGER NOT NULL REFERENCES project_group (id) DEFAULT 1,
|
||||
`title` TEXT NOT NULL,
|
||||
`description_en` TEXT NOT NULL,
|
||||
`description_no` TEXT NOT NULL,
|
||||
`gitea_link` TEXT,
|
||||
`issue_board_link` TEXT,
|
||||
`wiki_link` TEXT,
|
||||
`programming_languages` TEXT,
|
||||
`technologies` TEXT,
|
||||
`keywords` TEXT,
|
||||
`license` TEXT,
|
||||
`logo_url` TEXT,
|
||||
`is_hidden` BOOLEAN DEFAULT FALSE,
|
||||
FOREIGN KEY (group_id) REFERENCES project_group (id) ON DELETE SET DEFAULT
|
||||
);
|
||||
|
||||
CREATE TABLE project_maintainer (
|
||||
`uname` TEXT NOT NULL,
|
||||
`project_id` INTEGER NOT NULL,
|
||||
`name` TEXT NOT NULL,
|
||||
`email` TEXT,
|
||||
`is_organizer` BOOLEAN DEFAULT FALSE,
|
||||
PRIMARY KEY (uname, project_id),
|
||||
FOREIGN KEY (project_id) REFERENCES project (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE users (
|
||||
`id` INTEGER PRIMARY KEY AUTO_INCREMENT,
|
||||
`uname` TEXT NOT NULL UNIQUE,
|
||||
`groups` INT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE motd (
|
||||
`id` INTEGER PRIMARY KEY AUTO_INCREMENT,
|
||||
`title` TEXT NOT NULL,
|
||||
`content` TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE door (
|
||||
`time` INTEGER PRIMARY KEY,
|
||||
`open` BOOLEAN NOT NULL
|
||||
);
|
||||
@@ -0,0 +1,78 @@
|
||||
CREATE TABLE "events" (
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
"name" TEXT NOT NULL,
|
||||
"start" TEXT,
|
||||
"stop" TEXT,
|
||||
"organiser" TEXT,
|
||||
"location" TEXT,
|
||||
"description" TEXT
|
||||
);
|
||||
|
||||
-- PROJECTS
|
||||
|
||||
CREATE TABLE "project_group" (
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
"title" TEXT NOT NULL,
|
||||
"description_en" TEXT NOT NULL,
|
||||
"description_no" TEXT NOT NULL,
|
||||
"gitea_link" TEXT NOT NULL,
|
||||
"wiki_link" TEXT
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
project_group (title, description_en, description_no, gitea_link, wiki_link)
|
||||
VALUES
|
||||
(
|
||||
'Projects',
|
||||
'Projects developed by members of PVV.',
|
||||
'Prosjekter utviklet av medlemmer i PVV.',
|
||||
'https://git.pvv.ntnu.no/Projects',
|
||||
'https://wiki.pvv.ntnu.no/wiki/Programvareutvikling'
|
||||
);
|
||||
|
||||
CREATE TABLE "project" (
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
"group_id" INTEGER NOT NULL DEFAULT 1,
|
||||
"title" TEXT NOT NULL,
|
||||
"description_en" TEXT NOT NULL,
|
||||
"description_no" TEXT NOT NULL,
|
||||
"gitea_link" TEXT,
|
||||
"issue_board_link" TEXT,
|
||||
"wiki_link" TEXT,
|
||||
"programming_languages" TEXT,
|
||||
"technologies" TEXT,
|
||||
"keywords" TEXT,
|
||||
"license" TEXT,
|
||||
"logo_url" TEXT,
|
||||
"is_hidden" BOOLEAN DEFAULT FALSE,
|
||||
FOREIGN KEY (group_id) REFERENCES project_group (id) ON DELETE SET DEFAULT
|
||||
);
|
||||
|
||||
CREATE TABLE "project_maintainer" (
|
||||
"uname" TEXT NOT NULL,
|
||||
"project_id" INTEGER NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"email" TEXT,
|
||||
"is_organizer" BOOLEAN DEFAULT FALSE,
|
||||
PRIMARY KEY (uname, project_id),
|
||||
FOREIGN KEY (project_id) REFERENCES project (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
--
|
||||
|
||||
CREATE TABLE "users" (
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
"uname" TEXT NOT NULL UNIQUE,
|
||||
"groups" INT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE "motd" (
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
"title" TEXT NOT NULL,
|
||||
"content" TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "door" (
|
||||
"time" INTEGER PRIMARY KEY,
|
||||
"open" BOOLEAN NOT NULL
|
||||
);
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
-- See users in ../authsources.php
|
||||
INSERT INTO
|
||||
"users"("uname", "groups")
|
||||
VALUES
|
||||
('admin', 1 | 2 | 4),
|
||||
('user', 0);
|
||||
|
||||
INSERT INTO
|
||||
"motd"("title", "content")
|
||||
VALUES
|
||||
(
|
||||
'MOTD ./dev.sh',
|
||||
'du kan endre motd i admin panelet'
|
||||
);
|
||||
|
After Width: | Height: | Size: 477 KiB |
|
After Width: | Height: | Size: 1.0 MiB |
@@ -0,0 +1,25 @@
|
||||
# Forsiden til pvv.no
|
||||
|
||||
* NB! Anbefaler at pvv.org og pvv.ntnu.no/pvv/Programvareverkstedet redirecter til pvv.no, eller vice-versa, om mulig. Det er lettest for folk å huske pvv.no, og er lett å dele. Akkurat nå pointer pvv.no til ingenting, og det er teit.
|
||||
|
||||
Følgende punkt er viktigst mtp forsiden:
|
||||
* Det skal være lett å finne ut hva PVV er
|
||||
* En skal raskt kunne se oppkommende kurs og hendelser, og melde seg på disse
|
||||
* Rask oppmelding som medlem, synlig
|
||||
* Vise hvor vi er
|
||||
* Åpningsindikator (dørsensor) eller tentative åpningstider
|
||||
* Vis lite (få events, kort om det å bli medlem), og få brukeren til å gå til mer utfyllende sider med mer info via "les mer" lenker e.l.
|
||||
|
||||
## Utkast til skrivebordsversjon
|
||||
Under kickoffmøtet kom vi fram til følgende førsteutkast:
|
||||
|
||||

|
||||
|
||||
I tillegg må vi plassere åpen-status ett eller annet sted (øverst til høyre?), samt gjøre det lett å komme seg til wikien. Det kom fram et sterkt ønske om å ha få menyer, og å gjøre nettsiden så ren og lett som mulig.
|
||||
|
||||
Et sentralt mål bør være å tillate brukeren å melde seg inn som medlem, og/eller melde seg inn på kurs og events med så få klikk som mulig. Må se på løsninger rundt dette.
|
||||
|
||||
## Utkast til mobilversjon
|
||||
Sketsjene er relativt like, men mobilversjonen bør ha langt lettere funksjonalitet enn skrivebordsversjonen. På mobil bør nettsiden heller fokusere på å oppdatere besøkende på farten om kurs, åpenstatus, og gjøre det mulig å få varsler eller legge inn kursevents i google calendar e.l.. Vi må presse så mye nyttig informasjon som mulig, presentert på en oversiktlig og ikke-overveldende måte, uten at brukeren må scrolle.
|
||||
|
||||

|
||||
@@ -0,0 +1,72 @@
|
||||
# Getting started
|
||||
|
||||
Let's get you up and running.
|
||||
|
||||
## List of dependencies
|
||||
|
||||
You will need to install the following pieces of software:
|
||||
|
||||
- Git
|
||||
- SQLite3
|
||||
- PHP
|
||||
- Composer
|
||||
- OpenSSL
|
||||
|
||||
If you are running Ubuntu or Debian, you can install these dependencies with:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install git sqlite3 php composer openssl
|
||||
```
|
||||
|
||||
## Automatic setup
|
||||
|
||||
You can use the scripts in the `scripts/` directory to quickly set up a development environment.
|
||||
|
||||
By running the `./scripts/setup.sh`, all dependencies will be installed, in addition to other miscellaneous setup tasks. You can then run `./scripts/run.sh` to start the webserver.
|
||||
|
||||
You should now be able to access the site at [http://localhost:1080](http://localhost:1080).
|
||||
|
||||
Sometimes it is useful to completely reset the state of the project, deleting the data, redownloading dependencies, etc. You can do this by running `./scripts/reset.sh`. Be careful, as this will delete all data in the database!
|
||||
|
||||
> [!WARNING]
|
||||
> Even when resetting the project with the reset script, there are some situation where you need to clear your cookies or your browser cache to get a clean state.
|
||||
> How to do this varies between browsers, so please refer to your browser's documentation for instructions.
|
||||
|
||||
## Setup with nix
|
||||
|
||||
We provide a devshell with all dependencies included. We do recommend still using the scripts for setup tasks.
|
||||
|
||||
```bash
|
||||
nix develop
|
||||
./scripts/setup.sh
|
||||
./scripts/run.sh
|
||||
```
|
||||
|
||||
## Logging in
|
||||
|
||||
We have a development configuration for SimpleSAMLphp (which we use as our authentication system), that lets you log in with dummy users while developing.
|
||||
|
||||
The available users are:
|
||||
|
||||
- `admin` (password: `admin`) - An admin user
|
||||
- `user` (password: `user`) - A normal user
|
||||
|
||||
In addition, if you need to look into the SAML setup, you can log into the SimpleSAMLphp admin interface at [http://localhost:1080/simplesaml/admin](http://localhost:1080/simplesaml/admin) with username `admin` and password `123`.
|
||||
|
||||
## The codebase
|
||||
|
||||
In the codebase, you will find the following directories:
|
||||
|
||||
- `dist`: Contains files related to deployment, hosting and packaging.
|
||||
- `docs`: Documentation for the project.
|
||||
- `inc`: PHP include files, containing a base set of useful classes, functions and constants.
|
||||
- `nix`: Nix config for packaging, devshells, NixOS modules, etc.
|
||||
- `scripts`: Helper scripts for setting up development environments, running the server, etc.
|
||||
- `src`: The main library code for the project. This contains raw PHP code with business logic and database access.
|
||||
- `vendor`: Third-party dependencies installed with composer.
|
||||
- `www`: The webroot for the project. This contains public assets, styling, javascript and PHP code concerned with routing and rendering webpages.
|
||||
|
||||
## How SimpleSAMLphp is set up in the development environment
|
||||
|
||||
It used to be the case that we would connect to our production instance of SimpleSAMLphp for authentication even in development environments. This is no longer the case, as we now use our local SimpleSAMLphp instance both as a service provider and as an identity provider in development. The `config.php` and `authsources.php` files are written in a way where one single instance of SimpleSAMLphp acts as both parts. It will send authentication requests to itself. See `dist/simplesaml-dev` for implementation details.
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1778458615,
|
||||
"narHash": "sha256-cY07EsdhBJ8tFXPzDYevgqxRev9ZLxFonuq9wmq5kwg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c6e5ca3c836a5f4dd9af9f2c1fc1c38f0fac988a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
description = "Programvareverkstedet/nettsiden PHP environment";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs }:
|
||||
let
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
"aarch64-darwin"
|
||||
];
|
||||
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in f system pkgs);
|
||||
in {
|
||||
packages = forAllSystems (system: pkgs: {
|
||||
default = self.packages.${system}.pvv-nettsiden;
|
||||
pvv-nettsiden = pkgs.callPackage ./nix/package.nix { php = pkgs.php85; };
|
||||
});
|
||||
|
||||
overlays.default = final: prev: {
|
||||
inherit (self.packages.${final.stdenv.hostPlatform.system}) pvv-nettsiden;
|
||||
formats = prev.formats // {
|
||||
php = import ./nix/php-generator.nix { pkgs = prev; lib = prev.lib; };
|
||||
};
|
||||
};
|
||||
|
||||
nixosModules.default = nix/module.nix;
|
||||
|
||||
devShells = forAllSystems (system: pkgs: {
|
||||
default = pkgs.callPackage ./nix/shell.nix { inherit pkgs; };
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
require __DIR__ . '/../src/_autoload.php';
|
||||
require __DIR__ . '/../config.php';
|
||||
|
||||
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$agenda = new pvv\side\Agenda([
|
||||
new pvv\side\social\NerdepitsaActivity(),
|
||||
new pvv\side\social\AnimekveldActivity(),
|
||||
new pvv\side\DBActivity($pdo),
|
||||
]);
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
// Set up database and user system,
|
||||
// and include common files such as HTML includes or SimplSAMLphp.
|
||||
|
||||
require_once __DIR__ . \DIRECTORY_SEPARATOR . 'agenda.php';
|
||||
require_once __DIR__ . \DIRECTORY_SEPARATOR . 'navbar.php';
|
||||
|
||||
require_once dirname(__DIR__) . implode(\DIRECTORY_SEPARATOR, ['', 'config.php']);
|
||||
|
||||
require_once dirname(__DIR__) . implode(\DIRECTORY_SEPARATOR, ['', 'src', '_autoload.php']);
|
||||
require_once dirname(__DIR__) . implode(\DIRECTORY_SEPARATOR, ['', 'vendor', 'simplesamlphp', 'simplesamlphp', 'lib', '_autoload.php']);
|
||||
|
||||
date_default_timezone_set('Europe/Oslo');
|
||||
setlocale(\LC_ALL, 'nb_NO');
|
||||
|
||||
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$userManager = new pvv\admin\UserManager($pdo);
|
||||
|
||||
$sp = 'default-sp';
|
||||
$as = new SimpleSAML\Auth\Simple($sp);
|
||||
|
||||
use pvv\side\Agenda;
|
||||
|
||||
$agenda = new Agenda([
|
||||
// new \pvv\side\social\NerdepitsaActivity,
|
||||
// new \pvv\side\social\AnimekveldActivity,
|
||||
new pvv\side\social\HackekveldActivity(),
|
||||
new pvv\side\social\BrettspillActivity(),
|
||||
new pvv\side\social\DriftkveldActivity(),
|
||||
new pvv\side\DBActivity($pdo),
|
||||
]);
|
||||
|
||||
$months_translations = ['januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'];
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
function navbar($depth, $active = null) {
|
||||
$result = "\n\t<ul id=\"menu\">\n";
|
||||
$menuItems = [
|
||||
'Hjem' => '',
|
||||
'Hendelser' => 'hendelser',
|
||||
// 'Kalender' => 'kalender',
|
||||
// 'Aktiviteter' => 'aktiviteter',
|
||||
'Prosjekter' => 'prosjekt',
|
||||
'Kontakt' => 'kontakt',
|
||||
// 'Webmail' => 'https://webmail.pvv.ntnu.no/roundcube/',
|
||||
'Galleri' => 'galleri',
|
||||
'Wiki' => 'https://wiki.pvv.ntnu.no/',
|
||||
'Git' => 'https://git.pvv.ntnu.no/',
|
||||
'Tjenester' => 'tjenester',
|
||||
];
|
||||
foreach ($menuItems as $caption => $link) {
|
||||
$isActive = $active === $link;
|
||||
if (substr($link, 0, 4) !== 'http') {
|
||||
$link = rtrim(str_repeat('../', $depth) . $link, '/') . '/';
|
||||
}
|
||||
|
||||
// if ($isActive) $link = '#';
|
||||
|
||||
$result .= "\t\t<li" . ($isActive ? ' class="active"' : '') . '>'
|
||||
. '<a href="' . $link . '">'
|
||||
. $caption
|
||||
. "</a></li>\n";
|
||||
}
|
||||
|
||||
return $result . "\t</ul>\n";
|
||||
}
|
||||
|
||||
function loginBar($sp = null, $pdo = null) {
|
||||
if (null === $sp) {
|
||||
$sp = 'default-sp';
|
||||
}
|
||||
$result = "\n";
|
||||
require_once __DIR__ . '/../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
|
||||
$as = new SimpleSAML\Auth\Simple($sp);
|
||||
|
||||
$svg = '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 64 64">
|
||||
<circle cx="32" cy="27" r="14" stroke-width="0" />
|
||||
<ellipse cx="32" cy="66" rx="24" ry="28" stroke-width="0" />
|
||||
</svg>
|
||||
';
|
||||
|
||||
$attr = $as->getAttributes();
|
||||
if ($attr) {
|
||||
$uname = $attr['uid'][0];
|
||||
$isAdmin = false;
|
||||
if (isset($pdo)) {
|
||||
$userManager = new pvv\admin\UserManager($pdo);
|
||||
$isAdmin = $userManager->isAdmin($uname);
|
||||
}
|
||||
$result .= "\t<a id=\"login\" href=\"#usermenu\" aria-hidden=\"true\">{$svg}" . htmlspecialchars($uname) . "</a>\n";
|
||||
|
||||
$result .= "\n\t<ul id=\"usermenu\">\n";
|
||||
$result .= "\n\t\t<li><a id=\"login\" href=\"#\">{$svg}" . htmlspecialchars($uname) . "</a></li>\n";
|
||||
if ($isAdmin) {
|
||||
$result .= "\n\t\t<li><a href=\"/admin/\">Admin</a></li>\n";
|
||||
}
|
||||
$result .= "\n\t\t<li><a href=\"" . htmlspecialchars($as->getLogoutURL()) . "\">Logg ut</a></li>\n";
|
||||
$result .= "\n\t</ul>\n";
|
||||
} else {
|
||||
$result .= "\t<a id=\"login\" href=\"" . htmlspecialchars($as->getLoginURL()) . "\">{$svg}Logg inn</a>\n";
|
||||
}
|
||||
|
||||
$result .= "\n\t<a href=\"#menu\" id=\"menu_toggle\" aria-hidden=\"true\"><big>☰ </big>MENU</a>\n";
|
||||
|
||||
return $result;
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.services.pvv-nettsiden;
|
||||
inherit (lib) mkDefault mkEnableOption mkPackageOption mkIf mkOption types mdDoc;
|
||||
format = pkgs.formats.php { };
|
||||
in
|
||||
{
|
||||
options.services.pvv-nettsiden = {
|
||||
enable = mkEnableOption (lib.mdDoc "Enable pvv-nettsiden");
|
||||
|
||||
package = mkPackageOption pkgs "pvv-nettsiden" { };
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "pvv-nettsiden";
|
||||
description = mdDoc "User to run php-fpm and own the image directories";
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "pvv-nettsiden";
|
||||
description = mdDoc "Group to run php-fpm and own the image directories";
|
||||
};
|
||||
|
||||
domainName = mkOption {
|
||||
type = types.str;
|
||||
default = "www.pvv.no";
|
||||
description = mdDoc "Domain name for the website";
|
||||
};
|
||||
|
||||
enableNginx = mkEnableOption "nginx" // { default = true; };
|
||||
useSSL = mkEnableOption "secure cookies" // { default = true; };
|
||||
|
||||
settings = mkOption {
|
||||
description = "Settings for the website";
|
||||
default = { };
|
||||
type = types.submodule {
|
||||
freeformType = format.type;
|
||||
options = lib.mapAttrsRecursiveCond
|
||||
(attrs: !(attrs ? "type"))
|
||||
(_: option: option // { type = types.either option.type format.lib.types.raw; })
|
||||
{
|
||||
DOOR_SECRET = mkOption {
|
||||
type = types.str;
|
||||
description = mdDoc "Secret for the door sensor API";
|
||||
};
|
||||
|
||||
GALLERY = {
|
||||
DIR = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/lib/pvv-nettsiden/gallery";
|
||||
description = mdDoc "Directory where the gallery is located. See documentation at TODO";
|
||||
};
|
||||
|
||||
SERVER_PATH = mkOption {
|
||||
type = types.str;
|
||||
default = "/static/gallery";
|
||||
description = mdDoc "Path to the gallery on the server";
|
||||
};
|
||||
};
|
||||
|
||||
SLIDESHOW = {
|
||||
DIR = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/lib/pvv-nettsiden/slideshow";
|
||||
description = mdDoc "Directory where the slideshow is located. See documentation at TODO";
|
||||
};
|
||||
|
||||
SERVER_PATH = mkOption {
|
||||
type = types.str;
|
||||
default = "/static/slideshow";
|
||||
description = mdDoc "Path to the slideshow on the server";
|
||||
};
|
||||
};
|
||||
|
||||
DB = {
|
||||
DSN = mkOption {
|
||||
type = types.str;
|
||||
default = "sqlite:/var/lib/pvv-nettsiden/pvv-nettsiden.db";
|
||||
example = "pgsql:host=localhost;port=5432;dbname=testdb;user=bruce;password=mypass";
|
||||
description = mdDoc "Database connection string, see https://www.php.net/manual/en/pdo.construct.php";
|
||||
};
|
||||
|
||||
USER = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
example = "pvv-nettsiden";
|
||||
description = mdDoc "Database user";
|
||||
};
|
||||
|
||||
PASS = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
description = mdDoc "Database password. Recommends: null, set in extraConfig";
|
||||
};
|
||||
};
|
||||
|
||||
SAML = {
|
||||
COOKIE_SALT = mkOption {
|
||||
type = types.str;
|
||||
description = mdDoc "Salt for the SAML cookies";
|
||||
};
|
||||
|
||||
COOKIE_SECURE = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = mdDoc "Whether to set the secure flag on the SAML cookies";
|
||||
};
|
||||
|
||||
ADMIN_NAME = mkOption {
|
||||
type = types.str;
|
||||
description = mdDoc "Name for the admin user";
|
||||
};
|
||||
|
||||
ADMIN_EMAIL = mkOption {
|
||||
type = types.str;
|
||||
description = mdDoc "Email for the admin user";
|
||||
};
|
||||
|
||||
ADMIN_PASSWORD = mkOption {
|
||||
type = types.str;
|
||||
description = mdDoc "Password for the admin user";
|
||||
};
|
||||
|
||||
TRUSTED_DOMAINS = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ cfg.domainName ];
|
||||
description = mdDoc "List of trusted domains for the SAML service";
|
||||
};
|
||||
};
|
||||
|
||||
CACHE_DIRECTORY = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/cache/pvv-nettsiden/simplesamlphp";
|
||||
description = mdDoc "List of trusted domains for the SAML service";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
config = mkIf cfg.enable (let
|
||||
# NOTE: This should absolutely not be necessary, but for some reason this file refuses to import
|
||||
# the toplevel configuration file.
|
||||
# NOTE: Nvm, don't this this was the problem after all?
|
||||
finalPackage = cfg.package.overrideAttrs (_: _: {
|
||||
postInstall = let
|
||||
f = x: lib.escapeShellArg (format.lib.valueToString x);
|
||||
in cfg.package.postInstall + ''
|
||||
substituteInPlace $out/${cfg.package.passthru.simplesamlphpPath}/config/config.php \
|
||||
--replace '$SAML_COOKIE_SECURE' ${f cfg.settings.SAML.COOKIE_SECURE} \
|
||||
--replace '$SAML_COOKIE_SALT' ${f cfg.settings.SAML.COOKIE_SALT} \
|
||||
--replace '$SAML_ADMIN_PASSWORD' ${f cfg.settings.SAML.ADMIN_PASSWORD} \
|
||||
--replace '$SAML_ADMIN_NAME' ${f cfg.settings.SAML.ADMIN_NAME} \
|
||||
--replace '$SAML_ADMIN_EMAIL' ${f cfg.settings.SAML.ADMIN_EMAIL} \
|
||||
--replace '$SAML_TRUSTED_DOMAINS' ${f cfg.settings.SAML.TRUSTED_DOMAINS} \
|
||||
--replace '$CACHE_DIRECTORY' ${f cfg.settings.CACHE_DIRECTORY}
|
||||
'';
|
||||
});
|
||||
in {
|
||||
users.users = mkIf (cfg.user == "pvv-nettsiden") {
|
||||
"pvv-nettsiden" = {
|
||||
description = "PVV Website Service User";
|
||||
group = cfg.group;
|
||||
createHome = false;
|
||||
isSystemUser = true;
|
||||
};
|
||||
};
|
||||
|
||||
users.groups = mkIf (cfg.group == "pvv-nettsiden") {
|
||||
"pvv-nettsiden" = { };
|
||||
};
|
||||
|
||||
systemd.tmpfiles.settings."10-pvv-nettsiden".${cfg.settings.CACHE_DIRECTORY}.d = {
|
||||
inherit (cfg) user group;
|
||||
mode = "0770";
|
||||
};
|
||||
|
||||
services.nginx = mkIf cfg.enableNginx {
|
||||
enable = true;
|
||||
|
||||
recommendedGzipSettings = mkDefault true;
|
||||
recommendedProxySettings = mkDefault true;
|
||||
|
||||
virtualHosts."${cfg.domainName}" = {
|
||||
forceSSL = mkDefault cfg.useSSL;
|
||||
enableACME = mkDefault true;
|
||||
locations = {
|
||||
"/" = {
|
||||
root = "${finalPackage}/share/php/pvv-nettsiden/www/";
|
||||
index = "index.php";
|
||||
};
|
||||
|
||||
"~ \\.php$".extraConfig = ''
|
||||
include ${pkgs.nginx}/conf/fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME ${finalPackage}/share/php/pvv-nettsiden/www$fastcgi_script_name;
|
||||
fastcgi_pass unix:${config.services.phpfpm.pools."pvv-nettsiden".socket};
|
||||
'';
|
||||
|
||||
# based on https://simplesamlphp.org/docs/stable/simplesamlphp-install.html#configuring-nginx
|
||||
"^~ /simplesaml/" = {
|
||||
alias = "${finalPackage}/${finalPackage.passthru.simplesamlphpPath}/public/";
|
||||
index = "index.php";
|
||||
|
||||
extraConfig = ''
|
||||
location ~ ^/simplesaml/(?<phpfile>.+?\.php)(?<pathinfo>/.*)?$ {
|
||||
include ${pkgs.nginx}/conf/fastcgi_params;
|
||||
fastcgi_pass unix:${config.services.phpfpm.pools."pvv-nettsiden".socket};
|
||||
fastcgi_param SCRIPT_FILENAME ${finalPackage}/${finalPackage.passthru.simplesamlphpPath}/public/$phpfile;
|
||||
|
||||
# Must be prepended with the baseurlpath
|
||||
fastcgi_param SCRIPT_NAME /simplesaml/$phpfile;
|
||||
|
||||
fastcgi_param PATH_INFO $pathinfo if_not_empty;
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
"^~ ${cfg.settings.GALLERY.SERVER_PATH}" = {
|
||||
root = cfg.settings.GALLERY.DIR;
|
||||
extraConfig = ''
|
||||
rewrite ^${cfg.settings.GALLERY.SERVER_PATH}/(.*)$ /$1 break;
|
||||
'';
|
||||
};
|
||||
|
||||
"^~ ${cfg.settings.SLIDESHOW.SERVER_PATH}" = {
|
||||
root = cfg.settings.SLIDESHOW.DIR;
|
||||
extraConfig = ''
|
||||
rewrite ^${cfg.settings.SLIDESHOW.SERVER_PATH}/(.*)$ /$1 break;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
services.phpfpm.pools.pvv-nettsiden = {
|
||||
user = cfg.user;
|
||||
group = cfg.group;
|
||||
|
||||
phpEnv.PVV_CONFIG_FILE = toString (format.generate "pvv-nettsiden-conf.php" cfg.settings);
|
||||
|
||||
settings = {
|
||||
"listen.owner" = config.services.nginx.user;
|
||||
"listen.group" = config.services.nginx.group;
|
||||
"pm" = mkDefault "ondemand";
|
||||
"pm.max_children" = mkDefault 32;
|
||||
"pm.process_idle_timeout" = mkDefault "10s";
|
||||
"pm.max_requests" = mkDefault 500;
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{ lib
|
||||
, php
|
||||
, extra_files ? { }
|
||||
}:
|
||||
|
||||
php.buildComposerProject rec {
|
||||
src = lib.fileset.toSource {
|
||||
root = ./..;
|
||||
fileset = lib.fileset.difference
|
||||
(lib.fileset.unions [
|
||||
../dist
|
||||
../inc
|
||||
../src
|
||||
../www
|
||||
../composer.json
|
||||
../composer.lock
|
||||
])
|
||||
(lib.fileset.unions [
|
||||
(lib.fileset.maybeMissing ../www/simplesaml)
|
||||
(lib.fileset.maybeMissing ../www/simplesaml-idp)
|
||||
]);
|
||||
};
|
||||
pname = "pvv-nettsiden";
|
||||
version = "0.0.1";
|
||||
vendorHash = "sha256-SxuKP7CCLXbTtKQ1seLpAqUje+SEAJ1R+gK09UW2T9k=";
|
||||
|
||||
passthru.simplesamlphpPath = "share/php/pvv-nettsiden/vendor/simplesamlphp/simplesamlphp";
|
||||
|
||||
postInstall = ''
|
||||
install -Dm644 dist/simplesaml-prod/config.php "$out"/${passthru.simplesamlphpPath}/config/config.php
|
||||
install -Dm644 dist/simplesaml-prod/authsources.php "$out"/${passthru.simplesamlphpPath}/config/authsources.php
|
||||
install -Dm644 dist/simplesaml-prod/saml20-idp-remote.php "$out"/${passthru.simplesamlphpPath}/metadata/saml20-idp-remote.php
|
||||
install -Dm644 dist/config.source-env.php "$out"/share/php/pvv-nettsiden/config.php
|
||||
|
||||
${lib.pipe extra_files [
|
||||
(lib.mapAttrsToList (target_path: source_path: ''
|
||||
mkdir -p $(dirname "$out/${target_path}")
|
||||
cp -r "${source_path}" "$out/${target_path}"
|
||||
''))
|
||||
(lib.concatStringsSep "\n")
|
||||
]}
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
{ pkgs, lib }:
|
||||
|
||||
with lib;
|
||||
|
||||
{ }: let
|
||||
valueToString = val:
|
||||
if val == null then
|
||||
"null"
|
||||
else if isString val then
|
||||
builtins.toJSON val
|
||||
else if isBool val then
|
||||
boolToString val
|
||||
else if isInt val || isFloat val then
|
||||
toString val
|
||||
else if isList val then
|
||||
"array(${concatMapStringsSep ", " valueToString val})"
|
||||
else if isAttrs val && val ? value && (val._type or "") == "raw" then
|
||||
val.value
|
||||
else if isAttrs val then
|
||||
throw "Found unexpected attrs, that were not created by mkRaw. Have you put attrs in an array?\n${val}"
|
||||
else throw "unsupported :')";
|
||||
in {
|
||||
inherit (pkgs.formats.json { }) type;
|
||||
|
||||
generate = name: value: let
|
||||
flattenStructuredSettings = attrs: let
|
||||
partitionAttrs = pred: attrs: lib.pipe attrs [
|
||||
attrsToList
|
||||
(partition ({ name, value }: pred name value))
|
||||
(mapAttrs (_: listToAttrs))
|
||||
];
|
||||
|
||||
partitionedAttrs = partitionAttrs (_: v: isAttrs v && !(v ? value && (v._type or "") == "raw")) attrs;
|
||||
|
||||
flattenedAttrs = lib.pipe partitionedAttrs.right [
|
||||
(mapAttrs (n1: mapAttrs' (n2: v2: nameValuePair "${n1}_${n2}" v2)))
|
||||
attrValues
|
||||
(map flattenStructuredSettings)
|
||||
(foldl recursiveUpdate { })
|
||||
];
|
||||
in recursiveUpdate flattenedAttrs partitionedAttrs.wrong;
|
||||
|
||||
content = lib.pipe value [
|
||||
flattenStructuredSettings
|
||||
(mapAttrs (_: valueToString))
|
||||
(mapAttrsToList (n: v: ''''$${n} = ${v};''))
|
||||
(concatStringsSep "\n")
|
||||
(content: "<?php\n${content}\n?>")
|
||||
];
|
||||
in pkgs.writeText name content;
|
||||
|
||||
lib = {
|
||||
inherit valueToString;
|
||||
|
||||
mkRaw = value: {
|
||||
inherit value;
|
||||
_type = "raw";
|
||||
};
|
||||
|
||||
types.raw = lib.types.attrs;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{ pkgs }:
|
||||
let
|
||||
phpEnv = pkgs.php84.buildEnv {
|
||||
extensions = { enabled, all }: enabled ++ (with all; [ iconv mbstring pdo_mysql pdo_sqlite ]);
|
||||
};
|
||||
in
|
||||
pkgs.mkShellNoCC {
|
||||
buildInputs = with pkgs; [
|
||||
phpEnv
|
||||
php84Packages.composer
|
||||
php84Packages.php-parallel-lint
|
||||
php84Packages.php-cs-fixer
|
||||
sqlite-interactive
|
||||
sql-formatter
|
||||
openssl
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REQUIRED_COMMANDS=(git grep)
|
||||
MISSING_COMMANDS=false
|
||||
for cmd in "${REQUIRED_COMMANDS[@]}"; do
|
||||
if ! command -v "$cmd" &> /dev/null; then
|
||||
echo "$cmd could not be found" >&2
|
||||
MISSING_COMMANDS=true
|
||||
fi
|
||||
done
|
||||
if [ "$MISSING_COMMANDS" = true ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
declare -r GIT_TREE_IS_DIRTY="$(
|
||||
if ! git diff --quiet --ignore-submodules \
|
||||
|| git ls-files --others --exclude-standard | grep -q .; then
|
||||
echo 1
|
||||
else
|
||||
echo 0
|
||||
fi
|
||||
)"
|
||||
|
||||
if [ "$GIT_TREE_IS_DIRTY" == "1" ]; then
|
||||
echo "Git working tree is dirty, refusing to reset" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
declare -r PROJECT_ROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
(
|
||||
cd "$PROJECT_ROOT"
|
||||
git clean -fdx
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REQUIRED_COMMANDS=(git)
|
||||
MISSING_COMMANDS=false
|
||||
for cmd in "${REQUIRED_COMMANDS[@]}"; do
|
||||
if ! command -v "$cmd" &> /dev/null; then
|
||||
echo "$cmd could not be found" >&2
|
||||
MISSING_COMMANDS=true
|
||||
fi
|
||||
done
|
||||
if [ "$MISSING_COMMANDS" = true ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
declare -r PROJECT_ROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
"$PROJECT_ROOT/scripts/clean.sh"
|
||||
"$PROJECT_ROOT/scripts/setup.sh"
|
||||
"$PROJECT_ROOT/scripts/seed-test-data.sh"
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REQUIRED_COMMANDS=(
|
||||
php
|
||||
)
|
||||
MISSING_COMMANDS=false
|
||||
for cmd in "${REQUIRED_COMMANDS[@]}"; do
|
||||
if ! command -v "$cmd" &> /dev/null; then
|
||||
echo "$cmd could not be found" >&2
|
||||
MISSING_COMMANDS=true
|
||||
fi
|
||||
done
|
||||
if [ "$MISSING_COMMANDS" = true ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
declare -r PROJECT_ROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
# Check for hints that our project might not be correctly set up
|
||||
if [ ! -d "$PROJECT_ROOT/vendor" ] \
|
||||
|| [ ! -f "$PROJECT_ROOT/config.php" ] \
|
||||
|| [ ! -d "$PROJECT_ROOT/www/simplesaml" ] \
|
||||
|| [ ! -d "$PROJECT_ROOT/www/galleri/bilder" ]; then
|
||||
echo "It looks like the project is not correctly set up." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
declare -a PHP_ARGS=(
|
||||
-S localhost:1080
|
||||
-d error_reporting=E_ALL
|
||||
-d display_errors=1
|
||||
-t www/
|
||||
)
|
||||
|
||||
(cd "$PROJECT_ROOT" && php "${PHP_ARGS[@]}")
|
||||
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REQUIRED_COMMANDS=(
|
||||
sqlite3
|
||||
)
|
||||
MISSING_COMMANDS=false
|
||||
for cmd in "${REQUIRED_COMMANDS[@]}"; do
|
||||
if ! command -v "$cmd" &> /dev/null; then
|
||||
echo "$cmd could not be found" >&2
|
||||
MISSING_COMMANDS=true
|
||||
fi
|
||||
done
|
||||
if [ "$MISSING_COMMANDS" = true ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
declare -r PROJECT_ROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
if [ ! -f "$PROJECT_ROOT/pvv.sqlite" ] ; then
|
||||
echo "Database file $PROJECT_ROOT/pvv.sqlite does not exist. Please run setup.sh first." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sqlite3 "$PROJECT_ROOT/pvv.sqlite" < "$PROJECT_ROOT/dist/sql/test_data_sqlite.sql"
|
||||
|
||||
# Loop over the last 4 days' unix timestamps in 5-minute intervals and insert test data
|
||||
END_TIME=$(date +%s)
|
||||
START_TIME=$((END_TIME - 4 * 24 * 60 * 60))
|
||||
for ((timestamp=START_TIME; timestamp<=END_TIME; timestamp+=60 * 5 * 10)); do
|
||||
RANDOM_YES_NO=$((RANDOM % 2))
|
||||
sqlite3 "$PROJECT_ROOT/pvv.sqlite" <<EOF
|
||||
INSERT INTO
|
||||
door(time, open)
|
||||
VALUES
|
||||
($timestamp + 60 * 5 * 0, $RANDOM_YES_NO),
|
||||
($timestamp + 60 * 5 * 1, $RANDOM_YES_NO),
|
||||
($timestamp + 60 * 5 * 2, $RANDOM_YES_NO),
|
||||
($timestamp + 60 * 5 * 3, $RANDOM_YES_NO),
|
||||
($timestamp + 60 * 5 * 4, $RANDOM_YES_NO),
|
||||
($timestamp + 60 * 5 * 5, $RANDOM_YES_NO),
|
||||
($timestamp + 60 * 5 * 6, $RANDOM_YES_NO),
|
||||
($timestamp + 60 * 5 * 7, $RANDOM_YES_NO),
|
||||
($timestamp + 60 * 5 * 8, $RANDOM_YES_NO),
|
||||
($timestamp + 60 * 5 * 9, $RANDOM_YES_NO);
|
||||
EOF
|
||||
done
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REQUIRED_COMMANDS=(
|
||||
git
|
||||
composer
|
||||
sqlite3
|
||||
openssl
|
||||
install
|
||||
)
|
||||
MISSING_COMMANDS=false
|
||||
for cmd in "${REQUIRED_COMMANDS[@]}"; do
|
||||
if ! command -v "$cmd" &> /dev/null; then
|
||||
echo "$cmd could not be found" >&2
|
||||
MISSING_COMMANDS=true
|
||||
fi
|
||||
done
|
||||
if [ "$MISSING_COMMANDS" = true ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
declare -r PROJECT_ROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
mkdir -p "$PROJECT_ROOT/www/galleri/bilder/slideshow"
|
||||
test -e "$PROJECT_ROOT/pvv.sqlite" || sqlite3 "$PROJECT_ROOT/pvv.sqlite" < "$PROJECT_ROOT/dist/sql/pvv_sqlite.sql"
|
||||
test -e "$PROJECT_ROOT/config.php" || cp -v "$PROJECT_ROOT/dist/config.local.php" "$PROJECT_ROOT/config.php"
|
||||
|
||||
if [ ! -d "$PROJECT_ROOT/vendor" ] ; then
|
||||
pushd "$PROJECT_ROOT"
|
||||
composer install || exit $?
|
||||
|
||||
# Set up SimpleSAMLphp identity provider (for local testing)
|
||||
install -m644 dist/simplesaml-dev/authsources.php -t vendor/simplesamlphp/simplesamlphp/config/
|
||||
install -m644 dist/simplesaml-dev/config.php -t vendor/simplesamlphp/simplesamlphp/config/
|
||||
install -m644 dist/simplesaml-dev/saml20-idp-remote.php -t vendor/simplesamlphp/simplesamlphp/metadata/
|
||||
install -m644 dist/simplesaml-dev/saml20-idp-hosted.php -t vendor/simplesamlphp/simplesamlphp/metadata/
|
||||
install -m644 dist/simplesaml-dev/saml20-sp-remote.php -t vendor/simplesamlphp/simplesamlphp/metadata/
|
||||
|
||||
# See session.phpsession.savepath in config.php
|
||||
mkdir -p vendor/simplesamlphp/simplesamlphp/sessions/
|
||||
|
||||
openssl req \
|
||||
-newkey rsa:4096 \
|
||||
-new \
|
||||
-x509 \
|
||||
-days 3652 \
|
||||
-nodes \
|
||||
-out vendor/simplesamlphp/simplesamlphp/cert/localhost.crt \
|
||||
-keyout vendor/simplesamlphp/simplesamlphp/cert/localhost.pem \
|
||||
-subj "/C=NO/ST=Trondheim/L=Trondheim/O=Programvareverkstedet/CN=localhost"
|
||||
|
||||
cp dist/config.local.php config.php
|
||||
|
||||
ln -s ../vendor/simplesamlphp/simplesamlphp/public/ www/simplesaml
|
||||
popd
|
||||
fi
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/*
|
||||
* Copyright (c) 2014-2015, Jørn Åne de Jong <@jornane>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* Register SPL autoloading for classes and interfaces. Put this file in your
|
||||
* namespace root and make sure it gets included from your PHP entry-point.
|
||||
*
|
||||
* There is no requirement for capitalisation for your namespaces and classes,
|
||||
* but all folders and files MUST be lower-case. Class names are automatically
|
||||
* lower-cased on autoload. This conforms to the PHP design philosophy that
|
||||
* functions and class names must be case-insensitive.
|
||||
*
|
||||
* The include path is changed to prefer the current directory over the
|
||||
* established include path. This is because manual include/require statements
|
||||
* will likely not be used, because it will be handled by autoloading.
|
||||
* Feel free to change this behaviour if that works better for you.
|
||||
*
|
||||
* @author Jørn Åne de Jong <@jornane>
|
||||
* @copyright Copyright (c) 2014-2015, Jørn Åne de Jong <@jornane>
|
||||
* @link https://gist.github.com/jornane/667f2e3acc262ce6bf44
|
||||
* @link http://php.net/manual/en/function.spl-autoload.php
|
||||
* @license http://choosealicense.com/licenses/isc/ ISC license
|
||||
*/
|
||||
spl_autoload_extensions('.php');
|
||||
spl_autoload_register('spl_autoload');
|
||||
set_include_path(realpath(__DIR__).\PATH_SEPARATOR.get_include_path());
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\admin;
|
||||
|
||||
class UserManager {
|
||||
private \PDO $pdo;
|
||||
|
||||
public array $usergroups = [
|
||||
'admin' => 1,
|
||||
'prosjekt' => 2,
|
||||
'aktiviteter' => 4,
|
||||
];
|
||||
|
||||
public function __construct(\PDO $pdo) {
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
public function setupUser(string $uname, int $groups = 0): void {
|
||||
$query = 'INSERT INTO users (uname, groups) VALUES (:uname, :groups)';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->bindValue(':uname', $uname, \PDO::PARAM_STR);
|
||||
$statement->bindValue(':groups', $groups, \PDO::PARAM_INT);
|
||||
$statement->execute();
|
||||
}
|
||||
|
||||
public function updateFlags(string $uname, int $flags): void {
|
||||
$query = 'UPDATE users set groups=:groups WHERE uname=:uname';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->bindValue(':groups', $flags, \PDO::PARAM_INT);
|
||||
$statement->bindValue(':uname', $uname, \PDO::PARAM_STR);
|
||||
}
|
||||
|
||||
public function addGroup(string $uname, int $group): void {
|
||||
$userFlags = $this->getUsergroups($uname);
|
||||
|
||||
if ($userFlags) {
|
||||
$newFlags = ($group | $userFlags);
|
||||
$this->updateFlags($uname, $newFlags);
|
||||
}
|
||||
}
|
||||
|
||||
public function removeGroup(string $uname, int $group): void {
|
||||
$userFlags = $this->getUsergroups($uname);
|
||||
|
||||
if ($userFlags) {
|
||||
$newFlags = ($userFlags & (~$group));
|
||||
$this->updateFlags($uname, $newFlags);
|
||||
}
|
||||
}
|
||||
|
||||
public function setGroups(string $uname, int $groups): void {
|
||||
$query = 'SELECT * FROM users WHERE uname=:uname LIMIT 1';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->bindValue(':uname', $uname, \PDO::PARAM_STR);
|
||||
$statement->execute();
|
||||
$row = $statement->fetch();
|
||||
|
||||
if ($row) {
|
||||
$query = 'UPDATE users set groups=:groups WHERE uname=:uname';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->bindValue(':groups', $groups, \PDO::PARAM_INT);
|
||||
$statement->bindValue(':uname', $uname, \PDO::PARAM_STR);
|
||||
$statement->execute();
|
||||
} else {
|
||||
$this->setupUser($uname, $groups);
|
||||
}
|
||||
}
|
||||
|
||||
public function hasGroup(string $uname, string $groupName): bool {
|
||||
$userFlags = $this->getUsergroups($uname);
|
||||
|
||||
return (bool) ($userFlags & $this->usergroups[$groupName]);
|
||||
}
|
||||
|
||||
// for convenience
|
||||
public function isAdmin(string $uname): bool {
|
||||
return $this->hasGroup($uname, 'admin');
|
||||
}
|
||||
|
||||
public function getFlagfromNames(array $names): int {
|
||||
$resultFlag = 0;
|
||||
|
||||
foreach ($this->usergroups as $name => $flag) {
|
||||
if (\in_array($name, $names, true)) {
|
||||
$resultFlag = ($resultFlag | $flag);
|
||||
}
|
||||
}
|
||||
|
||||
return $resultFlag;
|
||||
}
|
||||
|
||||
public function getUsergroups(string $uname): int {
|
||||
$query = 'SELECT groups FROM users WHERE uname=:uname LIMIT 1';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->bindValue(':uname', $uname, \PDO::PARAM_STR);
|
||||
$statement->execute();
|
||||
|
||||
$row = $statement->fetch();
|
||||
if ($row === false) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $row[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getUsergroupNames($uname): array {
|
||||
$usersGroups = [];
|
||||
|
||||
$userFlags = $this->getUsergroups($uname);
|
||||
|
||||
foreach ($this->usergroups as $name => $flag) {
|
||||
if ($userFlags & $flag) {
|
||||
$usersGroups[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
return $usersGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int,array{name:string,groups:string[]}>
|
||||
*/
|
||||
public function getAllUserData(): array {
|
||||
$query = 'SELECT uname FROM users ORDER BY uname ASC';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->execute();
|
||||
|
||||
$users = [];
|
||||
foreach ($statement->fetchAll() as $userData) {
|
||||
$uname = $userData['uname'];
|
||||
$users[] = [
|
||||
'name' => $uname,
|
||||
'groups' => $this->getUsergroupNames($uname),
|
||||
];
|
||||
}
|
||||
|
||||
return $users;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side;
|
||||
|
||||
interface Activity {
|
||||
public function getNextEventFrom(\DateTimeImmutable $date): ?Event;
|
||||
|
||||
public function getPreviousEventFrom(\DateTimeImmutable $date): ?Event;
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side;
|
||||
|
||||
class Agenda {
|
||||
private array $activities;
|
||||
|
||||
public const int TODAY = 0;
|
||||
public const int TOMORROW = 1;
|
||||
public const int THIS_WEEK = 2;
|
||||
public const int NEXT_WEEK = 3;
|
||||
public const int THIS_MONTH = 4;
|
||||
public const int NEXT_MONTH = 5;
|
||||
|
||||
/**
|
||||
* @param array<int,DBActivity> $activities
|
||||
*/
|
||||
public function __construct(array $activities) {
|
||||
$this->activities = $activities;
|
||||
}
|
||||
|
||||
public static function getFormattedDate(\DateTimeImmutable $date): string {
|
||||
return $date->format('l j. M H.i');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Event>
|
||||
*/
|
||||
public function getEventsBetween(
|
||||
\DateTimeImmutable $from,
|
||||
\DateTimeImmutable $to,
|
||||
) {
|
||||
$results = [];
|
||||
for ($i = 0; $i < \count($this->activities); ++$i) {
|
||||
$result = [];
|
||||
do {
|
||||
$run = false;
|
||||
if (\count($result)) {
|
||||
$date = end($result)->getStop();
|
||||
} else {
|
||||
$date = $from;
|
||||
}
|
||||
$next = $this->activities[$i]->getNextEventFrom($date);
|
||||
if (isset($next) && $next->getStart() < $to) {
|
||||
$result[] = $this->activities[$i]->getNextEventFrom($date);
|
||||
$run = true;
|
||||
}
|
||||
} while ($run);
|
||||
$results[] = $result;
|
||||
}
|
||||
$result = [];
|
||||
foreach ($results as $a) {
|
||||
foreach ($a as $b) {
|
||||
$result[] = $b;
|
||||
}
|
||||
}
|
||||
usort(
|
||||
$result,
|
||||
static fn ($a, $b) => $a->getStart() < $b->getStart() ? -1 : 1,
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int,array>
|
||||
*/
|
||||
public function getNextDays(): array {
|
||||
$result = [[], [], [], [], [], []];
|
||||
$events = $this->getEventsBetween(
|
||||
new \DateTimeImmutable()->setTime(0, 0),
|
||||
new \DateTimeImmutable()->setTime(23, 59)->add(new \DateInterval('P1M')),
|
||||
);
|
||||
foreach ($events as $event) {
|
||||
$index = self::NEXT_MONTH;
|
||||
if (self::isToday($event->getStart())) {
|
||||
$index = self::TODAY;
|
||||
} elseif (self::isTomorrow($event->getStart())) {
|
||||
$index = self::TOMORROW;
|
||||
} elseif (self::isThisWeek($event->getStart())) {
|
||||
$index = self::THIS_WEEK;
|
||||
} elseif (self::isNextWeek($event->getStart())) {
|
||||
$index = self::NEXT_WEEK;
|
||||
} elseif (self::isThisMonth($event->getStart())) {
|
||||
$index = self::THIS_MONTH;
|
||||
}
|
||||
$result[$index][] = $event;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Event>
|
||||
*/
|
||||
public function getNextOfEach(\DateTimeImmutable $startDate): array {
|
||||
$result = array_filter(
|
||||
array_map(
|
||||
static fn ($a) => $a->getNextEventFrom($startDate),
|
||||
$this->activities,
|
||||
),
|
||||
static fn ($a) => isset($a),
|
||||
);
|
||||
usort(
|
||||
$result,
|
||||
static fn ($a, $b) => $a->getStart()->getTimeStamp()
|
||||
< $b->getStart()->getTimeStamp()
|
||||
? -1
|
||||
: 1,
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function isToday(\DateTimeImmutable $date): bool {
|
||||
return $date->format('dmY') === date('dmY');
|
||||
}
|
||||
|
||||
public static function isTomorrow(\DateTimeImmutable $date): bool {
|
||||
return $date->sub(new \DateInterval('P1D'))->format('dmY') === date('dmY');
|
||||
}
|
||||
|
||||
public static function isThisWeek(\DateTimeImmutable $date): bool {
|
||||
return $date->format('WY') === date('WY');
|
||||
}
|
||||
|
||||
public static function isNextWeek(\DateTimeImmutable $date): bool {
|
||||
return $date->sub(new \DateInterval('P7D'))->format('WY') === date('WY');
|
||||
}
|
||||
|
||||
public static function isThisMonth(\DateTimeImmutable $date): bool {
|
||||
return $date->format('mY') === date('mY');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side;
|
||||
|
||||
class DBActivity implements Activity {
|
||||
private $pdo;
|
||||
|
||||
public function __construct(\PDO $pdo) {
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEvent[]
|
||||
*/
|
||||
public function getAllEvents(): array {
|
||||
$query = 'SELECT * FROM events ORDER BY id DESC';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->execute();
|
||||
|
||||
$events = [];
|
||||
foreach ($statement->fetchAll() as $dbEvent) {
|
||||
$event = new SimpleEvent(
|
||||
$dbEvent['id'],
|
||||
$dbEvent['name'],
|
||||
\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $dbEvent['start']),
|
||||
\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $dbEvent['stop']),
|
||||
$dbEvent['organiser'],
|
||||
$dbEvent['location'],
|
||||
$dbEvent['description'],
|
||||
);
|
||||
$events[] = $event;
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
public function getEventByID(int $id): SimpleEvent {
|
||||
$query = 'SELECT * FROM events WHERE id=:id LIMIT 1';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->bindValue(':id', $id, \PDO::PARAM_INT);
|
||||
$statement->execute();
|
||||
|
||||
$dbEvent = $statement->fetch();
|
||||
|
||||
return new SimpleEvent(
|
||||
$dbEvent['id'],
|
||||
$dbEvent['name'],
|
||||
\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $dbEvent['start']),
|
||||
\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $dbEvent['stop']),
|
||||
$dbEvent['organiser'],
|
||||
$dbEvent['location'],
|
||||
$dbEvent['description'],
|
||||
);
|
||||
}
|
||||
|
||||
public function getNextEventFrom(\DateTimeImmutable $date): ?Event {
|
||||
$query = '
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
start,
|
||||
stop,
|
||||
organiser,
|
||||
location,
|
||||
description
|
||||
FROM events
|
||||
WHERE
|
||||
start > :date
|
||||
ORDER BY start ASC
|
||||
LIMIT 1
|
||||
';
|
||||
|
||||
return $this->retrieve($date, $query);
|
||||
}
|
||||
|
||||
public function getPreviousEventFrom(\DateTimeImmutable $date): ?Event {
|
||||
$query = '
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
start,
|
||||
stop,
|
||||
organiser,
|
||||
location,
|
||||
description
|
||||
FROM events
|
||||
WHERE
|
||||
start < :date
|
||||
ORDER BY start DESC
|
||||
LIMIT 1
|
||||
';
|
||||
|
||||
return $this->retrieve($date, $query);
|
||||
}
|
||||
|
||||
private function retrieve(
|
||||
\DateTimeImmutable $date,
|
||||
string $query,
|
||||
): ?SimpleEvent {
|
||||
$stmt = $this->pdo->prepare($query);
|
||||
$stmt->execute(['date' => $date->format('Y-m-d H:i:s')]);
|
||||
if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
return new SimpleEvent(
|
||||
$result['id'],
|
||||
$result['name'],
|
||||
\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $result['start']),
|
||||
\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $result['stop']),
|
||||
$result['organiser'],
|
||||
$result['location'],
|
||||
$result['description'],
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side;
|
||||
|
||||
class DoorStatus {
|
||||
private \DateTimeImmutable $time;
|
||||
private bool $open;
|
||||
|
||||
public function __construct(\DateTimeImmutable $time, bool $open) {
|
||||
$this->time = $time;
|
||||
$this->open = $open;
|
||||
}
|
||||
|
||||
public function getTime(): \DateTimeImmutable {
|
||||
return $this->time;
|
||||
}
|
||||
|
||||
public function getTimeStamp(): int {
|
||||
return $this->time->getTimestamp();
|
||||
}
|
||||
|
||||
public function isOpen(): bool {
|
||||
return $this->open;
|
||||
}
|
||||
}
|
||||
|
||||
class Door {
|
||||
private $pdo;
|
||||
|
||||
public const DAYS_OF_DOOR_HISTORY = 7;
|
||||
|
||||
public function __construct(\PDO $pdo) {
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DoorStatus[]
|
||||
*/
|
||||
public function getAll(): array {
|
||||
$query = '
|
||||
SELECT
|
||||
time,
|
||||
open
|
||||
FROM door
|
||||
ORDER BY time DESC
|
||||
';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->execute();
|
||||
|
||||
$result = array_map(
|
||||
static fn ($row) => new DoorStatus(
|
||||
new \DateTimeImmutable()->setTimestamp((int) $row['time']),
|
||||
(bool) $row['open'],
|
||||
),
|
||||
$statement->fetchAll(),
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DoorStatus[]
|
||||
*/
|
||||
public function getEntriesAfter(\DateTimeImmutable $startTime): array {
|
||||
$query = '
|
||||
SELECT
|
||||
time,
|
||||
open
|
||||
FROM door
|
||||
WHERE time > :startTime
|
||||
ORDER BY time DESC
|
||||
';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->bindValue(':startTime', $startTime->getTimestamp(), \PDO::PARAM_INT);
|
||||
$statement->execute();
|
||||
|
||||
$result = array_map(
|
||||
static fn ($row) => new DoorStatus(
|
||||
new \DateTimeImmutable()->setTimestamp((int) $row['time']),
|
||||
(bool) $row['open'],
|
||||
),
|
||||
$statement->fetchAll(),
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getCurrent(): ?DoorStatus {
|
||||
$query = '
|
||||
SELECT
|
||||
time,
|
||||
open
|
||||
FROM door
|
||||
ORDER BY time DESC
|
||||
LIMIT 1
|
||||
';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->execute();
|
||||
$row = $statement->fetch();
|
||||
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DoorStatus(
|
||||
new \DateTimeImmutable()->setTimestamp((int) $row['time']),
|
||||
(bool) $row['open'],
|
||||
);
|
||||
}
|
||||
|
||||
private function removeOld(): void {
|
||||
$firstValidTime = time() - 60 * 60 * 24 * self::DAYS_OF_DOOR_HISTORY;
|
||||
$query = 'DELETE FROM door WHERE time < :firstValid';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->bindValue(':firstValid', $firstValidTime, \PDO::PARAM_INT);
|
||||
$statement->execute();
|
||||
}
|
||||
|
||||
public function createEvent(\DateTimeImmutable $time, bool $open): void {
|
||||
$query = 'INSERT INTO door(time, open) VALUES (:time, :open)';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->bindValue(':time', $time->getTimestamp(), \PDO::PARAM_INT);
|
||||
$statement->bindValue(':open', $open, \PDO::PARAM_BOOL);
|
||||
$statement->execute();
|
||||
|
||||
$this->removeOld();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side;
|
||||
|
||||
abstract class Event {
|
||||
private \DateTimeImmutable $start;
|
||||
|
||||
public function __construct(\DateTimeImmutable $start) {
|
||||
$this->start = $start;
|
||||
}
|
||||
|
||||
public function getStart(): \DateTimeImmutable {
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
public function getRelativeDate(): string {
|
||||
if (Agenda::isToday($this->getStart())) {
|
||||
return 'i dag';
|
||||
}
|
||||
if (Agenda::isTomorrow($this->getStart())) {
|
||||
return 'i morgen';
|
||||
}
|
||||
if (
|
||||
Agenda::isThisWeek($this->getStart())
|
||||
|| $this->getStart()->sub(new \DateInterval('P4D'))->getTimestamp() < time()
|
||||
) {
|
||||
return $this->getStart()->format('l');
|
||||
}
|
||||
if (Agenda::isNextWeek($this->getStart())) {
|
||||
return 'neste uke';
|
||||
}
|
||||
if (Agenda::isThisMonth($this->getStart())) {
|
||||
return 'denne måneden';
|
||||
}
|
||||
|
||||
return $this->getStart()->format('j. F');
|
||||
}
|
||||
|
||||
abstract public function getStop(): \DateTimeImmutable;
|
||||
|
||||
abstract public function getName(): string;
|
||||
|
||||
abstract public function getLocation(): string;
|
||||
|
||||
abstract public function getOrganiser(): string;
|
||||
|
||||
abstract public function getURL(): string;
|
||||
|
||||
abstract public function getImageURL(): string;
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
abstract public function getDescription(): array;
|
||||
|
||||
abstract public function getColor(): string;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side;
|
||||
|
||||
class MOTDItem {
|
||||
private string $title;
|
||||
/** @var string[] */
|
||||
private array $content;
|
||||
|
||||
/**
|
||||
* @param string[] $content
|
||||
*/
|
||||
public function __construct(string $title, array $content) {
|
||||
$this->title = $title;
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
public function getTitle(): string {
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getContent(): array {
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function getContentAsString(): string {
|
||||
return implode("\n", $this->content);
|
||||
}
|
||||
}
|
||||
|
||||
class MOTD {
|
||||
private $pdo;
|
||||
|
||||
public function __construct(\PDO $pdo) {
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
public function setMOTD(string $title, string $content): void {
|
||||
if (\is_array($content)) {
|
||||
$content = implode('_', $content);
|
||||
}
|
||||
$query = 'INSERT INTO motd(title, content) VALUES (:title, :content)';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
|
||||
$statement->bindValue(':title', $title, \PDO::PARAM_STR);
|
||||
$statement->bindValue(':content', $content, \PDO::PARAM_STR);
|
||||
|
||||
$statement->execute();
|
||||
}
|
||||
|
||||
public function getMOTD(): MOTDItem {
|
||||
$query = '
|
||||
SELECT
|
||||
title,
|
||||
content
|
||||
FROM motd
|
||||
ORDER BY id DESC
|
||||
LIMIT 1
|
||||
';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->execute();
|
||||
|
||||
$data = $statement->fetch();
|
||||
|
||||
return new MOTDItem(
|
||||
$data['title'],
|
||||
explode("\n", $data['content']),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MOTDItem[]
|
||||
*/
|
||||
public function getMOTD_history(int $limit = 5): array {
|
||||
$query = '
|
||||
SELECT
|
||||
title,
|
||||
content
|
||||
FROM motd
|
||||
ORDER BY id DESC
|
||||
LIMIT :limit
|
||||
';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->bindValue(':limit', $limit, \PDO::PARAM_STR);
|
||||
$statement->execute();
|
||||
|
||||
$result = array_map(
|
||||
static fn ($item) => new MOTDItem(
|
||||
$item['title'],
|
||||
explode("\n", $item['content']),
|
||||
),
|
||||
$statement->fetchAll(),
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side;
|
||||
|
||||
class Project {
|
||||
private int $id;
|
||||
private string $title;
|
||||
private array $description_en;
|
||||
private array $description_no;
|
||||
private ?string $gitea_link;
|
||||
private ?string $issue_board_link;
|
||||
private ?string $wiki_link;
|
||||
private array $programming_languages;
|
||||
private array $technologies;
|
||||
private array $keywords;
|
||||
// NOTE: spdx identifier
|
||||
private ?string $license;
|
||||
private ?string $logo_url;
|
||||
private bool $is_hidden;
|
||||
|
||||
public function __construct(
|
||||
int $id,
|
||||
string $title,
|
||||
?string $description_en,
|
||||
?string $description_no,
|
||||
?string $gitea_link,
|
||||
?string $issue_board_link,
|
||||
?string $wiki_link,
|
||||
?string $programming_languages,
|
||||
?string $technologies,
|
||||
?string $keywords,
|
||||
?string $license,
|
||||
?string $logo_url,
|
||||
bool $is_hidden = false,
|
||||
) {
|
||||
$this->id = $id;
|
||||
$this->title = $title;
|
||||
$this->description_en
|
||||
= $description_en === null || $description_en === ''
|
||||
? []
|
||||
: explode("\n", $description_en);
|
||||
$this->description_no
|
||||
= $description_no === null || $description_no === ''
|
||||
? []
|
||||
: explode("\n", $description_no);
|
||||
$this->gitea_link = $gitea_link;
|
||||
$this->issue_board_link = $issue_board_link;
|
||||
$this->wiki_link = $wiki_link;
|
||||
$this->programming_languages
|
||||
= $programming_languages === null || $programming_languages === ''
|
||||
? []
|
||||
: explode(',', $programming_languages);
|
||||
$this->technologies
|
||||
= $technologies === null || $technologies === ''
|
||||
? []
|
||||
: explode(',', $technologies);
|
||||
$this->keywords
|
||||
= $keywords === null || $keywords === '' ? [] : explode(',', $keywords);
|
||||
$this->license = $license;
|
||||
$this->logo_url = $logo_url;
|
||||
$this->is_hidden = $is_hidden;
|
||||
}
|
||||
|
||||
public function getID(): int {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getTitle(): string {
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getDescriptionEn(): array {
|
||||
return $this->description_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getDescriptionNo(): array {
|
||||
return $this->description_no;
|
||||
}
|
||||
|
||||
public function getGiteaLink(): ?string {
|
||||
return $this->gitea_link;
|
||||
}
|
||||
|
||||
public function getIssueBoardLink(): ?string {
|
||||
return $this->issue_board_link;
|
||||
}
|
||||
|
||||
public function getWikiLink(): ?string {
|
||||
return $this->wiki_link;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getProgrammingLanguages(): array {
|
||||
return $this->programming_languages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getTechnologies(): array {
|
||||
return $this->technologies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getKeywords(): array {
|
||||
return $this->keywords;
|
||||
}
|
||||
|
||||
public function getLicense(): ?string {
|
||||
return $this->license;
|
||||
}
|
||||
|
||||
public function getLogoURL(): ?string {
|
||||
return $this->logo_url;
|
||||
}
|
||||
|
||||
public function isHidden(): bool {
|
||||
return $this->is_hidden;
|
||||
}
|
||||
}
|
||||
|
||||
class ProjectMaintainer {
|
||||
private string $uname;
|
||||
private string $name;
|
||||
private string $email;
|
||||
private bool $is_organizer;
|
||||
|
||||
public function __construct(
|
||||
string $uname,
|
||||
string $name,
|
||||
string $email,
|
||||
bool $is_organizer,
|
||||
) {
|
||||
$this->uname = $uname;
|
||||
$this->name = $name;
|
||||
$this->email = $email;
|
||||
$this->is_organizer = $is_organizer;
|
||||
}
|
||||
|
||||
public function getUname(): string {
|
||||
return $this->uname;
|
||||
}
|
||||
public function getName(): string {
|
||||
return $this->name;
|
||||
}
|
||||
public function getEmail(): string {
|
||||
return $this->email;
|
||||
}
|
||||
public function isOrganizer(): bool {
|
||||
return $this->is_organizer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side;
|
||||
|
||||
class ProjectManager {
|
||||
private $pdo;
|
||||
|
||||
public function __construct(\PDO $pdo) {
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
// TODO: groupid
|
||||
|
||||
/**
|
||||
* @return Project[]
|
||||
*/
|
||||
public function getAll(): array {
|
||||
$query = '
|
||||
SELECT
|
||||
id,
|
||||
title,
|
||||
description_en,
|
||||
description_no,
|
||||
gitea_link,
|
||||
issue_board_link,
|
||||
wiki_link,
|
||||
programming_languages,
|
||||
technologies,
|
||||
keywords,
|
||||
license,
|
||||
logo_url,
|
||||
is_hidden
|
||||
FROM project
|
||||
ORDER BY title ASC
|
||||
';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->execute();
|
||||
|
||||
$projects = [];
|
||||
foreach ($statement->fetchAll() as $dbProj) {
|
||||
$project = new Project(
|
||||
$dbProj['id'],
|
||||
$dbProj['title'],
|
||||
$dbProj['description_en'],
|
||||
$dbProj['description_no'],
|
||||
$dbProj['gitea_link'],
|
||||
$dbProj['issue_board_link'],
|
||||
$dbProj['wiki_link'],
|
||||
$dbProj['programming_languages'],
|
||||
$dbProj['technologies'],
|
||||
$dbProj['keywords'],
|
||||
$dbProj['license'],
|
||||
$dbProj['logo_url'],
|
||||
(bool) $dbProj['is_hidden']
|
||||
);
|
||||
$projects[] = $project;
|
||||
}
|
||||
|
||||
return $projects;
|
||||
}
|
||||
|
||||
// TODO: groupid
|
||||
public function getByID(int $id): ?Project {
|
||||
$query = '
|
||||
SELECT
|
||||
id,
|
||||
title,
|
||||
description_en,
|
||||
description_no,
|
||||
gitea_link,
|
||||
issue_board_link,
|
||||
wiki_link,
|
||||
programming_languages,
|
||||
technologies,
|
||||
keywords,
|
||||
license,
|
||||
logo_url,
|
||||
is_hidden
|
||||
FROM project
|
||||
WHERE id = :id
|
||||
';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->bindValue(':id', $id, \PDO::PARAM_INT);
|
||||
$statement->execute();
|
||||
|
||||
$dbProj = $statement->fetch();
|
||||
if (!$dbProj) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Project(
|
||||
$dbProj['id'],
|
||||
$dbProj['title'],
|
||||
$dbProj['description_en'],
|
||||
$dbProj['description_no'],
|
||||
$dbProj['gitea_link'],
|
||||
$dbProj['issue_board_link'],
|
||||
$dbProj['wiki_link'],
|
||||
$dbProj['programming_languages'],
|
||||
$dbProj['technologies'],
|
||||
$dbProj['keywords'],
|
||||
$dbProj['license'],
|
||||
$dbProj['logo_url'],
|
||||
(bool) $dbProj['is_hidden']
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// TODO: groupid
|
||||
/**
|
||||
* @return Project[]
|
||||
*/
|
||||
public function getByMaintainer(string $uname): array {
|
||||
$query = '
|
||||
SELECT
|
||||
project.id,
|
||||
project.title
|
||||
project.description_en,
|
||||
project.description_no,
|
||||
project.gitea_link,
|
||||
project.issue_board_link,
|
||||
project.wiki_link,
|
||||
project.programming_languages,
|
||||
project.technologies,
|
||||
project.keywords,
|
||||
project.license,
|
||||
project.logo_url,
|
||||
project.is_hidden
|
||||
FROM project_maintainer
|
||||
JOIN project ON project.id = project_maintainer.project_id
|
||||
WHERE project_maintainer.uname = :uname
|
||||
';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->bindValue(':uname', $uname, \PDO::PARAM_STR);
|
||||
$statement->execute();
|
||||
|
||||
$result = array_map(
|
||||
function ($dbProj) {
|
||||
return new Project(
|
||||
$dbProj['id'],
|
||||
$dbProj['title'],
|
||||
$dbProj['description_en'],
|
||||
$dbProj['description_no'],
|
||||
$dbProj['gitea_link'],
|
||||
$dbProj['issue_board_link'],
|
||||
$dbProj['wiki_link'],
|
||||
$dbProj['programming_languages'],
|
||||
$dbProj['technologies'],
|
||||
$dbProj['keywords'],
|
||||
$dbProj['license'],
|
||||
$dbProj['logo_url'],
|
||||
(bool) $dbProj['is_hidden']
|
||||
);
|
||||
},
|
||||
$statement->fetchAll()
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ProjectMaintainer[]
|
||||
*/
|
||||
public function getProjectMaintainers(int $project_id): array {
|
||||
$query = '
|
||||
SELECT
|
||||
project_maintainer.uname,
|
||||
project_maintainer.name,
|
||||
project_maintainer.email,
|
||||
project_maintainer.is_organizer
|
||||
FROM project_maintainer
|
||||
WHERE project_maintainer.project_id = :id
|
||||
';
|
||||
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->bindValue(':id', $project_id, \PDO::PARAM_STR);
|
||||
$statement->execute();
|
||||
|
||||
$result = array_map(
|
||||
function ($dbUsr) {
|
||||
return new ProjectMaintainer(
|
||||
$dbUsr['uname'],
|
||||
$dbUsr['name'],
|
||||
$dbUsr['email'],
|
||||
(bool)$dbUsr['is_organizer']
|
||||
);
|
||||
},
|
||||
$statement->fetchAll()
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ProjectMaintainer[]
|
||||
*/
|
||||
public function getProjectOrganizers(int $project_id): array {
|
||||
$query = '
|
||||
SELECT
|
||||
project_maintainer.uname,
|
||||
project_maintainer.name,
|
||||
project_maintainer.email,
|
||||
project_maintainer.is_organizer
|
||||
FROM project_maintainer
|
||||
WHERE
|
||||
project_maintainer.project_id = :id
|
||||
AND project_maintainer.is_organizer = True
|
||||
';
|
||||
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->bindValue(':id', $project_id, \PDO::PARAM_STR);
|
||||
$statement->execute();
|
||||
|
||||
$result = array_map(
|
||||
function ($dbUsr) {
|
||||
return new ProjectMaintainer(
|
||||
$dbUsr['uname'],
|
||||
$dbUsr['name'],
|
||||
$dbUsr['email'],
|
||||
(bool)$dbUsr['is_organizer']
|
||||
);
|
||||
},
|
||||
$statement->fetchAll()
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side;
|
||||
|
||||
class SimpleEvent extends Event {
|
||||
private int $id;
|
||||
private string $name;
|
||||
private array $descr;
|
||||
private \DateTimeImmutable $start;
|
||||
private \DateTimeImmutable $end;
|
||||
private string $org;
|
||||
private string $loc;
|
||||
|
||||
public function __construct(
|
||||
int $id,
|
||||
string $name,
|
||||
\DateTimeImmutable $start,
|
||||
\DateTimeImmutable $end,
|
||||
string $org,
|
||||
string $loc,
|
||||
string $descr,
|
||||
bool $_isDBEvent = false,
|
||||
) {
|
||||
$this->id = $id;
|
||||
$this->name = $name;
|
||||
$this->start = $start;
|
||||
$this->end = $end;
|
||||
$this->org = $org;
|
||||
$this->loc = $loc;
|
||||
$this->descr = explode("\n", $descr);
|
||||
}
|
||||
|
||||
public function getID(): int {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getStart(): \DateTimeImmutable {
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
public function getStop(): \DateTimeImmutable {
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
public function getOrganiser(): string {
|
||||
return $this->org;
|
||||
}
|
||||
|
||||
public function getLocation(): string {
|
||||
return $this->loc;
|
||||
}
|
||||
|
||||
public function getName(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getURL(): string {
|
||||
return '/hendelser/info.php?id='.$this->id;
|
||||
}
|
||||
|
||||
public function getImageURL(): string {
|
||||
return '/';
|
||||
}
|
||||
|
||||
public function getDescription(): array {
|
||||
return $this->descr;
|
||||
}
|
||||
|
||||
public function getColor(): string {
|
||||
return '#3b7';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side\social;
|
||||
|
||||
use pvv\side\Activity;
|
||||
|
||||
class AnimekveldActivity implements Activity {
|
||||
public function nextDate(\DateTimeImmutable $date): \DateTimeImmutable {
|
||||
if (
|
||||
(int) $date->format('H') > 20
|
||||
|| ((int) $date->format('H') === 19 && (int) $date->format('i') > 30)
|
||||
) {
|
||||
return $this->nextDate(
|
||||
$date->add(new \DateInterval('P1D'))->setTime(19, 30, 0),
|
||||
);
|
||||
}
|
||||
$date = $date->setTime(19, 30, 0);
|
||||
if ((int) $date->format('N') !== 5) {
|
||||
return $this->nextDate($date->add(new \DateInterval('P1D')));
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
public function prevDate(\DateTimeImmutable $date): \DateTimeImmutable {
|
||||
if (
|
||||
(int) $date->format('H') < 19
|
||||
|| ((int) $date->format('H') === 20 && (int) $date->format('i') < 30)
|
||||
) {
|
||||
return $this->prevDate(
|
||||
$date->sub(new \DateInterval('P1D'))->setTime(19, 30, 0),
|
||||
);
|
||||
}
|
||||
$date = $date->setTime(19, 30, 0);
|
||||
if ((int) $date->format('N') !== 5) {
|
||||
return $this->prevDate($date->sub(new \DateInterval('P1D')));
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
public function getNextEventFrom(\DateTimeImmutable $date): AnimekveldEvent {
|
||||
return new AnimekveldEvent($this->nextDate($date));
|
||||
}
|
||||
|
||||
public function getPreviousEventFrom(
|
||||
\DateTimeImmutable $date,
|
||||
): AnimekveldEvent {
|
||||
return new AnimekveldEvent($this->prevDate($date));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side\social;
|
||||
|
||||
use pvv\side\Event;
|
||||
|
||||
class AnimekveldEvent extends Event {
|
||||
public function getStop(): \DateTimeImmutable {
|
||||
return $this->getStart()->add(new \DateInterval('PT4H1800S'));
|
||||
}
|
||||
|
||||
public function getName(): string {
|
||||
return 'Animekveld';
|
||||
}
|
||||
|
||||
public function getLocation(): string {
|
||||
/* : Location */
|
||||
return 'Koserommet';
|
||||
}
|
||||
|
||||
public function getOrganiser(): string {
|
||||
return 'Christoffer Viken';
|
||||
}
|
||||
|
||||
public function getURL(): string {
|
||||
return '/anime/';
|
||||
}
|
||||
|
||||
public function getImageURL(): string {
|
||||
return '/sosiale/animekveld.jpg';
|
||||
}
|
||||
|
||||
public function getDescription(): array {
|
||||
return [
|
||||
'Er du glad i japanske tegneserier eller bare nysgjerrig på hva anime er?',
|
||||
'Bli med oss hver fredag, der vi finner frem de nyeste episodene for sesongen!',
|
||||
'',
|
||||
'Alle kan være med på å anbefale eller veto serier.',
|
||||
'',
|
||||
];
|
||||
}
|
||||
|
||||
public function getColor(): string {
|
||||
return '#35a';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side\social;
|
||||
|
||||
use pvv\side\Activity;
|
||||
|
||||
class BrettspillActivity implements Activity {
|
||||
public function nextDate(\DateTimeImmutable $date): \DateTimeImmutable {
|
||||
if (
|
||||
(int) $date->format('H') > 17
|
||||
|| ((int) $date->format('H') === 16 && (int) $date->format('i') > 15)
|
||||
) {
|
||||
return $this->nextDate(
|
||||
$date->add(new \DateInterval('P1D'))->setTime(16, 15, 0),
|
||||
);
|
||||
}
|
||||
$date = $date->setTime(16, 15, 0);
|
||||
if ((int) $date->format('N') !== 7) {
|
||||
return $this->nextDate($date->add(new \DateInterval('P1D')));
|
||||
}
|
||||
if (((int) $date->format('W') % 2) - 1) {
|
||||
return $this->nextDate($date->add(new \DateInterval('P7D')));
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
public function prevDate(\DateTimeImmutable $date): \DateTimeImmutable {
|
||||
if (
|
||||
(int) $date->format('H') < 16
|
||||
|| ((int) $date->format('H') === 17 && (int) $date->format('i') < 15)
|
||||
) {
|
||||
return $this->prevDate(
|
||||
$date->sub(new \DateInterval('P1D'))->setTime(16, 15, 0),
|
||||
);
|
||||
}
|
||||
$date = $date->setTime(16, 15, 0);
|
||||
if ((int) $date->format('N') !== 7) {
|
||||
return $this->prevDate($date->sub(new \DateInterval('P1D')));
|
||||
}
|
||||
if (((int) $date->format('W') % 2) - 1) {
|
||||
return $this->prevDate($date->sub(new \DateInterval('P7D')));
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
public function getNextEventFrom(\DateTimeImmutable $date): BrettspillEvent {
|
||||
return new BrettspillEvent($this->nextDate($date));
|
||||
}
|
||||
|
||||
public function getPreviousEventFrom(
|
||||
\DateTimeImmutable $date,
|
||||
): BrettspillEvent {
|
||||
return new BrettspillEvent($this->prevDate($date));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side\social;
|
||||
|
||||
use pvv\side\Event;
|
||||
|
||||
class BrettspillEvent extends Event {
|
||||
public function getStop(): \DateTimeImmutable {
|
||||
return $this->getStart()->add(new \DateInterval('PT4H1800S'));
|
||||
}
|
||||
|
||||
public function getName(): string {
|
||||
return 'Brettspillkveld';
|
||||
}
|
||||
|
||||
public function getLocation(): string {
|
||||
return 'Programvareverkstedet';
|
||||
}
|
||||
|
||||
public function getOrganiser(): string {
|
||||
return 'Programvareverkstedet';
|
||||
}
|
||||
|
||||
public function getURL(): string {
|
||||
return '/brettspill/';
|
||||
}
|
||||
|
||||
public function getImageURL(): string {
|
||||
return '/sosiale/brettspill.jpg';
|
||||
}
|
||||
|
||||
public function getDescription(): array {
|
||||
return [
|
||||
'Er du en hardcore brettspillentusiast eller en nybegynner som har så vidt spilt ludo? '
|
||||
.'Da er vår brettspillkveld noe for deg! '
|
||||
.'Vi tar ut et par spill fra vårt samling of spiller så mye vi orker. Kom innom!',
|
||||
'',
|
||||
'## Vår samling',
|
||||
'',
|
||||
'* Dominion\*',
|
||||
'* Three cheers for master',
|
||||
'* Avalon',
|
||||
'* Hanabi',
|
||||
'* Cards aginst humanity\*',
|
||||
'* Citadels',
|
||||
'* Munchkin\*\*',
|
||||
'* Exploding kittens\*\*',
|
||||
'* Aye dark overlord',
|
||||
'* Settlers of catan\*',
|
||||
'* Risk\*\*',
|
||||
'* og mange flere...',
|
||||
'',
|
||||
'\* Vi har flere ekspansjoner til spillet',
|
||||
'',
|
||||
'\*\* Vi har flere varianter av spillet',
|
||||
];
|
||||
}
|
||||
|
||||
public function getColor(): string {
|
||||
return '#000';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side\social;
|
||||
|
||||
use pvv\side\Activity;
|
||||
|
||||
class DriftkveldActivity implements Activity {
|
||||
public function nextDate(\DateTimeImmutable $date): \DateTimeImmutable {
|
||||
if (
|
||||
(int) $date->format('H') > 18
|
||||
|| ((int) $date->format('H') === 17 && (int) $date->format('i') > 30)
|
||||
) {
|
||||
return $this->nextDate(
|
||||
$date->add(new \DateInterval('P1D'))->setTime(18, 15, 0),
|
||||
);
|
||||
}
|
||||
$date = $date->setTime(18, 15, 0);
|
||||
if ((int) $date->format('N') !== 6) {
|
||||
return $this->nextDate($date->add(new \DateInterval('P1D')));
|
||||
}
|
||||
if (((int) $date->format('W') % 2) - 1) {
|
||||
return $this->nextDate($date->add(new \DateInterval('P7D')));
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
public function prevDate(\DateTimeImmutable $date): \DateTimeImmutable {
|
||||
if (
|
||||
(int) $date->format('H') < 17
|
||||
|| ((int) $date->format('H') === 18 && (int) $date->format('i') < 30)
|
||||
) {
|
||||
return $this->prevDate(
|
||||
$date->sub(new \DateInterval('P1D'))->setTime(18, 15, 0),
|
||||
);
|
||||
}
|
||||
$date = $date->setTime(18, 15, 0);
|
||||
if ((int) $date->format('N') !== 6) {
|
||||
return $this->prevDate($date->sub(new \DateInterval('P1D')));
|
||||
}
|
||||
if (((int) $date->format('W') % 2) - 1) {
|
||||
return $this->prevDate($date->sub(new \DateInterval('P7D')));
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
public function getNextEventFrom(\DateTimeImmutable $date): DriftkveldEvent {
|
||||
return new DriftkveldEvent($this->nextDate($date));
|
||||
}
|
||||
|
||||
public function getPreviousEventFrom(
|
||||
\DateTimeImmutable $date,
|
||||
): DriftkveldEvent {
|
||||
return new DriftkveldEvent($this->prevDate($date));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side\social;
|
||||
|
||||
use pvv\side\Event;
|
||||
|
||||
class DriftkveldEvent extends Event {
|
||||
public function getStop(): \DateTimeImmutable {
|
||||
return $this->getStart()->add(new \DateInterval('PT4H1800S'));
|
||||
}
|
||||
|
||||
public function getName(): string {
|
||||
return 'Driftkveld';
|
||||
}
|
||||
|
||||
public function getLocation(): string {
|
||||
return 'Terminalrommet / Discord / IRC';
|
||||
}
|
||||
|
||||
public function getOrganiser(): string {
|
||||
return 'Torstein Nordgård-Hansen';
|
||||
}
|
||||
|
||||
public function getURL(): string {
|
||||
return '/driftkveld/';
|
||||
}
|
||||
|
||||
public function getImageURL(): string {
|
||||
return '/sosiale/drift.jpg';
|
||||
}
|
||||
|
||||
public function getDescription(): array {
|
||||
return [
|
||||
'Vil du drifte?',
|
||||
'Vil du være kul kis TM?',
|
||||
'Kom på driftkveld!',
|
||||
'',
|
||||
'Vi møtes annenhver uke for å ta unna driftarbeid og drikke kaffe.',
|
||||
'Alle PVVere er velkommene, enten de er erfarne driftere eller helt utenforstående!',
|
||||
];
|
||||
}
|
||||
|
||||
public function getColor(): string {
|
||||
return '#35a';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side\social;
|
||||
|
||||
use pvv\side\Activity;
|
||||
|
||||
class HackekveldActivity implements Activity {
|
||||
public function nextDate(\DateTimeImmutable $date): \DateTimeImmutable {
|
||||
if ((int) $date->format('H') > 18 || (int) $date->format('H') === 17 && (int) $date->format('i') > 30) {
|
||||
return $this->nextDate($date->add(new \DateInterval('P1D'))->setTime(18, 15, 0));
|
||||
}
|
||||
$date = $date->setTime(16, 15, 0);
|
||||
if ((int) $date->format('N') !== 6) {
|
||||
return $this->nextDate($date->add(new \DateInterval('P1D')));
|
||||
}
|
||||
if ((int) $date->format('W') % 2) {
|
||||
return $this->nextDate($date->add(new \DateInterval('P7D')));
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
public function prevDate(\DateTimeImmutable $date): \DateTimeImmutable {
|
||||
if ((int) $date->format('H') < 17 || (int) $date->format('H') === 18 && (int) $date->format('i') < 30) {
|
||||
return $this->prevDate($date->sub(new \DateInterval('P1D'))->setTime(18, 15, 0));
|
||||
}
|
||||
$date = $date->setTime(18, 15, 0);
|
||||
if ((int) $date->format('N') !== 6) {
|
||||
return $this->prevDate($date->sub(new \DateInterval('P1D')));
|
||||
}
|
||||
if ((int) $date->format('W') % 2) {
|
||||
return $this->prevDate($date->sub(new \DateInterval('P7D')));
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
public function getNextEventFrom(\DateTimeImmutable $date): HackekveldEvent {
|
||||
return new HackekveldEvent($this->nextDate($date));
|
||||
}
|
||||
|
||||
public function getPreviousEventFrom(\DateTimeImmutable $date): HackekveldEvent {
|
||||
return new HackekveldEvent($this->prevDate($date));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side\social;
|
||||
|
||||
use pvv\side\Event;
|
||||
|
||||
class HackekveldEvent extends Event {
|
||||
public function getStop(): \DateTimeImmutable {
|
||||
return $this->getStart()->add(new \DateInterval('PT4H1800S'));
|
||||
}
|
||||
|
||||
public function getName(): string {
|
||||
return 'Hackekveld';
|
||||
}
|
||||
|
||||
public function getLocation(): string {
|
||||
return 'Terminalrommet / Discord / IRC';
|
||||
}
|
||||
|
||||
public function getOrganiser(): string {
|
||||
return 'PVV';
|
||||
}
|
||||
|
||||
public function getURL(): string {
|
||||
return '#';
|
||||
}
|
||||
|
||||
public function getImageURL(): string {
|
||||
return '/pvv-logo.png';
|
||||
}
|
||||
|
||||
public function getDescription(): array {
|
||||
return [
|
||||
'Mange PVV-medlemmer liker å programmere.',
|
||||
'Hvis du også liker å programmere, så bli med! Her kan du jobbe med dine egne prosjekter eller starte noe med andre nerder her på huset. Vi møtes for en hyggelig prat, mye god programmering og delsponset pizza.',
|
||||
];
|
||||
}
|
||||
|
||||
public function getColor(): string {
|
||||
return '#35a';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side\social;
|
||||
|
||||
use pvv\side\Activity;
|
||||
use pvv\side\Event;
|
||||
|
||||
class NerdepitsaActivity implements Activity {
|
||||
public function nextDate(\DateTimeImmutable $date): \DateTimeImmutable {
|
||||
if ((int) $date->format('H') > 19) {
|
||||
return $this->nextDate($date->add(new \DateInterval('P1D'))->setTime(19, 0, 0));
|
||||
}
|
||||
$date = $date->setTime(19, 0, 0);
|
||||
if ((int) $date->format('N') !== 5) {
|
||||
return $this->nextDate($date->add(new \DateInterval('P1D')));
|
||||
}
|
||||
if ((int) $date->format('W') % 2) {
|
||||
return $this->nextDate($date->add(new \DateInterval('P7D')));
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
public function prevDate(\DateTimeImmutable $date): \DateTimeImmutable {
|
||||
if ((int) $date->format('H') < 19) {
|
||||
return $this->prevDate($date->sub(new \DateInterval('P1D'))->setTime(19, 0, 0));
|
||||
}
|
||||
$date = $date->setTime(19, 0, 0);
|
||||
if ((int) $date->format('N') !== 5) {
|
||||
return $this->prevDate($date->sub(new \DateInterval('P1D')));
|
||||
}
|
||||
if ((int) $date->format('W') % 2) {
|
||||
return $this->prevDate($date->sub(new \DateInterval('P7D')));
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
public function getNextEventFrom(\DateTimeImmutable $date): ?Event {
|
||||
return new NerdepitsaEvent($this->nextDate($date));
|
||||
}
|
||||
|
||||
public function getPreviousEventFrom(\DateTimeImmutable $date): ?Event {
|
||||
return new NerdepitsaEvent($this->prevDate($date));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side\social;
|
||||
|
||||
use pvv\side\Event;
|
||||
|
||||
class NerdepitsaEvent extends Event {
|
||||
public function getStop(): \DateTimeImmutable {
|
||||
return $this->getStart()->add(new \DateInterval('PT2H1800S'));
|
||||
}
|
||||
|
||||
public function getName(): string {
|
||||
return 'Nerdepitsa';
|
||||
}
|
||||
|
||||
public function getLocation(): string {
|
||||
return 'Peppes Kjøpmansgata';
|
||||
}
|
||||
|
||||
public function getOrganiser(): string {
|
||||
return 'Anders Christensen';
|
||||
}
|
||||
|
||||
public function getURL(): string {
|
||||
return '/nerdepitsa/';
|
||||
}
|
||||
|
||||
public function getImageURL(): string {
|
||||
return '/sosiale/nerdepitsa.jpg';
|
||||
}
|
||||
|
||||
public function getDescription(): array {
|
||||
return [
|
||||
'Hei, har du lyst til å bli med på pizzaspising annenhver fredag? Vi møtes på Peppes i Kjøpmannsgata fredag klokken 19.00 hver partallsuke!',
|
||||
'',
|
||||
'Vi er en trivelig gjeng hvis der fellestrekk er en viss interesse for data, samt har eller har hatt en tilknytning til studentmiljøet ved NTNU. For å treffe andre som også faller inn under disse kriteriene treffes vi over pizza på Peppes annenhver fredag. (Definisjon: En fredag er annenhver dersom den ligger i en partallsuke). Vi har reservasjon under navnet Christensen med storkunderabatt.',
|
||||
'',
|
||||
'Det er ikke noe krav at du er nerd... noen av oss virker faktisk nesten normale! Det er heller ikke noe krav at du kjenner noen fra før. Det er ikke engang et krav at du må like pizza! (selv om det hjelper) Dersom du har lyst til å treffe personer fra datamiljøet ved NTNU så bare still opp! Vi biter ikke, vel, bortsett fra pizzaen da.',
|
||||
'',
|
||||
'Vi bestiller så mye pizza som vi i fellesskap klarer å stappe i oss, og splitter dermed pizza-regningen broderlig, mens hver enkelt betaler for sin egen drikke, dessert mm. Vell møtt!',
|
||||
];
|
||||
}
|
||||
|
||||
public function getColor(): string {
|
||||
return '#c35';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side\social;
|
||||
|
||||
ini_set('date.timezone', 'Europe/Oslo');
|
||||
|
||||
require implode(\DIRECTORY_SEPARATOR, [\dirname(__DIR__, 3), '', '_autoload.php']);
|
||||
|
||||
$c = new AnimekveldActivity();
|
||||
exit($c->nextDate(new \DateTimeImmutable())->format(\DATE_RFC2822));
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pvv\side\social;
|
||||
|
||||
ini_set('date.timezone', 'Europe/Oslo');
|
||||
|
||||
require implode(\DIRECTORY_SEPARATOR, [\dirname(__DIR__, 3), '', '_autoload.php']);
|
||||
|
||||
$c = new NerdepitsaActivity();
|
||||
exit($c->prevDate(new \DateTimeImmutable())->format(\DATE_RFC2822));
|
||||
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 52 KiB |
@@ -0,0 +1,141 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 800 800"
|
||||
style="enable-background:new 0 0 800 800;"
|
||||
xml:space="preserve"
|
||||
id="svg45"
|
||||
sodipodi:docname="Pvv logoBW.svg"
|
||||
inkscape:version="0.92.2 5c3e80d, 2017-08-06"><metadata
|
||||
id="metadata51"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs49" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1027"
|
||||
id="namedview47"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.834386"
|
||||
inkscape:cx="590.94635"
|
||||
inkscape:cy="338.49599"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_5" /><style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
.st0{fill:#ffffff;}
|
||||
.st1{fill:none;stroke:#ffffff;stroke-width:2;stroke-miterlimit:10;}
|
||||
.st2{fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:10;}
|
||||
.st3{fill:none;}
|
||||
.st4{stroke:#000000;stroke-miterlimit:10;}
|
||||
.st5{font-family:'OCRAStd';}
|
||||
.st6{font-size:126px;}
|
||||
</style><g
|
||||
id="Layer_2"><rect
|
||||
y="0"
|
||||
class="st0"
|
||||
width="800"
|
||||
height="800"
|
||||
id="rect4" /></g><g
|
||||
id="Layer_4"><path
|
||||
class="st1"
|
||||
d="M294.6,720.3"
|
||||
id="path7" /><line
|
||||
class="st1"
|
||||
x1="478.4"
|
||||
y1="720.3"
|
||||
x2="313.2"
|
||||
y2="720.3"
|
||||
id="line9" /><path
|
||||
class="st1"
|
||||
d="M478.4,720.3"
|
||||
id="path11" /><polyline
|
||||
class="st2"
|
||||
points="717.1,223.3 717.1,720.3 497.3,720.3 "
|
||||
id="polyline13" /><path
|
||||
class="st2"
|
||||
d="M498.3,720.3c0-5.6-4.5-10.1-10.1-10.1c-5.6,0-10.1,4.5-10.1,10.1H314.3c0-5.6-4.5-10.1-10.1-10.1 c-5.6,0-10.1,4.5-10.1,10.1h0.6H76.5V79.7h640.5v120.8v-0.8h-17.3v24.8h17.3"
|
||||
id="path15" /></g><g
|
||||
id="Layer_3"><circle
|
||||
class="st2"
|
||||
cx="396.8"
|
||||
cy="400"
|
||||
r="320.3"
|
||||
id="circle18" /></g><g
|
||||
id="Layer_1"><polyline
|
||||
class="st2"
|
||||
points="514.5,173.5 170.2,173.5 170.3,626.6 623.3,626.5 623.3,215.7 584.4,173.4 557,173.4 548,180.6 526.5,180.7 "
|
||||
id="polyline21" /><path
|
||||
class="st1"
|
||||
d="M396.8,173.5"
|
||||
id="path23" /><path
|
||||
class="st1"
|
||||
d="M396.8,173.3"
|
||||
id="path25" /><path
|
||||
class="st2"
|
||||
d="M526.5,331.8c0,7.6-5.4,13.7-12,13.7H227.7c-6.6,0-12-6.1-12-13.7V187.2c0-7.6,5.4-13.7,12-13.7h286.8 c6.6,0,12,6.1,12,13.7V331.8z"
|
||||
id="path27" /><path
|
||||
class="st2"
|
||||
d="M526.7,333.6c0,6.6-5.4,12-12,12H296.8c-6.6,0-12-5.4-12-12V185.5c0-6.6,5.4-12,12-12h217.9 c6.6,0,12,5.4,12,12V333.6z"
|
||||
id="path29" /><path
|
||||
class="st2"
|
||||
d="M577.9,613.7c0,6.6-5.4,12-12,12H227.7c-6.6,0-12-5.4-12-12V381.1c0-6.6,5.4-12,12-12h338.2 c6.6,0,12,5.4,12,12V613.7z"
|
||||
id="path31" /><rect
|
||||
x="179.9"
|
||||
y="590.2"
|
||||
class="st2"
|
||||
width="25.7"
|
||||
height="23"
|
||||
id="rect33" /><rect
|
||||
x="587.6"
|
||||
y="590.2"
|
||||
class="st2"
|
||||
width="25.7"
|
||||
height="23"
|
||||
id="rect35" /><rect
|
||||
x="433.6"
|
||||
y="193.5"
|
||||
class="st2"
|
||||
width="64.9"
|
||||
height="137.8"
|
||||
id="rect37" /></g><g
|
||||
id="Layer_5"><rect
|
||||
x="258"
|
||||
y="442.5"
|
||||
class="st3"
|
||||
width="277.5"
|
||||
height="109.7"
|
||||
id="rect40" /><g
|
||||
aria-label="PVV"
|
||||
transform="matrix(1 0 0 1 260.7021 547.998)"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:126px;font-family:OCRA;-inkscape-font-specification:OCRA;stroke:#000000;stroke-miterlimit:10"
|
||||
id="text42"><path
|
||||
d="m 14.238,-6.426 c 0,3.528 2.772,6.426 6.3,6.426 3.528,0 6.426,-2.898 6.426,-6.426 v -30.996 h 30.87 c 10.458,0 19.152,-8.694 19.152,-19.152 v -22.68 c 0,-10.332 -8.694,-19.026 -19.152,-19.026 H 14.238 Z m 12.726,-43.722 v -35.406 h 30.87 c 3.276,0 6.426,2.898 6.426,6.3 v 22.68 c 0,3.528 -3.024,6.426 -6.426,6.426 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:126px;font-family:OCRA;-inkscape-font-specification:OCRA;stroke:#000000;stroke-miterlimit:10"
|
||||
id="path55" /><path
|
||||
d="m 105.29269,-69.174 25.326,65.142 c 1.008,2.394 3.276,4.032 6.048,4.032 2.646,0 4.914,-1.638 5.922,-4.032 l 25.452,-65.268 v -22.68 c 0,-3.402 -2.898,-6.3 -6.426,-6.3 -3.528,0 -6.3,2.898 -6.3,6.3 v 20.286 l -18.648,47.628 -18.648,-47.628 V -91.98 c 0,-3.402 -2.898,-6.3 -6.426,-6.3 -3.528,0 -6.3,2.898 -6.3,6.3 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:126px;font-family:OCRA;-inkscape-font-specification:OCRA;stroke:#000000;stroke-miterlimit:10"
|
||||
id="path57" /><path
|
||||
d="m 196.34737,-69.174 25.326,65.142 c 1.008,2.394 3.276,4.032 6.048,4.032 2.646,0 4.914,-1.638 5.922,-4.032 l 25.452,-65.268 v -22.68 c 0,-3.402 -2.898,-6.3 -6.426,-6.3 -3.528,0 -6.3,2.898 -6.3,6.3 v 20.286 l -18.648,47.628 -18.648,-47.628 V -91.98 c 0,-3.402 -2.898,-6.3 -6.426,-6.3 -3.528,0 -6.3,2.898 -6.3,6.3 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:126px;font-family:OCRA;-inkscape-font-specification:OCRA;stroke:#000000;stroke-miterlimit:10"
|
||||
id="path59" /></g></g></svg>
|
||||
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
require __DIR__ . '/../../../src/_autoload.php';
|
||||
require __DIR__ . '/../../../config.php';
|
||||
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$userManager = new pvv\admin\UserManager($pdo);
|
||||
|
||||
require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as->requireAuth();
|
||||
$attrs = $as->getAttributes();
|
||||
$uname = $attrs['uid'][0];
|
||||
|
||||
if (!$userManager->hasGroup($uname, 'aktiviteter')) {
|
||||
echo 'Her har du ikke lov\'t\'å\'værra!!!';
|
||||
exit;
|
||||
}
|
||||
|
||||
$eventID = $_GET['id'];
|
||||
|
||||
$query = 'DELETE FROM events WHERE id=\'' . $eventID . '\'';
|
||||
$statement = $pdo->prepare($query);
|
||||
$statement->execute();
|
||||
|
||||
header('Location: ' . $_SERVER['HTTP_REFERER']);
|
||||
?>
|
||||
|
||||
<a href=".?page=1">Om du ikke ble omdirigert tilbake klikk her</a>
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
date_default_timezone_set('Europe/Oslo');
|
||||
setlocale(\LC_ALL, 'nb_NO');
|
||||
require __DIR__ . '/../../../inc/navbar.php';
|
||||
require __DIR__ . '/../../../src/_autoload.php';
|
||||
require __DIR__ . '/../../../config.php';
|
||||
|
||||
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$userManager = new pvv\admin\UserManager($pdo);
|
||||
|
||||
require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as->requireAuth();
|
||||
$attrs = $as->getAttributes();
|
||||
$uname = $attrs['uid'][0];
|
||||
$name = $attrs['cn'][0];
|
||||
|
||||
if (!$userManager->hasGroup($uname, 'aktiviteter')) {
|
||||
echo 'Her har du ikke lov\'t\'å\'værra!!!';
|
||||
exit;
|
||||
}
|
||||
|
||||
$customActivity = new pvv\side\DBActivity($pdo);
|
||||
|
||||
$new = 0;
|
||||
if (isset($_GET['new'])) {
|
||||
$new = $_GET['new'];
|
||||
}
|
||||
|
||||
$eventID = 0;
|
||||
if (isset($_GET['id'])) {
|
||||
$eventID = $_GET['id'];
|
||||
} elseif ($new == 0) {
|
||||
echo "\nID not set";
|
||||
exit;
|
||||
}
|
||||
|
||||
$today = new DateTimeImmutable();
|
||||
$today = $today->setTime(18, 15);
|
||||
$defaultStart = $today->format('Y-m-d H:15:00');
|
||||
$inTwoHours = $today->add(new DateInterval('PT1H45M'));
|
||||
$defaultEnd = $inTwoHours->format('Y-m-d H:00:00');
|
||||
|
||||
|
||||
if ($new == 0) {
|
||||
$event = $customActivity->getEventByID($eventID);
|
||||
} else {
|
||||
$event = new pvv\side\SimpleEvent(
|
||||
0,
|
||||
'',
|
||||
$today,
|
||||
$inTwoHours,
|
||||
'',
|
||||
'',
|
||||
''
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="no" locale="no">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="../../css/normalize.css">
|
||||
<link rel="stylesheet" href="../../css/style.css">
|
||||
<link rel="stylesheet" href="../../css/nav.css">
|
||||
<link rel="stylesheet" href="../../css/events.css">
|
||||
<link rel="stylesheet" href="../../css/admin.css">
|
||||
<meta name="theme-color" content="#024" />
|
||||
<title>Adminverkstedet</title>
|
||||
|
||||
<header>Admin­verk­stedet</header>
|
||||
|
||||
|
||||
<body>
|
||||
<nav>
|
||||
<?php echo navbar(3, 'admin'); ?>
|
||||
<?php echo loginbar(null, $pdo); ?>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
<h2>Aktivietsadministrasjon</h2>
|
||||
<hr class="ruler">
|
||||
|
||||
<h2><?php echo $new == 1 ? 'Ny hendelse' : 'Rediger hendelse'; ?></h2>
|
||||
|
||||
<form action="update.php", method="post" class="gridsplit fullwidth_inputs">
|
||||
<div class="gridl">
|
||||
<p class="subtitle">Tittel</p>
|
||||
<input type="text" name="title" value="<?php echo $event->getName(); ?>" class="boxinput" required placeholder="En kul hendelse"><br>
|
||||
|
||||
<div class="gridsplit5050">
|
||||
<div class="gridl">
|
||||
<p class="subtitle">Arrangør</p>
|
||||
<input type="text" name="organiser" value="<?php echo $event->getOrganiser(); ?>" class="boxinput" required placeholder="<?php echo $name; ?>"><br>
|
||||
</div>
|
||||
<div class="gridr noborder">
|
||||
<p class="subtitle">Sted</p>
|
||||
<input type="text" name="location" value="<?php echo $event->getLocation(); ?>" class="boxinput" required placeholder="Terminalrommet"><br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="subtitle">Beskrivelse (<i>markdown</i>)</p>
|
||||
<textarea name="desc" rows="8" class="boxinput" placeholder="Beskrivelse" required><?php echo implode("\n", $event->getDescription()); ?></textarea>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="gridr" style="line-height: 1.3em;">
|
||||
<h4>Starttid</h4><br>
|
||||
<i>Måned:</i><br>
|
||||
<input name="start_mon" type="month" class="boxinput" required value="<?php echo $event->getStart()->format('Y-m'); ?>"><br>
|
||||
<i>Dag:</i><br>
|
||||
<input name="start_day" type="number" min="1" max="31" required class="boxinput" value="<?php echo $event->getStart()->format('d'); ?>"><br>
|
||||
<i>Klokkeslett:</i><br>
|
||||
<input name="start_time" type="time" class="boxinput" required value="<?php echo $event->getStart()->format('H:i:s'); ?>"><br>
|
||||
<br>
|
||||
<h4>Varighet</h4><br>
|
||||
<?php $diff = $event->getStart()->diff($event->getStop()); ?>
|
||||
<i>Timer:</i><br>
|
||||
<input name="lasts_hours" type="number" min="0" class="boxinput" required value="<?php echo $diff->h; ?>"><br>
|
||||
<i>Minutter:</i><br>
|
||||
<input name="lasts_minutes" type="number" min="0" max="59" class="boxinput" required value="<?php echo $diff->i; ?>"><br>
|
||||
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="id" value="<?php echo $event->getID(); ?>" />
|
||||
|
||||
<div class="allgrids" style="margin-top: 2em;">
|
||||
<hr class="ruler">
|
||||
<input type="submit" class="btn" value="Lagre"></a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
</main>
|
||||
</body>
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
date_default_timezone_set('Europe/Oslo');
|
||||
setlocale(\LC_ALL, 'nb_NO');
|
||||
require __DIR__ . '/../../../inc/navbar.php';
|
||||
require __DIR__ . '/../../../src/_autoload.php';
|
||||
require __DIR__ . '/../../../config.php';
|
||||
|
||||
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$userManager = new pvv\admin\UserManager($pdo);
|
||||
|
||||
require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as->requireAuth();
|
||||
$attrs = $as->getAttributes();
|
||||
$uname = $attrs['uid'][0];
|
||||
|
||||
if (!$userManager->hasGroup($uname, 'aktiviteter')) {
|
||||
echo 'Her har du ikke lov\'t\'å\'værra!!!';
|
||||
exit;
|
||||
}
|
||||
|
||||
$customActivity = new pvv\side\DBActivity($pdo);
|
||||
$events = $customActivity->getAllEvents();
|
||||
|
||||
$page = 1;
|
||||
if (isset($_GET['page'])) {
|
||||
$page = $_GET['page'];
|
||||
}
|
||||
|
||||
$filterTitle = '';
|
||||
if (isset($_GET['title'])) {
|
||||
$filterTitle = $_GET['title'];
|
||||
}
|
||||
|
||||
$filterOrganiser = '';
|
||||
if (isset($_GET['organiser'])) {
|
||||
$filterOrganiser = $_GET['organiser'];
|
||||
}
|
||||
|
||||
// filter
|
||||
$events = array_values(array_filter(
|
||||
$events,
|
||||
static fn($event) => (preg_match('/.*' . $filterTitle . '.*/i', $event->getName()) && preg_match('/.*' . $filterOrganiser . '.*/i', $event->getOrganiser()))
|
||||
));
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="no">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="../../css/normalize.css">
|
||||
<link rel="stylesheet" href="../../css/style.css">
|
||||
<link rel="stylesheet" href="../../css/nav.css">
|
||||
<link rel="stylesheet" href="../../css/events.css">
|
||||
<link rel="stylesheet" href="../../css/admin.css">
|
||||
<meta name="theme-color" content="#024" />
|
||||
<title>Aktivitetsadministrasjonsverkstedet</title>
|
||||
|
||||
<header>Aktivitets­administrasjons­verk­stedet</header>
|
||||
|
||||
<body>
|
||||
|
||||
<nav>
|
||||
<?php echo navbar(2, 'admin'); ?>
|
||||
<?php echo loginbar(null, $pdo); ?>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
<h2>Aktivitetsadministrasjon</h2>
|
||||
<hr class="ruler">
|
||||
|
||||
<div class="gridsplit">
|
||||
<div class="gridl">
|
||||
<h2 class="no-chin">Aktive aktiviteter</h2>
|
||||
<p class="subnote">Gjentagende aktiviteter vises ikke</p>
|
||||
|
||||
<ul class="event-list">
|
||||
<?php
|
||||
$counter = 0;
|
||||
$pageLimit = 10;
|
||||
|
||||
for ($i = ($pageLimit * ($page - 1)); $i < count($events); ++$i) {
|
||||
if ($counter == $pageLimit) {
|
||||
break;
|
||||
}
|
||||
|
||||
$event = $events[$i];
|
||||
$eventID = $event->getID();
|
||||
?>
|
||||
|
||||
<li>
|
||||
<div class="event admin">
|
||||
<div class="event-info">
|
||||
<h3 class="no-chin"><?php echo $event->getName() . ' (ID: ' . $eventID . ')'; ?></h3>
|
||||
<p class="subnote">
|
||||
<?php echo $event->getStart()->format('(Y-m-d H:i:s)') . ' - ' . $event->getStop()->format('(Y-m-d H:i:s)'); ?>
|
||||
</p>
|
||||
<?php
|
||||
$Parsedown = new Parsedown();
|
||||
echo $Parsedown->text(implode("\n", $event->getDescription()));
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div class="event-actions">
|
||||
<a class="btn" href="edit.php?id=<?php echo $eventID; ?>">Rediger</a><br>
|
||||
<a class="btn" href="delete.php?id=<?php echo $eventID; ?>" onclick="return confirm('Knallsikker? (ID: <?php echo $eventID; ?>)');">Slett</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<?php
|
||||
++$counter;
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
|
||||
<?php
|
||||
if ($page != 1) {
|
||||
echo '<a class="btn float-left" href="?page=' . ($page - 1) . '&title=' . urlencode($filterTitle) . '&organiser=' . urlencode($filterOrganiser) . '">Forrige side</a>';
|
||||
}
|
||||
|
||||
if (($counter == $pageLimit) && (($pageLimit * $page) < count($events))) {
|
||||
echo '<a class="btn float-right" href="?page=' . ($page + 1) . '&title=' . urlencode($filterTitle) . '&organiser=' . urlencode($filterOrganiser) . '">Neste side</a>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div class="gridr">
|
||||
<h2>Verktøy</h2>
|
||||
<a class="btn adminbtn" href="edit.php?new=1">Legg inn ny aktivitet</a>
|
||||
<h2>Filter</h2>
|
||||
<form action="." method="get">
|
||||
<p class="no-chin">Navn</p>
|
||||
<?php echo '<input type="text" name="title" class="boxinput" value="' . $filterTitle . '">'; ?><br>
|
||||
<p class="no-chin">Organisator</p>
|
||||
<?php echo '<input type="text" name="organiser" class="boxinput" value="' . $filterOrganiser . '">'; ?><br>
|
||||
|
||||
<div style="margin-top: 2em;">
|
||||
<input type="submit" class="btn" value="Filtrer"></input>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
date_default_timezone_set('Europe/Oslo');
|
||||
setlocale(\LC_ALL, 'nb_NO');
|
||||
require __DIR__ . '/../../../src/_autoload.php';
|
||||
require __DIR__ . '/../../../config.php';
|
||||
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$userManager = new pvv\admin\UserManager($pdo);
|
||||
|
||||
require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as->requireAuth();
|
||||
$attrs = $as->getAttributes();
|
||||
$uname = $attrs['uid'][0];
|
||||
|
||||
if (!$userManager->hasGroup($uname, 'aktiviteter')) {
|
||||
echo 'Her har du ikke lov\'t\'å\'værra!!!';
|
||||
exit;
|
||||
}
|
||||
|
||||
if ((!isset($_POST['title']))
|
||||
|| (!isset($_POST['desc']))
|
||||
|| (!isset($_POST['organiser']))
|
||||
|| (!isset($_POST['location']))
|
||||
|| (!isset($_POST['start_mon']))
|
||||
|| (!isset($_POST['start_day']))
|
||||
|| (!isset($_POST['start_time']))
|
||||
|| (!isset($_POST['lasts_hours']))
|
||||
|| (!isset($_POST['lasts_minutes']))) {
|
||||
header('Location: ' . $_SERVER['HTTP_REFERER']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id = 0;
|
||||
if (isset($_POST['id'])) {
|
||||
$id = $_POST['id'];
|
||||
}
|
||||
|
||||
$title = $_POST['title'];
|
||||
$desc = $_POST['desc'];
|
||||
// $start = $_POST['start'];
|
||||
// $stop = $_POST['end'];
|
||||
$organiser = $_POST['organiser'];
|
||||
$location = $_POST['location'];
|
||||
|
||||
$date_part_start_mon = $_POST['start_mon'];
|
||||
$date_part_start_day = $_POST['start_day'];
|
||||
$date_part_start_time = $_POST['start_time'];
|
||||
$date_part_lasts_hours = $_POST['lasts_hours'];
|
||||
$date_part_lasts_minutes = $_POST['lasts_minutes'];
|
||||
|
||||
while (strlen($date_part_start_day) < 2) {
|
||||
$date_part_start_day = '0' . $date_part_start_day;
|
||||
}
|
||||
|
||||
$start = ($date_part_start_mon . '-' . $date_part_start_day . ' ' . $date_part_start_time);
|
||||
if (count(explode(':', $date_part_start_time)) == 2) {
|
||||
$start .= ':00';
|
||||
}
|
||||
|
||||
$start_date = DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $start);
|
||||
$stop_date = $start_date->add(new DateInterval('PT' . $date_part_lasts_hours . 'H' . $date_part_lasts_minutes . 'M'));
|
||||
$start = $start_date->format('Y-m-d H:i:s');
|
||||
$stop = $stop_date->format('Y-m-d H:i:s');
|
||||
|
||||
if ($start_date >= $stop_date) {
|
||||
echo 'Invalid dates. End date must come after the start date!';
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
if ($id == 0) {
|
||||
$query = '
|
||||
INSERT INTO
|
||||
events(name, start, stop, organiser, location, description)
|
||||
VALUES
|
||||
(:title, :start, :stop, :organiser, :loc, :desc)
|
||||
';
|
||||
$statement = $pdo->prepare($query);
|
||||
|
||||
$statement->bindValue(':title', $title, PDO::PARAM_STR);
|
||||
$statement->bindValue(':desc', $desc, PDO::PARAM_STR);
|
||||
$statement->bindValue(':start', $start, PDO::PARAM_STR);
|
||||
$statement->bindValue(':stop', $stop, PDO::PARAM_STR);
|
||||
$statement->bindValue(':organiser', $organiser, PDO::PARAM_STR);
|
||||
$statement->bindValue(':loc', $location, PDO::PARAM_STR);
|
||||
} else {
|
||||
$query = '
|
||||
UPDATE
|
||||
events
|
||||
SET
|
||||
name = :title,
|
||||
start = :start,
|
||||
stop = :stop,
|
||||
organiser = :organiser,
|
||||
location = :loc,
|
||||
description = :desc
|
||||
WHERE
|
||||
id = :id
|
||||
';
|
||||
$statement = $pdo->prepare($query);
|
||||
|
||||
$statement->bindValue(':title', $title, PDO::PARAM_STR);
|
||||
$statement->bindValue(':desc', $desc, PDO::PARAM_STR);
|
||||
$statement->bindValue(':start', $start, PDO::PARAM_STR);
|
||||
$statement->bindValue(':stop', $stop, PDO::PARAM_STR);
|
||||
$statement->bindValue(':organiser', $organiser, PDO::PARAM_STR);
|
||||
$statement->bindValue(':loc', $location, PDO::PARAM_STR);
|
||||
$statement->bindValue(':id', $id, PDO::PARAM_INT);
|
||||
}
|
||||
|
||||
$statement->execute();
|
||||
|
||||
header('Location: .');
|
||||
?>
|
||||
|
||||
<a href=".?page=1">Om du ikke ble automatisk omdirigert tilbake klikk her</a>
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
ini_set('display_errors', '1');
|
||||
date_default_timezone_set('Europe/Oslo');
|
||||
setlocale(\LC_ALL, 'nb_NO');
|
||||
error_reporting(\E_ALL);
|
||||
require __DIR__ . '/../../../inc/navbar.php';
|
||||
require __DIR__ . '/../../../src/_autoload.php';
|
||||
require __DIR__ . '/../../../config.php';
|
||||
require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$attrs = $as->getAttributes();
|
||||
|
||||
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$userManager = new pvv\admin\UserManager($pdo);
|
||||
|
||||
require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as->requireAuth();
|
||||
$attrs = $as->getAttributes();
|
||||
$uname = $attrs['uid'][0];
|
||||
|
||||
if (!$userManager->isAdmin($uname)) {
|
||||
echo 'Her har du ikke lov\'t\'å\'værra!!!';
|
||||
exit;
|
||||
}
|
||||
|
||||
$users = $userManager->getAllUserData();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="no">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="../../css/normalize.css">
|
||||
<link rel="stylesheet" href="../../css/style.css">
|
||||
<link rel="stylesheet" href="../../css/events.css">
|
||||
<link rel="stylesheet" href="../../css/admin.css">
|
||||
<meta name="theme-color" content="#024" />
|
||||
<title>Brukeradministrasjonsverkstedet</title>
|
||||
|
||||
<header>Bruker­administrasjons­verk­stedet</header>
|
||||
|
||||
<body>
|
||||
<nav>
|
||||
<?php echo navbar(2, 'admin'); ?>
|
||||
<?php echo loginbar(null, $pdo); ?>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
<h2>Brukeradministrasjon</h2>
|
||||
<hr class="ruler">
|
||||
|
||||
<form action="./update.php" method="post">
|
||||
<table class="userlist">
|
||||
<tr>
|
||||
<th>Brukernavn</th>
|
||||
<th>Brukergrupper</th>
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
$users_to_update = [];
|
||||
foreach ($users as $i => $data) {
|
||||
$uname = $data['name'];
|
||||
$groupFlag = $userManager->getUsergroups($uname);
|
||||
|
||||
$users_to_update[] = $uname;
|
||||
?>
|
||||
|
||||
<tr>
|
||||
<td><?php echo $uname; ?></td>
|
||||
<?php
|
||||
foreach ($userManager->usergroups as $name => $group) {
|
||||
echo '<td><input type="checkbox" ' . (($groupFlag & $group) ? 'checked' : '') . ' name="' . $uname . '_' . $name . '" class="usergroupcheckbox">' . $name . '</td>';
|
||||
}
|
||||
?>
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
}
|
||||
foreach ($users_to_update as $uname) {
|
||||
echo '<input type="hidden" name="user_to_update" value="' . $uname . '" />';
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<tr class="newuserrow">
|
||||
<td class="newuserelement"><input type="text" name="newuser" class="newuserinput"></td>
|
||||
<?php
|
||||
foreach ($userManager->usergroups as $name => $group) {
|
||||
echo '<td><input type="checkbox" name="newuser_' . $name . '" class="usergroupcheckbox">' . $name . '</td>';
|
||||
}
|
||||
?>
|
||||
</tr>
|
||||
</table>
|
||||
<input type="submit" class="btn" value="Lagre">
|
||||
</form>
|
||||
</main>
|
||||
</body>
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
ini_set('display_errors', '1');
|
||||
date_default_timezone_set('Europe/Oslo');
|
||||
setlocale(\LC_ALL, 'nb_NO');
|
||||
error_reporting(\E_ALL);
|
||||
require __DIR__ . '/../../../src/_autoload.php';
|
||||
require __DIR__ . '/../../../config.php';
|
||||
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$userManager = new pvv\admin\UserManager($pdo);
|
||||
|
||||
require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as->requireAuth();
|
||||
$attrs = $as->getAttributes();
|
||||
$uname = $attrs['uid'][0];
|
||||
|
||||
if (!$userManager->isAdmin($uname)) {
|
||||
echo 'Her har du ikke lov\'t\'å\'værra!!!';
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
if (isset($_POST['newuser'])) {
|
||||
$newUser = $_POST['newuser'];
|
||||
unset($_POST['newuser']);
|
||||
}
|
||||
|
||||
// $updatingUsers = explode('_', $_POST['users']);
|
||||
$updatingUsers = [];
|
||||
foreach ($_POST as $key => $value) {
|
||||
if ($key === 'user_to_update') {
|
||||
$updatingUsers[] = $value;
|
||||
}
|
||||
}
|
||||
unset($_POST['user_to_update']);
|
||||
|
||||
// 2d array of usernames and their corresponding group flags
|
||||
$userFlags = [];
|
||||
if ($newUser) {
|
||||
$userFlags[$newUser] = 0;
|
||||
}
|
||||
|
||||
foreach ($_POST as $namegroup => $info) {
|
||||
$data = explode('_', $namegroup);
|
||||
$group = array_pop($data);
|
||||
$uname = implode('_', $data);
|
||||
if ($uname == 'newuser') {
|
||||
if (!$newUser) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$uname = $newUser;
|
||||
}
|
||||
|
||||
if (!isset($userFlags[$uname])) {
|
||||
$userFlags[$uname] = 0;
|
||||
}
|
||||
|
||||
$userFlags[$uname] = ($userFlags[$uname] | $userManager->usergroups[$group]);
|
||||
}
|
||||
|
||||
foreach ($updatingUsers as $uname) {
|
||||
if (!array_key_exists($uname, $userFlags)) {
|
||||
$userFlags[$uname] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($userFlags as $uname => $flag) {
|
||||
$userManager->setGroups($uname, $flag);
|
||||
}
|
||||
|
||||
header('Location: .');
|
||||
?>
|
||||
|
||||
<a href=".">Om du ikke ble automatisk omdirigert tilbake klikk her</a>
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
require_once dirname(__DIR__, 2) . implode(\DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']);
|
||||
|
||||
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$userManager = new pvv\admin\UserManager($pdo);
|
||||
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as->requireAuth();
|
||||
$attrs = $as->getAttributes();
|
||||
$uname = $attrs['uid'][0];
|
||||
|
||||
$isAdmin = $userManager->isAdmin($uname);
|
||||
$projectGroup = $userManager->hasGroup($uname, 'prosjekt');
|
||||
$activityGroup = $userManager->hasGroup($uname, 'aktiviteter');
|
||||
|
||||
if (!($isAdmin | $projectGroup | $activityGroup)) {
|
||||
header('Content-Type: text/plain', true, 403);
|
||||
echo "Her har du ikke lov't'å'værra!!!\r\n";
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="no">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="../css/normalize.css">
|
||||
<link rel="stylesheet" href="../css/style.css">
|
||||
<link rel="stylesheet" href="../css/events.css">
|
||||
<link rel="stylesheet" href="../css/admin.css">
|
||||
<meta name="theme-color" content="#024" />
|
||||
<title>Administrasjonsverkstedet</title>
|
||||
|
||||
<header>Administrasjons­verk­stedet</header>
|
||||
|
||||
|
||||
<body>
|
||||
<nav id="navbar">
|
||||
<?php echo navbar(1, 'admin'); ?>
|
||||
<?php echo loginbar(null, $pdo); ?>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
<h2>Administrasjon</h2>
|
||||
<ul class="tools">
|
||||
<?php if ($isAdmin | $activityGroup) : ?>
|
||||
<li><a class="btn" href="aktiviteter/?page=1">Aktiviteter/Hendelser</a></li>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($isAdmin | $projectGroup) : ?>
|
||||
<li><a class="btn" href="prosjekter/?page=1">Prosjekter</a></li>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($isAdmin) : ?>
|
||||
<li><a class="btn" href="motd/">Dagens melding</a></li>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($isAdmin) : ?>
|
||||
<li><a class="btn" href="brukere/">Brukerrettigheter</a></li>
|
||||
<?php endif ?>
|
||||
<ul>
|
||||
</main>
|
||||
</body>
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
ini_set('display_errors', '1');
|
||||
date_default_timezone_set('Europe/Oslo');
|
||||
setlocale(\LC_ALL, 'no_NO');
|
||||
error_reporting(\E_ALL);
|
||||
require __DIR__ . '/../../../inc/navbar.php';
|
||||
require __DIR__ . '/../../../src/_autoload.php';
|
||||
require __DIR__ . '/../../../config.php';
|
||||
require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$attrs = $as->getAttributes();
|
||||
|
||||
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$userManager = new pvv\admin\UserManager($pdo);
|
||||
|
||||
require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as->requireAuth();
|
||||
$attrs = $as->getAttributes();
|
||||
$uname = $attrs['uid'][0];
|
||||
|
||||
if (!$userManager->isAdmin($uname)) {
|
||||
echo 'Her har du ikke lov\'t\'å\'værra!!!';
|
||||
exit;
|
||||
}
|
||||
|
||||
$motdfetcher = new pvv\side\MOTD($pdo);
|
||||
$motd = $motdfetcher->getMOTD();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="no">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="../../css/normalize.css">
|
||||
<link rel="stylesheet" href="../../css/style.css">
|
||||
<link rel="stylesheet" href="../../css/nav.css">
|
||||
<link rel="stylesheet" href="../../css/events.css">
|
||||
<link rel="stylesheet" href="../../css/admin.css">
|
||||
<meta name="theme-color" content="#024" />
|
||||
<title>MOTDadministrasjonsverkstedet</title>
|
||||
|
||||
<header>MOTD­administrasjons­verk­stedet</header>
|
||||
|
||||
<body>
|
||||
<nav>
|
||||
<?php echo navbar(2, 'admin'); ?>
|
||||
<?php echo loginbar(null, $pdo); ?>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
<h2>Dagens melding</h2>
|
||||
<hr class="ruler">
|
||||
|
||||
<form action="update.php", method="post">
|
||||
<p class="subtitle no-chin">Tittel</p>
|
||||
<p class="subnote">Ikke nødvendig</p>
|
||||
<input type="text" name="title" value="<?php echo $motd->getTitle(); ?>" class="boxinput" style="width:66%;"><br>
|
||||
|
||||
<p class="subtitle no-chin">Innhold (<i>markdown</i>)</p>
|
||||
<textarea name="content" style="width:100%" rows="8" class="boxinput"><?php echo $motd->getContentAsString(); ?></textarea>
|
||||
|
||||
<div style="margin-top: 2em;">
|
||||
<hr class="ruler">
|
||||
|
||||
<?php echo '<input type="submit" class="btn" value="Lagre endringer"></a>'; ?>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
</body>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
ini_set('display_errors', '1');
|
||||
date_default_timezone_set('Europe/Oslo');
|
||||
setlocale(\LC_ALL, 'no_NO');
|
||||
error_reporting(\E_ALL);
|
||||
require __DIR__ . '/../../../src/_autoload.php';
|
||||
require __DIR__ . '/../../../config.php';
|
||||
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$userManager = new pvv\admin\UserManager($pdo);
|
||||
|
||||
require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as->requireAuth();
|
||||
$attrs = $as->getAttributes();
|
||||
$uname = $attrs['uid'][0];
|
||||
|
||||
if (!isset($_POST['title']) || !isset($_POST['content'])) {
|
||||
header('Location: ' . $_SERVER['HTTP_REFERER']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!$userManager->isAdmin($uname)) {
|
||||
echo 'Her har du ikke lov\'t\'å\'værra!!!';
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
$motdfetcher = new pvv\side\MOTD($pdo);
|
||||
$motdfetcher->setMOTD($_POST['title'], $_POST['content']);
|
||||
|
||||
header('Location: .');
|
||||
?>
|
||||
|
||||
<a href=".">Om du ikke ble automatisk omdirigert tilbake klikk her</a>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
require __DIR__ . '/../../../src/_autoload.php';
|
||||
require __DIR__ . '/../../../config.php';
|
||||
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$userManager = new pvv\admin\UserManager($pdo);
|
||||
|
||||
require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as->requireAuth();
|
||||
$attrs = $as->getAttributes();
|
||||
$uname = $attrs['uid'][0];
|
||||
|
||||
if (!$userManager->hasGroup($uname, 'prosjekt')) {
|
||||
echo 'Her har du ikke lov\'t\'å\'værra!!!';
|
||||
exit;
|
||||
}
|
||||
|
||||
$projectID = $_GET['id'];
|
||||
|
||||
$query = 'DELETE FROM project WHERE id=:projectID';
|
||||
$statement = $pdo->prepare($query);
|
||||
$statement->bindValue(':projectID', $projectID, PDO::PARAM_INT);
|
||||
$statement->execute();
|
||||
|
||||
header('Location: ' . $_SERVER['HTTP_REFERER']);
|
||||
?>
|
||||
|
||||
<a href=".?page=1">Om du ikke ble omdirigert tilbake klikk her</a>
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
date_default_timezone_set('Europe/Oslo');
|
||||
setlocale(\LC_ALL, 'nb_NO');
|
||||
require __DIR__ . '/../../../inc/navbar.php';
|
||||
require __DIR__ . '/../../../src/_autoload.php';
|
||||
require __DIR__ . '/../../../config.php';
|
||||
|
||||
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$userManager = new pvv\admin\UserManager($pdo);
|
||||
|
||||
require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as->requireAuth();
|
||||
$attrs = $as->getAttributes();
|
||||
$uname = $attrs['uid'][0];
|
||||
|
||||
if (!$userManager->hasGroup($uname, 'prosjekt')) {
|
||||
echo 'Her har du ikke lov\'t\'å\'værra!!!';
|
||||
exit;
|
||||
}
|
||||
|
||||
$projectManager = new pvv\side\ProjectManager($pdo);
|
||||
$projects = $projectManager->getAll();
|
||||
|
||||
$new = 0;
|
||||
if (isset($_GET['new'])) {
|
||||
$new = $_GET['new'];
|
||||
}
|
||||
|
||||
$projectID = 0;
|
||||
if (isset($_GET['id'])) {
|
||||
$projectID = $_GET['id'];
|
||||
} elseif ($new == 0) {
|
||||
echo "\nID not set";
|
||||
exit;
|
||||
}
|
||||
|
||||
$project = new pvv\side\Project(
|
||||
id: 0,
|
||||
title: 'Kult Prosjekt',
|
||||
description_en: '',
|
||||
description_no: '',
|
||||
gitea_link: 'https://git.pvv.ntnu.no/Projects/kultprosjekt',
|
||||
issue_board_link: 'https://git.pvv.ntnu.no/Projects/kultprosjekt/issues',
|
||||
wiki_link: 'https://wiki.pvv.ntnu.no/wiki/Kult_Prosjekt',
|
||||
programming_languages: 'PHP, HTML, CSS, JavaScript',
|
||||
technologies: 'MySQL, REST, AJAX',
|
||||
keywords: 'web, very-cool',
|
||||
license: 'GPL-3.0',
|
||||
logo_url: '',
|
||||
);
|
||||
if ($new == 0) {
|
||||
$project = $projectManager->getByID($projectID);
|
||||
}
|
||||
|
||||
$members = $projectManager->getProjectMembers($projectID);
|
||||
$owner = [
|
||||
'name' => '',
|
||||
'uname' => '',
|
||||
'mail' => '',
|
||||
];
|
||||
foreach ($members as $i => $data) {
|
||||
if ($data['is_owner']) {
|
||||
$owner = $data;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="no">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="../../css/normalize.css">
|
||||
<link rel="stylesheet" href="../../css/style.css">
|
||||
<link rel="stylesheet" href="../../css/events.css">
|
||||
<link rel="stylesheet" href="../../css/admin.css">
|
||||
<meta name="theme-color" content="#024" />
|
||||
<title>Prosjektadministrasjonsverkstedet</title>
|
||||
|
||||
<header>Prosjekt­administrasjons­verk­stedet</header>
|
||||
|
||||
<body>
|
||||
<nav>
|
||||
<?php echo navbar(3, 'admin'); ?>
|
||||
<?php echo loginbar(null, $pdo); ?>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
<h2>Prosjektadministrasjon</h2>
|
||||
<hr class="ruler">
|
||||
|
||||
<h2><?php echo $new == 1 ? 'Nytt prosjekt' : 'Rediger prosjekt'; ?></h2>
|
||||
|
||||
<form action="update.php", method="post" class="gridsplit5050">
|
||||
<div class="gridl">
|
||||
<p class="subtitle">Tittel</p>
|
||||
<?php echo '<input type="text" name="title" value="' . $project->getName() . '" class="boxinput">'; ?><br>
|
||||
|
||||
<p class="subtitle">Beskrivelse (<i>markdown</i>)</p>
|
||||
<textarea name="desc" cols="40" rows="5" class="boxinput"><?php echo implode("\n", $project->getDescription()); ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="gridr noborder">
|
||||
<p class="subtitle">Prosjektleder (Brukernavn)</p>
|
||||
<?php echo '<input type="text" name="organiser" value="' . $owner['uname'] . '" class="boxinput">'; ?><br>
|
||||
|
||||
<p class="subtitle">Prosjektleder (Navn)</p>
|
||||
<?php echo '<input type="text" name="organisername" value="' . $owner['name'] . '" class="boxinput">'; ?>
|
||||
|
||||
<p class="subtitle">Prosjektleder E-post</p>
|
||||
<?php echo '<input type="text" name="organiseremail" value="' . $owner['mail'] . '" class="boxinput">'; ?><br>
|
||||
|
||||
<p class="subtitle">Aktiv</p>
|
||||
<?php echo '<input type="checkbox" ' . ($project->getActive() ? 'checked' : '') . ' name="active"/>'; ?>
|
||||
</div>
|
||||
|
||||
<?php echo '<input type="hidden" name="id" value="' . $project->getID() . '" />'; ?>
|
||||
|
||||
<?php if (!$new) { ?>
|
||||
<div style="grid-column: span 2;">
|
||||
<hr class="ruler">
|
||||
</div>
|
||||
|
||||
<h2 style="grid-column: span 2">Prosjektmedlemmer</h2>
|
||||
|
||||
<table class="userlist" style="grid-column: span 2;">
|
||||
<tr><th>Brukernavn</th><th>Navn</th><th>Rolle</th></tr>
|
||||
<?php foreach ($members as $i => $data) { ?>
|
||||
<tr>
|
||||
<td><?php echo $data['uname']; ?></td>
|
||||
<td><?php echo $data['name']; ?></td>
|
||||
<td><?php echo $data['role']; ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
|
||||
<tr class="newuserrow">
|
||||
<td class="newuserelement"><input type="text" name="newuser_uname"></td>
|
||||
<td class="newuserelement"><input type="text" name="newuser_name"></td>
|
||||
<td class="newuserelement"><input type="text" name="newuser_role"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php } ?>
|
||||
|
||||
<div class="allgrids" style="margin-top: 2em;">
|
||||
<hr class="ruler">
|
||||
|
||||
<input type="submit" class="btn" value="Lagre">
|
||||
</div>
|
||||
</form>
|
||||
<p>
|
||||
</main>
|
||||
</body>
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
date_default_timezone_set('Europe/Oslo');
|
||||
setlocale(\LC_ALL, 'nb_NO');
|
||||
require __DIR__ . '/../../../inc/navbar.php';
|
||||
require __DIR__ . '/../../../src/_autoload.php';
|
||||
require __DIR__ . '/../../../config.php';
|
||||
|
||||
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$userManager = new pvv\admin\UserManager($pdo);
|
||||
|
||||
require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as->requireAuth();
|
||||
$attrs = $as->getAttributes();
|
||||
$uname = $attrs['uid'][0];
|
||||
|
||||
if (!$userManager->hasGroup($uname, 'prosjekt')) {
|
||||
echo 'Her har du ikke lov\'t\'å\'værra!!!';
|
||||
exit;
|
||||
}
|
||||
|
||||
$projectManager = new pvv\side\ProjectManager($pdo);
|
||||
$projects = $projectManager->getAll();
|
||||
|
||||
$page = 1;
|
||||
if (isset($_GET['page'])) {
|
||||
$page = $_GET['page'];
|
||||
}
|
||||
|
||||
$filterTitle = '';
|
||||
if (isset($_POST['title'])) {
|
||||
$filterTitle = $_POST['title'];
|
||||
}
|
||||
|
||||
/* Temporarily out of service :<
|
||||
$filterOrganiser = '';
|
||||
if(isset($_POST['organiser'])){
|
||||
$filterOrganiser = $_POST['organiser'];
|
||||
}
|
||||
*/
|
||||
|
||||
// filter
|
||||
$projects = array_values(array_filter(
|
||||
$projects,
|
||||
static fn($project) => preg_match('/.*' . $filterTitle . '.*/i', $project->getTitle())
|
||||
));
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="no">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="../../css/normalize.css">
|
||||
<link rel="stylesheet" href="../../css/style.css">
|
||||
<link rel="stylesheet" href="../../css/nav.css">
|
||||
<link rel="stylesheet" href="../../css/events.css">
|
||||
<link rel="stylesheet" href="../../css/admin.css">
|
||||
<meta name="theme-color" content="#024" />
|
||||
<title>Prosjektadministrasjonsverkstedet</title>
|
||||
|
||||
<header>Prosjekt­administrasjons­verk­stedet</header>
|
||||
|
||||
<body>
|
||||
<nav>
|
||||
<?php echo navbar(2, 'admin'); ?>
|
||||
<?php echo loginbar(null, $pdo); ?>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
<h2>Prosjektadministrasjon</h2>
|
||||
<hr class="ruler">
|
||||
|
||||
<div class="gridsplit">
|
||||
<div class="gridl">
|
||||
<h2 class="no-chin">Prosjekter</h2>
|
||||
|
||||
<ul class="event-list">
|
||||
<?php
|
||||
$counter = 0;
|
||||
$pageLimit = 4;
|
||||
|
||||
for ($i = ($pageLimit * ($page - 1)); $i < count($projects); ++$i) {
|
||||
if ($counter == $pageLimit) {
|
||||
break;
|
||||
}
|
||||
|
||||
$project = $projects[$i];
|
||||
$projectID = $project->getID();
|
||||
$organizers = $projectManager->getProjectOrganizers($projectID);
|
||||
?>
|
||||
|
||||
<li>
|
||||
<div class="event admin">
|
||||
<div class="event-info">
|
||||
<h3 class="no-chin"><?php echo $project->getTitle() . ' (ID: ' . $projectID . ')'; ?></h3>
|
||||
<p class="subnote"><?php echo 'Organisert av: ' . implode(',', array_map(function($org) { return $org->getName(); }, $organizers)); ?></p>
|
||||
<?php
|
||||
$Parsedown = new Parsedown();
|
||||
echo $Parsedown->text(implode("\n", $project->getDescriptionNo()));
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div class="event-actions">
|
||||
<?php echo '<a href="edit.php?id=' . $projectID . '">🖊</a>'; ?>
|
||||
<?php echo '<a href="delete.php?id=' . $projectID . '" onclick="return confirm(\'Knallsikker? (ID: ' . $projectID . ')\');">🗑</a>'; ?>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<?php
|
||||
++$counter;
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
|
||||
<?php
|
||||
if ($page != 1) {
|
||||
echo '<a class="btn float-left" href="?page=' . ($page - 1) . '">Forrige side</a>';
|
||||
}
|
||||
|
||||
if (($counter == $pageLimit) && (($pageLimit * $page) < count($projects))) {
|
||||
echo '<a class="btn float-right" href="?page=' . ($page + 1) . '">Neste side</a>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div class="gridr">
|
||||
<h2>Verktøy</h2>
|
||||
<a class="btn adminbtn" href="edit.php?new=1">Legg inn nytt prosjekt</a>
|
||||
<h2>Filter</h2>
|
||||
<form action="." method="post">
|
||||
<p class="no-chin">Prosjektnavn</p>
|
||||
<?php echo '<input type="text" name="title" class="boxinput" value="' . $filterTitle . '">'; ?><br>
|
||||
<p class="no-chin">Leders brukernavn</p>
|
||||
<?php echo '<input type="text" name="organiser" class="boxinput" value="">'; ?><br>
|
||||
|
||||
<div style="margin-top: 2em;">
|
||||
<input type="submit" class="btn" value="Filtrer"></input>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</body>
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
date_default_timezone_set('Europe/Oslo');
|
||||
setlocale(\LC_ALL, 'nb_NO');
|
||||
require __DIR__ . '/../../../src/_autoload.php';
|
||||
require __DIR__ . '/../../../config.php';
|
||||
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$userManager = new pvv\admin\UserManager($pdo);
|
||||
|
||||
require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as->requireAuth();
|
||||
$attrs = $as->getAttributes();
|
||||
$uname = $attrs['uid'][0];
|
||||
|
||||
if (!$userManager->hasGroup($uname, 'prosjekt')) {
|
||||
echo 'Her har du ikke lov\'t\'å\'værra!!!';
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!isset($_POST['title']) || !isset($_POST['desc']) || !isset($_POST['organisername']) || !isset($_POST['organiser'])) {
|
||||
header('Location: ' . $_SERVER['HTTP_REFERER']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id = 0;
|
||||
if (isset($_POST['id'])) {
|
||||
$id = $_POST['id'];
|
||||
}
|
||||
|
||||
$title = $_POST['title'];
|
||||
$desc = $_POST['desc'];
|
||||
$name = $_POST['organisername'];
|
||||
$uname = $_POST['organiser'];
|
||||
$mail = $_POST['organiseremail'];
|
||||
$active = ($_POST['active'] ?? false);
|
||||
|
||||
|
||||
if ($id == 0) {
|
||||
$query = '
|
||||
INSERT INTO
|
||||
projects(name, description, active)
|
||||
VALUES
|
||||
(:title, :desc, :active)
|
||||
';
|
||||
$statement = $pdo->prepare($query);
|
||||
|
||||
$statement->bindValue(':title', $title, PDO::PARAM_STR);
|
||||
$statement->bindValue(':desc', $desc, PDO::PARAM_STR);
|
||||
$statement->bindValue(':active', $active, PDO::PARAM_BOOL);
|
||||
|
||||
$statement->execute();
|
||||
|
||||
$ownerQuery = '
|
||||
INSERT INTO
|
||||
projectmembers(projectid, name, uname, mail, role, lead, owner)
|
||||
VALUES
|
||||
(last_insert_rowid(), :owner, :owneruname, :owneremail, \'Prosjektleder\', 1, 1)
|
||||
';
|
||||
$statement = $pdo->prepare($ownerQuery);
|
||||
$statement->bindValue(':owner', $name, PDO::PARAM_STR);
|
||||
$statement->bindValue(':owneruname', $uname, PDO::PARAM_STR);
|
||||
$statement->bindValue(':owneremail', $mail, PDO::PARAM_STR);
|
||||
|
||||
$statement->execute();
|
||||
} else {
|
||||
$query = '
|
||||
UPDATE
|
||||
projects
|
||||
SET
|
||||
name = :title,
|
||||
description = :desc,
|
||||
active = :active
|
||||
WHERE
|
||||
id = :id
|
||||
';
|
||||
$statement = $pdo->prepare($query);
|
||||
|
||||
$statement->bindValue(':title', $title, PDO::PARAM_STR);
|
||||
$statement->bindValue(':desc', $desc, PDO::PARAM_STR);
|
||||
$statement->bindValue(':active', $active, PDO::PARAM_BOOL);
|
||||
$statement->bindValue(':id', $id, PDO::PARAM_INT);
|
||||
|
||||
$statement->execute();
|
||||
|
||||
$query = '
|
||||
UPDATE
|
||||
projectmembers
|
||||
SET
|
||||
name = :name,
|
||||
uname = :uname,
|
||||
mail = :mail
|
||||
';
|
||||
$statement = $pdo->prepare($query);
|
||||
|
||||
$statement->bindValue(':name', $name, PDO::PARAM_STR);
|
||||
$statement->bindValue(':uname', $uname, PDO::PARAM_STR);
|
||||
$statement->bindValue(':mail', $mail, PDO::PARAM_STR);
|
||||
|
||||
$statement->execute();
|
||||
}
|
||||
|
||||
header('Location: .');
|
||||
?>
|
||||
|
||||
<a href=".?page=1">Om du ikke ble automatisk omdirigert tilbake klikk her</a>
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace pvv\side;
|
||||
|
||||
require_once \dirname(__DIR__, 2) . implode(\DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']);
|
||||
|
||||
$year = (isset($_GET['year']))
|
||||
? $_GET['year']
|
||||
: date('Y');
|
||||
$month = (isset($_GET['month']))
|
||||
? $_GET['month']
|
||||
: date('m');
|
||||
$day = (isset($_GET['day']))
|
||||
? $_GET['day']
|
||||
: -1;
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="no">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="../css/normalize.css">
|
||||
<link rel="stylesheet" href="../css/style.css">
|
||||
<link rel="stylesheet" href="../css/events.css">
|
||||
<meta name="theme-color" content="#024" />
|
||||
<title>Aktivitetsverkstedet</title>
|
||||
|
||||
<header>Aktivitets­verk­stedet</header>
|
||||
|
||||
|
||||
<body>
|
||||
<nav>
|
||||
<?php echo navbar(1, 'aktiviteter'); ?>
|
||||
<?php echo loginbar(null, $pdo); ?>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
<?php
|
||||
use DateTimeImmutable;
|
||||
|
||||
$events = ($day == -1)
|
||||
? $agenda->getNextOfEach(new DateTimeImmutable())
|
||||
: $agenda->getEventsBetween(
|
||||
new DateTimeImmutable("{$year}-{$month}-{$day} 00:00:00"),
|
||||
new DateTimeImmutable("{$year}-{$month}-{$day} 23:59:59")
|
||||
);
|
||||
|
||||
$limit = 0;
|
||||
foreach ($events as $event) {
|
||||
?>
|
||||
<article>
|
||||
<h2>
|
||||
<?php if (Agenda::isToday($event->getStart())) { ?><strong><?php } ?>
|
||||
<em><?php echo $event->getRelativeDate(); ?></em>
|
||||
<?php if (Agenda::isToday($event->getStart())) { ?></strong><?php } ?>
|
||||
<?php if ($event->getURL()) { ?>
|
||||
<br>
|
||||
<a href="<?php echo $event->getURL(); ?>"><?php echo $event->getName(); ?></a>
|
||||
<?php } else { ?>
|
||||
<?php echo $event->getName(); ?>
|
||||
<?php } ?>
|
||||
<?php if ($event->getImageURL()) { ?>
|
||||
<img src="<?php echo $event->getImageURL(); ?>">
|
||||
<?php } ?>
|
||||
</h2>
|
||||
<ul class="subtext">
|
||||
<li>Tid: <strong><?php echo Agenda::getFormattedDate($event->getStart()); ?></strong></li>
|
||||
<li>Sted: <strong><?php echo $event->getLocation(); ?></strong></li>
|
||||
<li>Arrangør: <strong><?php echo $event->getOrganiser(); ?></strong></li>
|
||||
</ul>
|
||||
|
||||
<?php $description = $event->getDescription(); ?>
|
||||
<?php if ($limit) {
|
||||
array_splice($description, $limit);
|
||||
} ?>
|
||||
<?php
|
||||
$Parsedown = new \Parsedown();
|
||||
echo $Parsedown->text(implode("\n", $description));
|
||||
?>
|
||||
</article>
|
||||
|
||||
<?php } ?>
|
||||
</main>
|
||||
|
||||
</body>
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
require_once dirname(__DIR__, 2) . implode(\DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']);
|
||||
use pvv\side\Agenda;
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="no">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="../css/normalize.css">
|
||||
<link rel="stylesheet" href="../css/style.css">
|
||||
<link rel="stylesheet" href="../css/nav.css">
|
||||
<link rel="stylesheet" href="../css/events.css">
|
||||
<meta name="theme-color" content="#024" />
|
||||
<title>Animeverkstedet</title>
|
||||
|
||||
<header>Sosial­verk­stedet</header>
|
||||
|
||||
|
||||
<main>
|
||||
|
||||
<?php
|
||||
$activity = new pvv\side\social\AnimekveldActivity();
|
||||
$nextEvent = $activity->getNextEventFrom(new DateTimeImmutable());
|
||||
?>
|
||||
|
||||
<article>
|
||||
<h2><em><?php echo $nextEvent->getRelativeDate(); ?></em> Animekveld
|
||||
<?php if ($nextEvent->getImageURL()) { ?>
|
||||
<img src="<?php echo $nextEvent->getImageURL(); ?>">
|
||||
<?php } ?>
|
||||
</h2>
|
||||
<ul class="subtext">
|
||||
<li>Tid:
|
||||
<strong>
|
||||
<?php echo Agenda::getFormattedDate($nextEvent->getStart()); ?>
|
||||
</strong>
|
||||
<li>Sted:
|
||||
<strong>
|
||||
<?php echo $nextEvent->getLocation(); ?>
|
||||
</strong>
|
||||
<li>Arrangør:
|
||||
<strong>
|
||||
<?php echo $nextEvent->getOrganiser(); ?>
|
||||
</strong>
|
||||
</ul>
|
||||
|
||||
<?php
|
||||
$Parsedown = new Parsedown();
|
||||
echo $Parsedown->text(implode("\n", $nextEvent->getDescription()));
|
||||
?>
|
||||
</article>
|
||||
|
||||
</main>
|
||||
|
||||
<nav>
|
||||
<?php echo navbar(1, 'aktiviteter'); ?>
|
||||
<?php echo loginbar($sp, $pdo); ?>
|
||||
</nav>
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
require_once dirname(__DIR__, 2) . implode(\DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']);
|
||||
use pvv\side\Agenda;
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="no">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="../css/normalize.css">
|
||||
<link rel="stylesheet" href="../css/style.css">
|
||||
<link rel="stylesheet" href="../css/nav.css">
|
||||
<link rel="stylesheet" href="../css/events.css">
|
||||
<meta name="theme-color" content="#024" />
|
||||
<title>Sosialverkstedet</title>
|
||||
|
||||
<header>Sosial­verk­stedet</header>
|
||||
|
||||
|
||||
<main>
|
||||
|
||||
<?php
|
||||
$activity = new pvv\side\social\BrettspillActivity();
|
||||
$nextEvent = $activity->getNextEventFrom(new DateTimeImmutable());
|
||||
?>
|
||||
|
||||
<article>
|
||||
|
||||
<h2><em><?php echo $nextEvent->getRelativeDate(); ?></em> Brettspillkveld
|
||||
<?php if ($nextEvent->getImageURL()) { ?>
|
||||
<img src="<?php echo $nextEvent->getImageURL(); ?>">
|
||||
<?php } ?>
|
||||
</h2>
|
||||
<ul class="subtext">
|
||||
<li>Tid:
|
||||
<strong>
|
||||
<?php echo Agenda::getFormattedDate($nextEvent->getStart()); ?>
|
||||
</strong>
|
||||
<li>Sted:
|
||||
<strong>
|
||||
<?php echo $nextEvent->getLocation(); ?>
|
||||
</strong>
|
||||
<li>Arrangør:
|
||||
<strong>
|
||||
<?php echo $nextEvent->getOrganiser(); ?>
|
||||
</strong>
|
||||
</ul>
|
||||
|
||||
<?php
|
||||
$Parsedown = new Parsedown();
|
||||
echo $Parsedown->text(implode("\n", $nextEvent->getDescription()));
|
||||
?>
|
||||
</article>
|
||||
|
||||
</main>
|
||||
|
||||
<nav>
|
||||
<?php echo navbar(1, 'aktiviteter'); ?>
|
||||
<?php echo loginbar($sp, $pdo); ?>
|
||||
</nav>
|
||||
@@ -0,0 +1,107 @@
|
||||
.tools {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.tools li {
|
||||
margin: 1.5em 0;
|
||||
}
|
||||
|
||||
.event-list {
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.event {
|
||||
display: grid;
|
||||
grid-template-columns: auto 5em;
|
||||
|
||||
margin-bottom: 2em;
|
||||
padding-bottom: .5em;
|
||||
border-bottom: 1px dotted rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
.event-info {
|
||||
grid-column: 1;
|
||||
overflow-x: hidden; /*force text wrap*/
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.event-info h3 {
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.event-info p {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.event-info a {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.event-info a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.event-actions {
|
||||
grid-column: 2;
|
||||
text-align: right;
|
||||
}
|
||||
.event-actions .btn {
|
||||
margin: 0.3em 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.fullwidth_inputs input,
|
||||
.fullwidth_inputs textarea {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.allgrids {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.float-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.float-left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.userlist {
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.userlist tr th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.userlist tr {
|
||||
border-bottom: 1px solid gray;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.usergroupcheckbox {
|
||||
margin-right: .3em;
|
||||
}
|
||||
|
||||
.newuserrow {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.newuserelement {
|
||||
background-color: #ddd;
|
||||
border-bottom: 2px dotted gray;
|
||||
}
|
||||
|
||||
.newuserelement input {
|
||||
border: none;
|
||||
background-color: #ddd;
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
.pagination_bar {
|
||||
display: grid;
|
||||
grid-template-columns: 8em auto 8em;
|
||||
grid-template-areas: "left . right";
|
||||
text-align: center;
|
||||
}
|
||||
.pagination_bar >*:nth-child(1) {
|
||||
grid-area: left;
|
||||
}
|
||||
.pagination_bar >*:nth-child(2) {
|
||||
grid-area: right;
|
||||
}
|
||||
|
||||
figure.calendar {
|
||||
margin: 0;
|
||||
padding:0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.calendar ul {
|
||||
min-width: 43em;
|
||||
list-style-type: none;
|
||||
padding-left:0;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 4fr);
|
||||
grid-template-rows: auto;
|
||||
}
|
||||
|
||||
.calendar ul a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
.calendar ul a div {
|
||||
min-height: 4.8em;
|
||||
}
|
||||
|
||||
|
||||
.calendar ul li {
|
||||
margin: 2px;
|
||||
|
||||
border-style: solid;
|
||||
border-color: #e0e0e0;
|
||||
border-width: 1px;
|
||||
border-radius: 5px;
|
||||
|
||||
background-color: #f3f3f3;
|
||||
padding: 0.2em 0.5em;
|
||||
padding-bottom: 0.5em;
|
||||
min-height: 4.8em;
|
||||
font-size: 0.8em;
|
||||
color: #444;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.calendar ul li.header {
|
||||
text-align: center;
|
||||
min-height: 1em;
|
||||
|
||||
background-color: #fff;
|
||||
border: None;
|
||||
border-radius: 0;
|
||||
margin: 0px;
|
||||
padding: 0.2em 0;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
color: #666;
|
||||
}
|
||||
.calendar ul li.outOfMonth {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.calendar ul li.active {
|
||||
color: #222;
|
||||
border-color: #679;
|
||||
box-shadow: 0 0 3px #89f;
|
||||
}
|
||||
|
||||
.calendar ul li:hover {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.calendar ul li .day{
|
||||
display: inline-block;
|
||||
width: 1.75em;
|
||||
height: 1.75em;
|
||||
text-align: center;
|
||||
line-height: 1.75em;
|
||||
background: #9ab;
|
||||
color: white;
|
||||
border-radius: 0.875em;
|
||||
margin-bottom: 0.1em;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.calendar ul li.active .day{
|
||||
background: #248;
|
||||
}
|
||||
|
||||
.calendar ul li section {
|
||||
line-height: 1.5em;
|
||||
background: #038;
|
||||
color: white;
|
||||
border-radius: 0.75em;
|
||||
text-align: center;
|
||||
padding: 0 0.2em;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.calendar ul li section + section {
|
||||
margin-top: 0.1em;
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
h2 a, h4 a {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
h2 a:hover, h4 a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
h2 em {
|
||||
display: inline-block;
|
||||
color: gray;
|
||||
font-size: .5em;
|
||||
line-height: 2em;
|
||||
float: left;
|
||||
border: .1em solid gray;
|
||||
padding: 0 1em;
|
||||
border-radius: .25em;
|
||||
font-style: normal;
|
||||
}
|
||||
h2 strong em {
|
||||
background: #084;
|
||||
border-color: #084;
|
||||
color: white;
|
||||
}
|
||||
h2 img {
|
||||
float: right;
|
||||
max-width: 10em;
|
||||
border: .1em solid white;
|
||||
border-radius: 0.1em;
|
||||
box-shadow: 0 2px 2px gray;
|
||||
margin-left: 1em;
|
||||
clear: right;
|
||||
margin-bottom: 0.8em;
|
||||
clear: left;
|
||||
}
|
||||
h4 {
|
||||
margin-top: 0;
|
||||
margin-bottom: -0.6em;
|
||||
}
|
||||
|
||||
|
||||
h2 + .subtext {
|
||||
margin: -1.5em 0 1em 0;
|
||||
}
|
||||
p + .subtext {
|
||||
margin: -0.5em 0 1em 0;
|
||||
}
|
||||
.subtext {
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
clear: left;
|
||||
}
|
||||
.subtext li {
|
||||
display: inline;
|
||||
margin-right: 3em;
|
||||
font-size: .7em;
|
||||
color: gray;
|
||||
}
|
||||
.subtext li a, .subtext li strong {
|
||||
color: black;
|
||||
font-size: 1.2em;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.events:before {
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
display: block;
|
||||
content: " ";
|
||||
background-image: -webkit-linear-gradient(left, transparent, rgba(0,0,0,.1), transparent);
|
||||
background-image: -moz-linear-gradient(left, transparent, rgba(0,0,0,.1), transparent);
|
||||
background-image: -o-linear-gradient(left, transparent, rgba(0,0,0,.1), transparent);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
.events {
|
||||
margin-top: -1.5em;
|
||||
margin-left: 0.3em;
|
||||
margin-bottom: 2em;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
.events >li {
|
||||
padding-left: 0.5em;
|
||||
border-left: 4px solid #35a;
|
||||
margin-top: 0.9em;
|
||||
}
|
||||
|
||||
.events li p {
|
||||
text-align: left;
|
||||
line-height: 1.5em;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.events .subtext {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.events li h4 +.subtext {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 50rem) {
|
||||
article:first-child h2 img {
|
||||
max-width: 12em;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 50rem) {
|
||||
h2 {
|
||||
position: relative;
|
||||
border-bottom-left-radius: 0.3em;
|
||||
border-bottom-right-radius: 0.3em;
|
||||
max-height: 30vh;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
h2 em {
|
||||
display: block;
|
||||
top:0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
|
||||
}
|
||||
h2 img {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
border-radius: 0.3em;
|
||||
float: none;
|
||||
margin: 0;
|
||||
max-width: none;
|
||||
width: 100%;
|
||||
}
|
||||
article >.subtext {
|
||||
margin-top: -1em !important;
|
||||
}
|
||||
|
||||
.subtext li {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||