140 Commits

Author SHA1 Message Date
aa8adfc6a4 Merge pull request 'make y-margin for .serviceGrid fixed' (#117) from tjenester_consistency into main
Reviewed-on: #117
Reviewed-by: Oystein Kristoffer Tveit <oysteikt@pvv.ntnu.no>
2026-01-21 16:36:46 +01:00
aa1bdd6996 make y-margin for .serviceGrid fixed 2026-01-21 15:24:58 +01:00
3a8f82b12a www/tjenester: add user databases 2026-01-17 16:53:20 +09:00
6c9284b8f6 www/tjenester: add mapcrafter 2026-01-17 16:48:09 +09:00
2a20a1b4eb www/tjenester: rename recreational category to 'other', add vaultwarden 2026-01-17 16:44:32 +09:00
f3c13b1aee door: fix navbar (again) 2026-01-13 20:09:25 +09:00
c997ad4b47 composer.lock: bump 2026-01-13 19:59:14 +09:00
d5d8937365 .well-known: remove 2026-01-13 19:49:41 +09:00
ceb9b51756 .mailmap: init 2026-01-13 19:49:11 +09:00
f163ed3a2f www/door: fix navbar position 2026-01-13 19:29:58 +09:00
bdea5cf182 www/door: remove gray color, add blue boxes 2026-01-13 19:24:10 +09:00
280833253c www/door: add navbar 2026-01-13 19:09:10 +09:00
cefd8640b5 www/door: clean up graph options 2026-01-13 18:58:25 +09:00
5a25087d32 scripts/seed-test-data: fill some door data 2026-01-13 18:58:06 +09:00
bde2e88273 www/css: remove leftover css and imagery from webmail page 2026-01-13 17:31:52 +09:00
597aaf413a tjenester: add physical services, replace github icon 2026-01-13 17:23:49 +09:00
a5e3ac6308 tjenester: less yabai colors 2026-01-13 17:00:57 +09:00
83ce4792e2 tjenester: comment out miniflux 2026-01-13 16:55:43 +09:00
9c645fdb0e tjenester: add icon for gopher, find better svgs for discord and element 2026-01-13 16:49:55 +09:00
7f706ccd2a tjenester: grid and shid 2026-01-13 16:49:55 +09:00
2e7acb7a9a Wrap door status entries in dataclass 2026-01-13 13:39:12 +09:00
9e2fab0ea2 Wrap motd entries in dataclass 2026-01-13 13:28:10 +09:00
189324b87e www/tjenester: replace some pngs with svgs, remove unused images 2026-01-13 12:59:28 +09:00
9f81ae0b8a navbar: don't display webmail 2026-01-13 12:39:30 +09:00
167dd77107 www/tjenester/index: add and remove some sections 2026-01-13 12:37:37 +09:00
cc8adf3f84 www/tjenester/index: pull content out of html 2026-01-13 12:17:56 +09:00
73aee17ae3 www/admin: format a few queries 2026-01-13 11:58:46 +09:00
2f0e4b2d83 www/admin/index: use php if blocks and literal html 2026-01-13 11:54:50 +09:00
b67cbd6503 door: unvendor javascript blobs 2026-01-13 11:46:19 +09:00
32ba9c11f7 door: don't require default row in database 2026-01-13 11:35:34 +09:00
b9992c7c57 dist/sql: format test data script 2026-01-13 11:22:51 +09:00
346cb433ac dist/sql: add yet more constraints 2026-01-13 11:22:03 +09:00
5279c588d5 pvv/side: format long queries 2026-01-13 11:15:37 +09:00
e84236c84b dist/sql: add more constraints 2026-01-13 11:04:25 +09:00
8f4dfc992e dist/sql: move test data to test_data_sqlite.sql 2026-01-13 09:34:30 +09:00
1766cc23d6 door: return datetime objects for core functions 2026-01-13 09:27:28 +09:00
044444eaa8 door: fix data extraction 2026-01-13 08:34:59 +09:00
16c9b610ce door: fix data insertion 2026-01-12 21:47:46 +09:00
65118b6abe flake.lock: bump 2026-01-09 06:12:05 +09:00
75226f8314 flake.nix: system -> stdenv.hostPlatform.system 2026-01-09 06:11:43 +09:00
1a4676d85d docs/getting-started: fix warning block 2026-01-07 22:50:43 +09:00
08a216f447 flake.lock: bump 2025-12-30 16:36:28 +09:00
31b7026867 Fix nix package 2025-12-30 16:36:23 +09:00
961f021d27 docs: add directory, write getting started guide 2025-12-17 22:35:48 +09:00
158e816ed0 Add the dev auth users to the database 2025-12-17 22:11:06 +09:00
42cb584ef4 Fix user metadata for dev authsource 2025-12-17 22:11:06 +09:00
1eabf809f0 Use bool values in database 2025-12-17 22:11:06 +09:00
bb5b013d31 Remove docker stuff 2025-12-17 21:17:24 +09:00
a366769fb9 Add scripts for setting up and resetting the project 2025-12-17 21:17:24 +09:00
19c49b4a00 Host both service provider and identity provider for local dev 2025-12-17 19:58:06 +09:00
3d07547f80 src/pvv/side/agenda: fix type 2025-12-17 05:58:16 +09:00
fc8ca571fb Remove reference to previously used gitmodule 2025-12-17 05:11:48 +09:00
6fd4a0599c dist/simplesamlphp-config: renew to 2.5 2025-12-17 04:50:44 +09:00
f782d20e56 Run php-cs-fixer on src 2025-12-17 04:25:47 +09:00
0a77f46fe1 flake.lock: bump, composer.lock: bump 2025-12-17 04:01:26 +09:00
ed720af80b Add hosting instructions 2025-12-17 03:49:17 +09:00
f8acc4b815 Mark data classes and functions with types 2025-12-17 03:44:44 +09:00
da1113341a Merge pull request 'simplify mobile view' (#92) from mobile_view into main
Reviewed-on: #92
2025-09-08 13:58:02 +02:00
cd31bd4476 simplify mobile view 2025-09-08 13:25:54 +02:00
77e5d336eb Merge pull request 'remove unused border and fix navbar width' (#91) from navbar into main
Reviewed-on: #91
2025-09-08 11:46:19 +02:00
403afdc472 remove unused border and fix navbar width 2025-09-08 11:35:41 +02:00
86816489e3 Merge pull request 'fix /tjenester mobile view' (#90) from mobile_view into main
Reviewed-on: #90
Reviewed-by: Oystein Kristoffer Tveit <oysteikt@pvv.ntnu.no>
2025-09-03 23:08:21 +02:00
c38c502598 Start recurring events, and remove fadderuke 2025-poster 2025-09-01 20:15:44 +02:00
3d843667ad update /tjenester for mobile devices 2025-08-31 01:13:26 +02:00
617a799ad8 Merge pull request 'remove duplicated Kalender button at /hendelser' (#89) from vegardbm/nettsiden:main into main
Reviewed-on: #89
2025-08-18 02:03:29 +02:00
0be8e51af4 remove duplicated Kalender button at /hendelser 2025-08-18 01:59:37 +02:00
381f67189a Merge pull request 'fix missing port for buttercup' (#88) from vegardbm/nettsiden:main into main
Reviewed-on: #88
2025-08-17 20:57:52 +02:00
2e56c7aed4 fix missing port for buttercup 2025-08-17 20:54:21 +02:00
5b7a04dc69 Merge pull request 'update dead links for VM hosts at /tjenester' (#87) from vegardbm/nettsiden:main into main
Reviewed-on: #87
2025-08-17 20:45:06 +02:00
485110bf43 update dead links for VM hosts at /tjenester 2025-08-17 20:43:05 +02:00
3498cb7d8e Merge pull request 'fix minecraft map link at /tjenester' (#86) from vegardbm/nettsiden:main into main
Reviewed-on: #86
2025-08-17 00:13:58 +02:00
ed3f307b9b fix minecraft map link at /tjenester 2025-08-17 00:04:51 +02:00
7070a12e16 Merge pull request 'render /hendelser tid, sted, arrangør nicely on mobile' (#85) from vegardbm/nettsiden:main into main
Reviewed-on: #85
Reviewed-by: Oystein Kristoffer Tveit <oysteikt@pvv.ntnu.no>
2025-08-14 22:47:21 +02:00
6bda1a91bd render /hendelser tid, sted, arrangør nicely on mobile 2025-08-14 22:46:06 +02:00
559b7ec03b Merge pull request 'fix mobile experience for /aktiviteter' (#84) from vegardbm/nettsiden:main into main
Reviewed-on: #84
Reviewed-by: Oystein Kristoffer Tveit <oysteikt@pvv.ntnu.no>
2025-08-14 22:20:24 +02:00
602ae1f396 fix mobile experience for /aktiviteter 2025-08-14 22:17:25 +02:00
f3c439d038 fix README 2025-08-14 21:20:05 +02:00
2b3a9dd6ec update README to reflect changes in dev environment 2025-08-14 21:09:33 +02:00
59b071d8be Fix oopsie, gitignore cache 2025-08-14 19:00:44 +02:00
f732582d0d Merge pull request 'Høst 2025; Legg til fadderuke, pause events' (#83) from fall-2025 into main
Reviewed-on: #83
Reviewed-by: Peder Bergebakken Sundt <pederbs@pvv.ntnu.no>
2025-07-18 21:05:40 +02:00
de72342018 activities: disable recurring events for the summer 2025-07-17 23:39:56 +02:00
b54bbda71f index.php: add fadderuke 2025 poster 2025-07-17 23:35:07 +02:00
20bab54235 dist/simplesamlphp-authsources: set entityID for service provider 2025-03-19 01:34:39 +01:00
c3d8ce017d shell.nix: find rootlevel in shell hook 2025-03-18 21:25:41 +01:00
02cfe9feaa pvv_mysql.sql: format 2025-03-18 21:18:24 +01:00
4d4ec78ea3 pvv_sqlite.sql: format 2025-03-18 21:17:36 +01:00
a74ea31356 .envrc: init 2025-03-18 21:15:59 +01:00
0653672a17 shell.nix: add sql formatter 2025-03-18 21:15:59 +01:00
8a1ff1a265 dist/pvv.sql -> dist/pvv_sqlite.sql 2025-03-18 21:10:48 +01:00
c1802e7cf2 treewide: strict comparisons 2025-03-12 01:09:08 +01:00
84de16fc25 shell.nix: fix simplesamlphp symlink 2025-03-12 00:43:22 +01:00
23b8e91a6c git blame ignore the formattening 2025-03-12 00:43:21 +01:00
da8afe735c The formattening, part 2 2025-03-12 00:42:34 +01:00
b6697e5750 The formattening, part 1 2025-03-12 00:20:04 +01:00
ece3c8ab80 .php-cs-fixer: init 2025-03-12 00:19:41 +01:00
7297c83cea shell.nix: add some more tools 2025-03-11 22:28:54 +01:00
74662af3ef flake.lock: bump 2025-03-11 22:28:15 +01:00
32e147fd02 nix: php82 -> php84 2025-03-11 22:28:05 +01:00
d5c28d4e0f package.nix bump vendorHash 2025-03-11 21:23:32 +01:00
f1b3c63311 composer: bump deps 2025-03-11 20:37:24 +01:00
a4ebe6ded0 Vårsemester; Nå med events!
Revert "Reapply "Calendar: Remove recurring events for summer break 2024""

This reverts commit 2930f9863f.
2025-01-17 23:09:18 +01:00
2930f9863f Reapply "Calendar: Remove recurring events for summer break 2024"
Christmas break 2024

This reverts commit e7b66b4bc6.
2024-12-21 23:32:29 +01:00
e7b66b4bc6 Revert "Calendar: Remove recurring events for summer break 2024"
This reverts commit ce99b309f8.
2024-09-01 19:45:59 +02:00
c62f4d4705 www/tjenester: update wiki link for hjemmesider 2024-08-21 10:46:43 +02:00
814e5bc6c7 www/tjenester: move nettsiden from github to gitea 2024-08-21 10:46:43 +02:00
f57edf60c1 flake.nix: remove abundant todos
One had already been fixed, the other one has been converted to a proper
issue on gitea
2024-08-21 07:37:08 +02:00
a29d3fe803 Err, try again 2024-08-17 23:59:17 +02:00
8bcadd1d2d Merge pull request 'Replace deprecated functions to support php 8.3' (#68) from php83-fixes-fr-fr into master
Reviewed-on: #68
Reviewed-by: Oystein Kristoffer Tveit <oysteikt@pvv.ntnu.no>
2024-08-17 20:45:08 +02:00
8a82e2795c Various: Replace deprecated functions to support php 8.3 2024-08-17 18:31:43 +02:00
4ee8b73044 nix/shell: create slideshow dir 2024-08-17 01:35:14 +02:00
6580cfe546 Merge pull request 'treewide: flip arg order for implode()' (#63) from i-am-imploding into master
Reviewed-on: #63
Reviewed-by: Felix Albrigtsen <felixalb@pvv.ntnu.no>
2024-08-04 00:08:52 +02:00
a0f9e71d46 treewide: flip arg order for implode() 2024-08-04 00:01:34 +02:00
6e4a79ed3d Merge pull request 'Calendar: Remove recurring events for summer break 2024' (#61) from calendar-disable-events into master
Reviewed-on: #61
2024-06-15 00:36:32 +02:00
ce99b309f8 Calendar: Remove recurring events for summer break 2024 2024-06-11 17:09:35 +02:00
37445f42b5 Merge pull request 'Oppdater Matrix-server til Matrix Space™' (#50) from info-updates into master
Reviewed-on: #50
2024-05-30 21:19:42 +02:00
9717c11af5 Fix discord-server og matrix space 2024-05-30 21:19:29 +02:00
2cab4df4b1 Merge pull request 'fix: updated spaceapi coords' (#60) from adriangl-patch-spaceapi-coords into master
Reviewed-on: #60
2024-05-19 22:25:52 +02:00
18c8426246 fix: updated spaceapi coords 2024-05-19 22:09:37 +02:00
4890a0af04 nix/module: fix spaceapi endpoint 2024-05-19 20:06:22 +02:00
7bf2c31db3 feat: adds spaceapi endpoint (#57)
A basic implementation of the https://spaceapi.io/ specification.
Tested working door sensor status. Added basic info about us, our website, git forge and wiki.

Co-authored with @sindos and @oysteikt.

Reviewed-on: #57
Co-authored-by: Felix Albrigtsen <felix@albrigtsen.it>
Co-committed-by: Felix Albrigtsen <felix@albrigtsen.it>
2024-05-18 20:05:13 +02:00
13a6df92ce Merge pull request 'Gitea istedenfor gogs på tjenester-siden' (#56) from gitea-i-tjenester into master
Reviewed-on: #56
2024-05-11 22:55:36 +02:00
f87c6820d7 services: move gitea above github and remove trac 2024-05-07 21:31:42 +02:00
592c6d46c4 services: replaced gogs with gitea 2024-05-07 21:31:20 +02:00
9d9d99e6ba gallery: sort by timestamp. slideshow: fix transition bug on firefox 2024-04-14 01:59:12 +02:00
216e153f89 nix/module: correct some nginx locations directives 2024-04-11 13:19:59 +02:00
d528df5f99 Merge pull request 'Fix links after moving from spikkje to bekka' (#55) from www2-www-fixes into master
Reviewed-on: #55
2024-04-11 00:43:32 +02:00
faf93cc45a Fix links after moving from spikkje to bekka 2024-04-11 00:42:12 +02:00
1aa4f4fc8a Merge pull request 'Mega PR: Update deps, consolidate config, build with nix, gallery fixes, etc.' (#53) from nixify-ng into master
Reviewed-on: #53
2024-04-10 21:45:10 +02:00
f1958d9afc galleri: Support .thumbnails 2024-04-10 21:44:58 +02:00
7f269f05d6 gallery: Fix usernames/paths in the gallery 2024-04-10 21:44:58 +02:00
7e158c9fc3 Update dependencies 2024-04-10 21:44:58 +02:00
d79cd3ad37 dist/pvv.sql: fix failing parts 2024-04-10 21:44:58 +02:00
f5a6868301 Build new nix {module,package,flake}. Adapt to new config variables
Co-authored-by: h7x4 <h7x4@nani.wtf>
2024-04-10 21:44:58 +02:00
310246dd20 Update global config variables 2024-04-10 21:44:58 +02:00
151a0d44f6 move gallery/slideshow directories 2024-04-10 21:44:58 +02:00
10c70e89f6 Remove 'ticker', deprecated since 1da1785e46 2024-04-10 21:44:58 +02:00
318e9cfe6b Update dependencies, fix broken flake 2024-04-10 21:44:58 +02:00
1f60b80b98 move sql_config.php to config.php 2024-04-10 21:44:58 +02:00
517f39eee9 Update SimpleSamlPHP 2024-04-10 21:44:58 +02:00
2f6553225a remove deprecated options and dependencies for dataporten/oauth 2024-04-10 21:44:58 +02:00
157 changed files with 9898 additions and 11096 deletions

1
.envrc Normal file
View File

@@ -0,0 +1 @@
use flake

3
.git-blame-ignore-revs Normal file
View File

@@ -0,0 +1,3 @@
# The formattening
c5d308654744e116090e9ba165a968b8bf66006c
da8afe735c62e1f8ee9ad5f71291d87102fe126b

5
.gitignore vendored
View File

@@ -1,6 +1,7 @@
/sql_config.php
/dataporten_config.php
*.sqlite *.sqlite
/cache
/config.php
/result
/test.sql /test.sql
/vendor/ /vendor/
/www/simplesaml /www/simplesaml

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "lib/OAuth2-Client"]
path = lib/OAuth2-Client
url = https://github.com/UNINETT/OAuth2-Client.git

26
.mailmap Normal file
View File

@@ -0,0 +1,26 @@
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>
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>

58
.php-cs-fixer.php Normal file
View File

@@ -0,0 +1,58 @@
<?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([
'@PhpCsFixer' => true,
'@Symfony' => true,
'@PER-CS' => true,
'@PHP71Migration' => true,
'@PHP73Migration' => true,
'@PHP74Migration' => true,
'@PHP80Migration' => true,
'@PHP81Migration' => true,
'@PHP82Migration' => true,
'@PHP83Migration' => true,
'@PHP84Migration' => true,
'@PhpCsFixer:risky' => true,
'@Symfony:risky' => true,
'@PER-CS:risky' => true,
'@PHP74Migration:risky' => true,
'@PHP80Migration:risky' => true,
'@PHP82Migration: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")
;

View File

@@ -1,7 +0,0 @@
# this is a development container, not hardened for hosting
FROM php:7.4-cli
RUN apt-get update && \
apt-get install -y \
sqlite3 \
unzip \
git

View File

@@ -1,79 +1,11 @@
# Programvareverkstedets nettside # Programvareverkstedets nettside
A website created with the latest and greatest web technologies. A website created with the latest and greatest web technologies.
May contain blackjack and other things one tends to include in awesome projects. May contain blackjack and other things one tends to include in awesome projects.
## Installation See [Getting Started](./docs/getting-started.md) for help to hack on the project.
git clone --recursive https://github.com/Programvareverkstedet/nettsiden.git
Put it in a folder your webserver can find.
## Development setup
Make sure you have `sqlite3`, `php` and `pdo-sqlite` installed.
These can be obtained from your package manager.
Then make sure PHP has the `curl`, `pdo-sqlite`, `ext-dom` and `sqlite3` extensions enabled, see `/etc/php/php.ini`.
To install all mentioned requirements on debian: `apt install composer sqlite3 php8.1-sqlite3 simplesamlphp php-xml`, followed by `composer update`.
./dev.sh
On Windows you can use chocolatey and git bash to run `./dev.sh`.
Install `php` and `sqlite`, then enable these extensions in `C:\tools\php80\php.ini`:
`mbstring`, `openssl`, `curl`, `pdo-sqlite` and `sqlite3`
Alternatively you may use `cmd` on Windows.
In this case you'll have to perform a `composer install` manually beforehand.
Good luck.
dev.bat
### Dependency management
`dev.sh` will ensure the git submodules have been properly pulled, then download the `composer` package manager to a php archive file named `composer.phar`, then run it.
Composer will then check for the php extensions needed, such as `pdo_sqlite`, which must be enabled on your system.
This usually includes installing a php-sqlite3 package and enabling it in `/etc/php/php.ini`:
[PHP]
extension=pdo_sqlite
extension=sqlite3
extension=ext-curl
Composer is used as such:
php composer.phar update
php composer.phar install
### Docker
We provide a simple docker-compose setup for local development.
First ensure that docker is running:
sudo systemctl start docker
then
DOCKER_USER=$(id -u):$(id -g) docker-compose up
### Admin account
Login goes through `idp.pvv.ntnu.no` via SAML, so you have to use your PVV account.
(This only works if you use access the local development site via the the hostname `localhost`)
To make your account into an admin account, run:
sqlite3 pvv.sqlite 'INSERT INTO users (uname, groups) VALUES ("YOUR_USERNAME", 1);'
If using docker, when already running:
DOCKER_USER=$(id -u):$(id -g) docker-compose exec nettside sqlite3 pvv.sqlite 'INSERT INTO users (uname, groups) VALUES ("YOUR_USERNAME", 1);'
If not already running:
DOCKER_USER=$(id -u):$(id -g) docker-compose run nettside sqlite3 pvv.sqlite 'INSERT INTO users (uname, groups) VALUES ("YOUR_USERNAME", 1);'
## Hosting ## Hosting
![](./docs/hosting.jpg)

View File

@@ -1,14 +1,16 @@
{ {
"require": { "name": "programvareverkstedet/nettsiden",
"simplesamlphp/simplesamlphp": "~1", "description": "Programvareverkstedets nettside",
"erusev/parsedown": "^1.7" "license": "proprietary",
},
"require-dev": { "config": {
"ext-pdo_sqlite": "*" "allow-plugins": {
}, "simplesamlphp/composer-module-installer": true,
"config": { "simplesamlphp/composer-xmlprovider-installer": true
"allow-plugins": { }
"simplesamlphp/composer-module-installer": true },
} "require": {
} "simplesamlphp/simplesamlphp": "^2.2.1",
"erusev/parsedown": "^1.7.4"
}
} }

4896
composer.lock generated

File diff suppressed because it is too large Load Diff

11
dev.bat
View File

@@ -1,11 +0,0 @@
REM php og sqlite3 må være tilgjengelig i PATH
IF EXIST "sql_config.php" goto config_end
cp sql_config_example.php sql_config.php
:config_end
IF EXIST "pvv.sqlite" goto sqlite_end
sqlite3 pvv.sqlite < pvv.sql
:sqlite_end
php -S [::1]:1080 -t www/ -c php.ini

25
dev.sh
View File

@@ -1,25 +0,0 @@
#!/bin/sh
which sqlite3 > /dev/null 2>&1 || (echo ERROR: sqlite not found; false) || exit 1
test ! -e pvv.sqlite && sqlite3 pvv.sqlite < dist/pvv.sql
test ! -e sql_config.php && cp -v dist/sql_config_example.php sql_config.php
test ! -e dataporten_config.php && cp -v dist/dataporten_config.php dataporten_config.php
test -e composer.phar || curl -O https://getcomposer.org/composer.phar
if test ! -f lib/OAuth2-Client/OAuth2Client.php ; then
echo Missing git submodules. Installing...
(set -x; git submodule update --init --recursive) || exit $?
fi
if test ! -d vendor; then
php composer.phar install || exit $?
cp -v dist/authsources_example.php vendor/simplesamlphp/simplesamlphp/config/authsources.php
cp -v dist/saml20-idp-remote.php vendor/simplesamlphp/simplesamlphp/metadata/saml20-idp-remote.php
cp -v vendor/simplesamlphp/simplesamlphp/config-templates/config.php vendor/simplesamlphp/simplesamlphp/config/config.php
sed -e "s/'trusted.url.domains' => array()/'trusted.url.domains' => array('localhost:1080')/g" < vendor/simplesamlphp/simplesamlphp/config-templates/config.php > vendor/simplesamlphp/simplesamlphp/config/config.php
ln -s ../vendor/simplesamlphp/simplesamlphp/www/ www/simplesaml
fi
php -S ${DOCKER_HOST:-[::1]}:${DOCKER_PORT:-1080} -d error_reporting=E_ALL -d display_errors=1 -t www/

View File

@@ -1,9 +0,0 @@
<?php
$config = array(
/* This is the name of this authentication source, and will be used to access it later. */
'default-sp' => array(
'saml:SP',
'idp' => 'https://idp.pvv.ntnu.no/',
),
);

24
dist/config.local.php vendored Normal file
View File

@@ -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';

6
dist/config.source-env.php vendored Normal file
View File

@@ -0,0 +1,6 @@
<?php
declare(strict_types=1);
$configFile = getenv('PVV_CONFIG_FILE');
require_once $configFile;

View File

@@ -1,21 +0,0 @@
<?php
# go to https://auth.dataporten.no/
$dataportenConfig = [
'client_id' => "",
'client_secret' => "",
//'redirect_uri' => "https://pvv.ntnu.no/paamelding/",
'redirect_uri' => "http://localhost:1080/paamelding/",
'auth' => "https://auth.dataporten.no/oauth/authorization",#Authorization endpoint
'token' => "https://auth.dataporten.no/oauth/token",#Token endpoint
/* OPTIONAL */
# 'authorization_type' => "Bearer",
# 'session' => false,
# 'verify' => 1,
# 'grant_type' => "authorization_code",
# 'response_type' => "code",
# 'scope' => "",
];

50
dist/pvv.sql vendored
View File

@@ -1,50 +0,0 @@
CREATE TABLE "events" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"name" TEXT,
"start" TEXT,
"stop" TEXT,
"organiser" TEXT,
"location" TEXT,
"description" TEXT
);
CREATE TABLE "projects" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"name" TEXT,
"description" TEXT,
"active" BOOLEAN
);
CREATE TABLE "projectmembers" (
"projectid" INTEGER,
"name" TEXT,
"uname" TEXT,
"mail" TEXT,
"role" TEXT,
"lead" BOOLEAN DEFAULT 0,
"owner" BOOLEAN DEFAULT 0
);
CREATE TABLE "users" (
"uname" TEXT,
"groups" INT DEFAULT 0
);
CREATE TABLE "motd" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"title" TEXT,
"content" TEXT
);
INSERT INTO motd (title, content)
VALUES ("MOTD ./dev.sh", "du kan endre motd i admin panelet");
CREATE TABLE "door" (
"time" INTEGER PRIMARY KEY,
"open" BOOLEAN
);
INSERT INTO door (time, open)
VALUES (0, FALSE);
INSERT INTO users (uname, groups)
VALUES ("min_test_bruker", 1);

47
dist/pvv_mysql.sql vendored
View File

@@ -1,47 +0,0 @@
CREATE TABLE events (
`id` INTEGER PRIMARY KEY AUTO_INCREMENT,
`name` TEXT,
`start` TEXT,
`stop` TEXT,
`organiser` TEXT,
`location` TEXT,
`description` TEXT
);
CREATE TABLE projects (
`id` INTEGER PRIMARY KEY AUTO_INCREMENT,
`name` TEXT,
`description` TEXT,
`active` BOOLEAN
);
CREATE TABLE projectmembers (
`projectid` INTEGER,
`name` TEXT,
`uname` TEXT,
`mail` TEXT,
`role` TEXT,
`lead` BOOLEAN DEFAULT 0,
`owner` BOOLEAN DEFAULT 0
);
CREATE TABLE users (
`uname` TEXT,
`groups` INT DEFAULT 0
);
CREATE TABLE motd (
`id` INTEGER PRIMARY KEY AUTO_INCREMENT,
`title` TEXT,
`content` TEXT
);
/*
INSERT INTO motd (title, content)
VALUES ("MOTD ./dev.sh", "du kan endre motd i admin panelet");
*/
CREATE TABLE door (
`time` INTEGER PRIMARY KEY,
`open` BOOLEAN
);
INSERT INTO door(time, open) VALUES (0, FALSE);

36
dist/simplesaml-dev/authsources.php vendored Normal file
View File

@@ -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',
],
];

1416
dist/simplesaml-dev/config.php vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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',
];

View File

@@ -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',
];

View File

@@ -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',
],
],
];

12
dist/simplesaml-prod/authsources.php vendored Normal file
View File

@@ -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/',
],
];

1408
dist/simplesaml-prod/config.php vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,23 +1,21 @@
<?php <?php
$metadata['https://idp.pvv.ntnu.no/'] = array (
declare(strict_types=1);
$metadata['https://idp.pvv.ntnu.no/'] = [
'metadata-set' => 'saml20-idp-remote', 'metadata-set' => 'saml20-idp-remote',
'entityid' => 'https://idp.pvv.ntnu.no/', 'entityid' => 'https://idp.pvv.ntnu.no/',
'SingleSignOnService' => 'SingleSignOnService' => [
array ( 0 => [
0 =>
array (
'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', 'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
'Location' => 'https://idp.pvv.ntnu.no/simplesaml/saml2/idp/SSOService.php', 'Location' => 'https://idp.pvv.ntnu.no/simplesaml/saml2/idp/SSOService.php',
), ],
), ],
'SingleLogoutService' => 'SingleLogoutService' => [
array ( 0 => [
0 =>
array (
'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', 'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
'Location' => 'https://idp.pvv.ntnu.no/simplesaml/saml2/idp/SingleLogoutService.php', '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==', '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', 'NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient',
); ];

44
dist/sql/pvv_mysql.sql vendored Normal file
View File

@@ -0,0 +1,44 @@
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 projects (
`id` INTEGER PRIMARY KEY AUTO_INCREMENT,
`name` TEXT NOT NULL,
`description` TEXT,
`active` BOOLEAN DEFAULT TRUE
);
CREATE TABLE projectmembers (
`id` INTEGER PRIMARY KEY AUTO_INCREMENT,
`projectid` INTEGER FOREIGN KEY REFERENCES projects(`id`),
`name` TEXT NOT NULL,
`uname` TEXT NOT NULL REFERENCES users(`uname`),
`mail` TEXT,
`role` TEXT,
`lead` BOOLEAN NOT NULL DEFAULT FALSE,
`owner` BOOLEAN NOT NULL DEFAULT FALSE
);
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
);

44
dist/sql/pvv_sqlite.sql vendored Normal file
View File

@@ -0,0 +1,44 @@
CREATE TABLE "events" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL,
"start" TEXT,
"stop" TEXT,
"organiser" TEXT,
"location" TEXT,
"description" TEXT
);
CREATE TABLE "projects" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL,
"description" TEXT,
"active" BOOLEAN DEFAULT TRUE
);
CREATE TABLE "projectmembers" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"projectid" INTEGER REFERENCES projects(id),
"name" TEXT NOT NULL,
"uname" TEXT NOT NULL REFERENCES users(uname),
"mail" TEXT,
"role" TEXT,
"lead" BOOLEAN NOT NULL DEFAULT FALSE,
"owner" BOOLEAN NOT NULL DEFAULT FALSE
);
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
);

15
dist/sql/test_data_sqlite.sql vendored Normal file
View File

@@ -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'
);

View File

@@ -1,6 +0,0 @@
<?php
$dbDsn = 'sqlite:'.__DIR__.DIRECTORY_SEPARATOR.'pvv.sqlite';
$dbUser = null;
$dbPass = null;
$doorSensorSecret = "OGJiZTdjZDctMmFkNy00ZjZjLTk3OGItOTA3NzU3ZDM2Yjlm";

View File

@@ -1,21 +0,0 @@
version: "3.9"
# cleanup:
# docker container prune -f && docker volume prune -f
# docker system prune -a
services:
nettside: # https://hub.docker.com/_/php
#image: php:7.4-cli
build: .
volumes:
- .:/usr/src/nettside
working_dir: /usr/src/nettside
command: ./dev.sh
environment:
- DOCKER_HOST=0.0.0.0
- DOCKER_PORT=1080
ports:
- 1080:1080
user: "${DOCKER_USER}"

View File

Before

Width:  |  Height:  |  Size: 477 KiB

After

Width:  |  Height:  |  Size: 477 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

72
docs/getting-started.md Normal file
View File

@@ -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.

BIN
docs/hosting.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

6
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1692463654, "lastModified": 1767364772,
"narHash": "sha256-F8hZmsQINI+S6UROM4jyxAMbQLtzE44pI8Nk6NtMdao=", "narHash": "sha256-fFUnEYMla8b7UKjijLnMe+oVFOz6HjijGGNS1l7dYaQ=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "ca3c9ac9f4cdd4bea19f592b32bb59b74ab7d783", "rev": "16c7794d0a28b5a37904d55bcca36003b9109aaa",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -12,56 +12,26 @@
"aarch64-linux" "aarch64-linux"
"aarch64-darwin" "aarch64-darwin"
]; ];
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system); forAllSystems = f: nixpkgs.lib.genAttrs systems (system: let
pkgs = nixpkgs.legacyPackages.${system};
in f system pkgs);
in { in {
devShells = forAllSystems (system: rec { packages = forAllSystems (system: pkgs: {
pkgs = import nixpkgs { inherit system; }; default = self.packages.${system}.pvv-nettsiden;
default = pkgs.mkShellNoCC { pvv-nettsiden = pkgs.callPackage ./nix/package.nix { php = pkgs.php84; };
buildInputs = with pkgs; [ });
php82
(with php82Extensions; [
iconv
mbstring
pdo_mysql
pdo_sqlite
])
sqlite
git
];
shellHook = ''
export PHPHOST=localhost
export PHPPORT=1080
alias runDev='php -S $PHPHOST:$PHPPORT -d error_reporting=E_ALL -d display_errors=1 -t www/'
# Prepare dev environment with sqlite and config files
test -e pvv.sqlite || sqlite3 pvv.sqlite < dist/pvv.sql
test -e sql_config.php || cp -v dist/sql_config_example.php sql_config.php
test -e dataporten_config.php || cp -v dist/dataporten_config.php dataporten_config.php
test -e composer.phar || curl -O https://getcomposer.org/composer.phar
if [ ! -f lib/OAuth2-Client/OAuth2Client.php ] ; then
echo Missing git submodules. Installing...
(set -x; git submodule update --init --recursive) || exit $?
fi
if [ ! -d vendor ] ; then
php composer.phar install || exit $?
cp -v dist/authsources_example.php vendor/simplesamlphp/simplesamlphp/config/authsources.php
cp -v dist/saml20-idp-remote.php vendor/simplesamlphp/simplesamlphp/metadata/saml20-idp-remote.php
cp -v vendor/simplesamlphp/simplesamlphp/config-templates/config.php vendor/simplesamlphp/simplesamlphp/config/config.php
sed -e "s/'trusted.url.domains' => array()/'trusted.url.domains' => array(\"$PHPHOST:$PHPPORT\")/g" < vendor/simplesamlphp/simplesamlphp/config-templates/config.php > vendor/simplesamlphp/simplesamlphp/config/config.php
ln -s ../vendor/simplesamlphp/simplesamlphp/www/ www/simplesaml
fi
'';
# TODO:
# - Integrate with docker config
# - Make "trusted.url.domains" dynamic based on the current host:port
# - Do not download composer.phar with curl
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; };
}); });
}; };
} }

View File

@@ -1,11 +1,13 @@
<?php <?php
require __DIR__ . '/../src/_autoload.php';
require __DIR__ . '/../sql_config.php';
$pdo = new \PDO($dbDsn, $dbUser, $dbPass); 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); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$agenda = new \pvv\side\Agenda([ $agenda = new pvv\side\Agenda([
new \pvv\side\social\NerdepitsaActivity, new pvv\side\social\NerdepitsaActivity(),
new \pvv\side\social\AnimekveldActivity, new pvv\side\social\AnimekveldActivity(),
new \pvv\side\DBActivity($pdo), new pvv\side\DBActivity($pdo),
]); ]);

View File

@@ -1,36 +1,36 @@
<?php <?php
declare(strict_types=1);
// Set up database and user system, // Set up database and user system,
// and include common files such as HTML includes or SimplSAMLphp. // and include common files such as HTML includes or SimplSAMLphp.
require_once __DIR__ . DIRECTORY_SEPARATOR . 'agenda.php'; require_once __DIR__ . \DIRECTORY_SEPARATOR . 'agenda.php';
require_once __DIR__ . DIRECTORY_SEPARATOR . 'navbar.php'; require_once __DIR__ . \DIRECTORY_SEPARATOR . 'navbar.php';
require_once dirname(__DIR__) . implode(DIRECTORY_SEPARATOR, ['', 'lib', 'OAuth2-Client', 'OAuth2Client.php']); require_once dirname(__DIR__) . implode(\DIRECTORY_SEPARATOR, ['', 'config.php']);
require_once dirname(__DIR__) . implode(DIRECTORY_SEPARATOR, ['', 'dataporten_config.php']);
require_once dirname(__DIR__) . implode(DIRECTORY_SEPARATOR, ['', 'sql_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']);
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'); date_default_timezone_set('Europe/Oslo');
setlocale(LC_ALL, 'nb_NO'); setlocale(\LC_ALL, 'nb_NO');
$pdo = new \PDO($dbDsn, $dbUser, $dbPass); $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userManager = new \pvv\admin\UserManager($pdo); $userManager = new pvv\admin\UserManager($pdo);
$sp = 'default-sp'; $sp = 'default-sp';
$as = new SimpleSAML_Auth_Simple($sp); $as = new SimpleSAML\Auth\Simple($sp);
use \pvv\side\Agenda; use pvv\side\Agenda;
$agenda = new \pvv\side\Agenda([
$agenda = new Agenda([
// new \pvv\side\social\NerdepitsaActivity, // new \pvv\side\social\NerdepitsaActivity,
// new \pvv\side\social\AnimekveldActivity, // new \pvv\side\social\AnimekveldActivity,
new \pvv\side\social\HackekveldActivity, new pvv\side\social\HackekveldActivity(),
new \pvv\side\social\BrettspillActivity, new pvv\side\social\BrettspillActivity(),
new \pvv\side\social\DriftkveldActivity, new pvv\side\social\DriftkveldActivity(),
new \pvv\side\DBActivity($pdo), new pvv\side\DBActivity($pdo),
]); ]);
$months_translations = ['januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember']; $months_translations = ['januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'];

View File

@@ -1,70 +1,74 @@
<?php <?php
function navbar($depth, $active = NULL) {
$result = "\n\t<ul id=\"menu\">\n"; declare(strict_types=1);
$menuItems = [ function navbar($depth, $active = null) {
'Hjem' => '', $result = "\n\t<ul id=\"menu\">\n";
'Hendelser' => 'hendelser', $menuItems = [
//'Kalender' => 'kalender', 'Hjem' => '',
//'Aktiviteter' => 'aktiviteter', 'Hendelser' => 'hendelser',
'Prosjekter' => 'prosjekt', // 'Kalender' => 'kalender',
'Kontakt' => 'kontakt', // 'Aktiviteter' => 'aktiviteter',
'Webmail' => 'https://webmail2.pvv.ntnu.no/roundcube/', 'Prosjekter' => 'prosjekt',
'Galleri' => 'galleri', 'Kontakt' => 'kontakt',
'Wiki' => 'https://wiki.pvv.ntnu.no/', // 'Webmail' => 'https://webmail.pvv.ntnu.no/roundcube/',
'Git' => 'https://git.pvv.ntnu.no/', 'Galleri' => 'galleri',
'Tjenester' => 'tjenester', 'Wiki' => 'https://wiki.pvv.ntnu.no/',
]; 'Git' => 'https://git.pvv.ntnu.no/',
foreach($menuItems as $caption => $link) { 'Tjenester' => 'tjenester',
$isActive = $active === $link; ];
if (substr( $link, 0, 4 ) != "http") { foreach ($menuItems as $caption => $link) {
$link = rtrim(str_repeat('../', $depth) . $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"' : '') . '>' // if ($isActive) $link = '#';
. '<a href="' . $link . '">'
. $caption $result .= "\t\t<li" . ($isActive ? ' class="active"' : '') . '>'
. "</a></li>\n" . '<a href="' . $link . '">'
; . $caption
} . "</a></li>\n";
return $result . "\t</ul>\n"; }
return $result . "\t</ul>\n";
} }
function loginBar($sp = null, $pdo = null) { function loginBar($sp = null, $pdo = null) {
if (is_null($sp)) $sp = 'default-sp'; if (null === $sp) {
$result = "\n"; $sp = 'default-sp';
require_once(__DIR__ . '/../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'); }
$as = new SimpleSAML_Auth_Simple($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"> $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" /> <circle cx="32" cy="27" r="14" stroke-width="0" />
<ellipse cx="32" cy="66" rx="24" ry="28" stroke-width="0" /> <ellipse cx="32" cy="66" rx="24" ry="28" stroke-width="0" />
</svg> </svg>
'; ';
$attr = $as->getAttributes(); $attr = $as->getAttributes();
if($attr) { if ($attr) {
$uname = $attr['uid'][0]; $uname = $attr['uid'][0];
$isAdmin = false; $isAdmin = false;
if (isset($pdo)) { if (isset($pdo)) {
$userManager = new \pvv\admin\UserManager($pdo); $userManager = new pvv\admin\UserManager($pdo);
$isAdmin = $userManager->isAdmin($uname); $isAdmin = $userManager->isAdmin($uname);
} }
$result .= "\t<a id=\"login\" href=\"#usermenu\" aria-hidden=\"true\">{$svg}" . htmlspecialchars($uname) . "</a>\n"; $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<ul id=\"usermenu\">\n";
$result .= "\n\t\t<li><a id=\"login\" href=\"#\">{$svg}" . htmlspecialchars($uname) . "</a></li>\n"; $result .= "\n\t\t<li><a id=\"login\" href=\"#\">{$svg}" . htmlspecialchars($uname) . "</a></li>\n";
if ($isAdmin) { if ($isAdmin) {
$result .= "\n\t\t<li><a href=\"/admin/\">Admin</a></li>\n"; $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\t<li><a href=\"" . htmlspecialchars($as->getLogoutURL()) . "\">Logg ut</a></li>\n";
$result .= "\n\t</ul>\n"; $result .= "\n\t</ul>\n";
} else { } else {
$result .= "\t<a id=\"login\" href=\"" . htmlspecialchars($as->getLoginURL()) . "\">{$svg}Logg inn</a>\n"; $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>&#9776;&nbsp;</big>MENU</a>\n"; $result .= "\n\t<a href=\"#menu\" id=\"menu_toggle\" aria-hidden=\"true\"><big>&#9776;&nbsp;</big>MENU</a>\n";
return $result; return $result;
} }

View File

@@ -1,35 +0,0 @@
<ul id="ticker">
<?php
{
require __DIR__ . '/../src/_autoload.php';
require __DIR__ . '/../sql_config.php';
$translation = ['i dag', 'i morgen', 'denne uken', 'neste uke', 'denne måneden', 'neste måned'];
$pdo = new \PDO($dbDsn, $dbUser, $dbPass);
$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),
]);
$test = true;
foreach($agenda->getNextDays() as $period => $events) {
if (!$events) continue;
$i = 0;
$n = count($events);
foreach($events as $event){
if ($i == 0){
echo '<li style="text-align: center;"><span style="text-transform: uppercase;">' . $translation[$period] . '</span>: ';
} else if ($i < $n-1) {
echo '<i style="opacity:0.7;">,&nbsp;</i>';
} else{
echo '<i style="opacity:0.7;">&nbsp;og&nbsp;</i>';
}
echo '<a href="' . $event->getURL() . '">' . $event->getName() . '</a>';
$i = $i + 1;
}
break;
}
}
?>
</ul>

254
nix/module.nix Normal file
View File

@@ -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;
};
};
});
}

43
nix/package.nix Normal file
View File

@@ -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-3+hX9tzC7IvU2bDKpPsfk/TH1ZxffTp+5k5ky5tP7yg=";
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")
]}
'';
}

62
nix/php-generator.nix Normal file
View File

@@ -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;
};
}

17
nix/shell.nix Normal file
View File

@@ -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
];
}

36
scripts/clean.sh Executable file
View File

@@ -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
)

21
scripts/reset.sh Executable file
View File

@@ -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"

37
scripts/run.sh Executable file
View File

@@ -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[@]}")

48
scripts/seed-test-data.sh Executable file
View File

@@ -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

57
scripts/setup.sh Executable file
View File

@@ -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

View File

@@ -1,4 +1,6 @@
<?php <?php
declare(strict_types=1);
/* /*
* Copyright (c) 2014-2015, Jørn Åne de Jong <@jornane> * Copyright (c) 2014-2015, Jørn Åne de Jong <@jornane>
* *
@@ -14,7 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
/** /*
* Register SPL autoloading for classes and interfaces. Put this file in your * 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. * namespace root and make sure it gets included from your PHP entry-point.
* *
@@ -34,6 +36,6 @@
* @link http://php.net/manual/en/function.spl-autoload.php * @link http://php.net/manual/en/function.spl-autoload.php
* @license http://choosealicense.com/licenses/isc/ ISC license * @license http://choosealicense.com/licenses/isc/ ISC license
*/ */
spl_autoload_extensions( '.php' ); spl_autoload_extensions('.php');
spl_autoload_register( 'spl_autoload' ); spl_autoload_register('spl_autoload');
set_include_path( realpath( __DIR__ ) . PATH_SEPARATOR . get_include_path() ); set_include_path(realpath(__DIR__) . \PATH_SEPARATOR . get_include_path());

View File

@@ -1,134 +1,144 @@
<?php <?php
declare(strict_types=1);
namespace pvv\admin; namespace pvv\admin;
use \PDO; class UserManager {
private \PDO $pdo;
class UserManager{ public array $usergroups = [
private $pdo; 'admin' => 1,
'prosjekt' => 2,
'aktiviteter' => 4,
];
public $usergroups = [ public function __construct(\PDO $pdo) {
'admin' => 1, $this->pdo = $pdo;
'prosjekt' => 2, }
'aktiviteter' => 4
];
public function __construct($pdo){ public function setupUser(string $uname, int $groups = 0): void {
$this->pdo = $pdo; $query = 'INSERT INTO users (uname, groups) VALUES (:uname, :groups)';
} $statement = $this->pdo->prepare($query);
$statement->bindParam(':uname', $uname, \PDO::PARAM_STR);
$statement->bindParam(':groups', $groups, \PDO::PARAM_INT);
$statement->execute();
}
public function setupUser($uname, $groups=0){ public function updateFlags(string $uname, int $flags): void {
$query = 'INSERT INTO users (uname, groups) VALUES (:uname, :groups)'; $query = 'UPDATE users set groups=:groups WHERE uname=:uname';
$statement = $this->pdo->prepare($query); $statement = $this->pdo->prepare($query);
$statement->bindParam(':uname', $uname, PDO::PARAM_STR); $statement->bindParam(':groups', $flags, \PDO::PARAM_INT);
$statement->bindParam(':groups', $groups, PDO::PARAM_INT); $statement->bindParam(':uname', $uname, \PDO::PARAM_STR);
$statement->execute(); }
}
public function updateFlags($uname, $flags){ public function addGroup(string $uname, int $group): void {
$query = 'UPDATE users set groups=:groups WHERE uname=:uname'; $userFlags = $this->getUsergroups($uname);
$statement = $this->pdo->prepare($query);
$statement->bindParam(':groups', $flags, PDO::PARAM_INT);
$statement->bindParam(':uname', $uname, PDO::PARAM_STR);
}
public function addGroup($uname, $group){ if ($userFlags) {
$userFlags = $this->getUsergroups($uname); $newFlags = ($group | $userFlags);
$this->updateFlags($uname, $newFlags);
}
}
if($userFlags){ public function removeGroup(string $uname, int $group): void {
$newFlags = ($group | $userFlags); $userFlags = $this->getUsergroups($uname);
$this->updateFlags($uname, $newFlags);
}
}
public function removeGroup($uname, $group){ if ($userFlags) {
$userFlags = $this->getUsergroups($uname); $newFlags = ($userFlags & (~ $group));
$this->updateFlags($uname, $newFlags);
}
}
if($userFlags){ public function setGroups(string $uname, int $groups): void {
$newFlags = ($userFlags & (~ $group)); $query = 'SELECT * FROM users WHERE uname=:uname LIMIT 1';
$this->updateFlags($uname, $newFlags); $statement = $this->pdo->prepare($query);
} $statement->bindParam(':uname', $uname, \PDO::PARAM_STR);
} $statement->execute();
$row = $statement->fetch();
public function setGroups($uname, $groups){ if ($row) {
$query = 'SELECT * FROM users WHERE uname=:uname LIMIT 1'; $query = 'UPDATE users set groups=:groups WHERE uname=:uname';
$statement = $this->pdo->prepare($query); $statement = $this->pdo->prepare($query);
$statement->bindParam(':uname', $uname, PDO::PARAM_STR); $statement->bindParam(':groups', $groups, \PDO::PARAM_INT);
$statement->execute(); $statement->bindParam(':uname', $uname, \PDO::PARAM_STR);
$row = $statement->fetch(); $statement->execute();
} else {
$this->setupUser($uname, $groups);
}
}
if($row){ public function hasGroup(string $uname, string $groupName): bool {
$query = 'UPDATE users set groups=:groups WHERE uname=:uname'; $userFlags = $this->getUsergroups($uname);
$statement = $this->pdo->prepare($query);
$statement->bindParam(':groups', $groups, PDO::PARAM_INT);
$statement->bindParam(':uname', $uname, PDO::PARAM_STR);
$statement->execute();
}else{
$this->setupUser($uname, $groups);
}
}
public function hasGroup($uname, $groupName){ return (bool) ($userFlags & $this->usergroups[$groupName]);
$userFlags = $this->getUsergroups($uname); }
return ($userFlags & $this->usergroups[$groupName]); // for convenience
} public function isAdmin(string $uname): bool {
return $this->hasGroup($uname, 'admin');
}
// for convenience public function getFlagfromNames(array $names): int {
public function isAdmin($uname){ $resultFlag = 0;
return $this->hasGroup($uname, 'admin');
}
public function getFlagfromNames($names){ foreach ($this->usergroups as $name => $flag) {
$resultFlag = 0; if (\in_array($name, $names, true)) {
$resultFlag = ($resultFlag | $flag);
}
}
foreach($this->usergroups as $name => $flag){ return $resultFlag;
if(in_array($name, $names)){ }
$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->bindParam(':uname', $uname, \PDO::PARAM_STR);
$statement->execute();
public function getUsergroups($uname){ $row = $statement->fetch();
$query = 'SELECT groups FROM users WHERE uname=:uname LIMIT 1'; if ($row === false) {
$statement = $this->pdo->prepare($query); return 0;
$statement->bindParam(':uname', $uname, PDO::PARAM_STR); }
$statement->execute();
$row = $statement->fetch(); return $row[0];
if ($row == false) return 0; }
return $row[0];
}
public function getUsergroupNames($uname){ /**
$usersGroups = []; * @return string[]
*/
public function getUsergroupNames($uname): array {
$usersGroups = [];
$userFlags = $this->getUsergroups($uname); $userFlags = $this->getUsergroups($uname);
foreach($this->usergroups as $name => $flag){ foreach ($this->usergroups as $name => $flag) {
if($userFlags & $flag){ if ($userFlags & $flag) {
$usersGroups[] = $name; $usersGroups[] = $name;
} }
} }
return $usersGroups; return $usersGroups;
} }
public function getAllUserData(){ /**
$query = 'SELECT uname FROM users ORDER BY uname ASC'; * @return array<int,array{name:string,groups:string[]}>
$statement = $this->pdo->prepare($query); */
$statement->execute(); public function getAllUserData(): array {
$query = 'SELECT uname FROM users ORDER BY uname ASC';
$statement = $this->pdo->prepare($query);
$statement->execute();
$users = []; $users = [];
foreach($statement->fetchAll() as $userData){ foreach ($statement->fetchAll() as $userData) {
$uname = $userData['uname']; $uname = $userData['uname'];
$users[] = [ $users[] = [
'name' => $uname, 'name' => $uname,
'groups' => $this->getUsergroupNames($uname) 'groups' => $this->getUsergroupNames($uname),
]; ];
} }
return $users; return $users;
} }
} }

View File

@@ -1,12 +1,11 @@
<?php //declare(strict_types=1); <?php
declare(strict_types=1);
namespace pvv\side; namespace pvv\side;
use \DateTimeImmutable;
interface Activity { interface Activity {
public function getNextEventFrom(\DateTimeImmutable $date): ?Event;
public function getNextEventFrom(DateTimeImmutable $date) /* : Event */; public function getPreviousEventFrom(\DateTimeImmutable $date): ?Event;
public function getPreviousEventFrom(DateTimeImmutable $date) /* : Event */;
} }

View File

@@ -1,106 +1,136 @@
<?php //declare(strict_types=1); <?php
declare(strict_types=1);
namespace pvv\side; namespace pvv\side;
use \DateTimeImmutable;
use \DateInterval;
class Agenda { class Agenda {
private array $activities;
const TODAY = 0; public const int TODAY = 0;
const TOMORROW = 1; public const int TOMORROW = 1;
const THIS_WEEK = 2; public const int THIS_WEEK = 2;
const NEXT_WEEK = 3; public const int NEXT_WEEK = 3;
const THIS_MONTH = 4; public const int THIS_MONTH = 4;
const NEXT_MONTH = 5; public const int NEXT_MONTH = 5;
public function __construct($activities) { /**
$this->activities = $activities; * @param array<int,DBActivity> $activities
} */
public function __construct(array $activities) {
$this->activities = $activities;
}
public static function getFormattedDate($date) { public static function getFormattedDate(\DateTimeImmutable $date): string {
return trim(strftime('%A %e. %b %H.%M', $date->getTimeStamp())); 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;
} }
public function getEventsBetween(DateTimeImmutable $from, DateTimeImmutable $to) { return $result;
$results = []; }
for($i = 0; $i < sizeof($this->activities); $i++) {
$result = [];
do {
$run = false;
if (sizeof($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, function($a, $b) {
return ($a->getStart() < $b->getStart()) ? -1 : 1;
});
return $result;
}
public function getNextDays() { /**
$result = [[], [], [], [], [], []]; * @return array<Event>
$events = $this->getEventsBetween( */
(new DateTimeImmutable)->setTime(0, 0), public function getNextOfEach(\DateTimeImmutable $startDate): array {
(new DateTimeImmutable)->setTime(23, 59)->add(new DateInterval('P1M')) $result = array_filter(
); array_map(
foreach ($events as $event) { static fn($a) => $a->getNextEventFrom($startDate),
$index = self::NEXT_MONTH; $this->activities,
if (self::isToday($event->getStart())) $index = self::TODAY; ),
elseif (self::isTomorrow($event->getStart())) $index = self::TOMORROW; static fn($a) => isset($a),
elseif (self::isThisWeek($event->getStart())) $index = self::THIS_WEEK; );
elseif (self::isNextWeek($event->getStart())) $index = self::NEXT_WEEK; usort(
elseif (self::isThisMonth($event->getStart())) $index = self::THIS_MONTH; $result,
$result[$index][] = $event; static fn($a, $b) => $a->getStart()->getTimeStamp()
} < $b->getStart()->getTimeStamp()
return $result; ? -1
} : 1,
);
public function getNextOfEach(DateTimeImmutable $startDate) { return $result;
$result = array_filter(array_map( }
function($a) use ($startDate){
return $a->getNextEventFrom($startDate);
}, $this->activities
), function($a){
return isset($a);
});
usort($result, function($a, $b) {
return ($a->getStart()->getTimeStamp() < $b->getStart()->getTimeStamp())
? -1
: 1
;
});
return $result;
}
public static function isToday(DateTimeImmutable $date) { public static function isToday(\DateTimeImmutable $date): bool {
return $date->format('dmY') == date('dmY'); return $date->format('dmY') === date('dmY');
} }
public static function isTomorrow(DateTimeImmutable $date) { public static function isTomorrow(\DateTimeImmutable $date): bool {
return $date->sub(new DateInterval('P1D'))->format('dmY') == date('dmY'); return $date->sub(new \DateInterval('P1D'))->format('dmY') === date('dmY');
} }
public static function isThisWeek(DateTimeImmutable $date) { public static function isThisWeek(\DateTimeImmutable $date): bool {
return $date->format('WY') == date('WY'); return $date->format('WY') === date('WY');
} }
public static function isNextWeek(DateTimeImmutable $date) { public static function isNextWeek(\DateTimeImmutable $date): bool {
return $date->sub(new DateInterval('P7D'))->format('WY') == date('WY'); return $date->sub(new \DateInterval('P7D'))->format('WY') === date('WY');
} }
public static function isThisMonth(DateTimeImmutable $date) {
return $date->format('mY') == date('mY');
}
public static function isThisMonth(\DateTimeImmutable $date): bool {
return $date->format('mY') === date('mY');
}
} }

View File

@@ -1,84 +1,119 @@
<?php <?php
declare(strict_types=1);
namespace pvv\side; namespace pvv\side;
use \DateTimeImmutable;
use \PDO;
class DBActivity implements Activity { class DBActivity implements Activity {
private $pdo;
public function __construct(PDO $pdo) { public function __construct(\PDO $pdo) {
$this->pdo = $pdo; $this->pdo = $pdo;
} }
public function getAllEvents() { /**
$query = 'SELECT * FROM events ORDER BY id DESC'; * @return SimpleEvent[]
$statement = $this->pdo->prepare($query); */
$statement->execute(); public function getAllEvents(): array {
$query = 'SELECT * FROM events ORDER BY id DESC';
$statement = $this->pdo->prepare($query);
$statement->execute();
$events = []; $events = [];
foreach($statement->fetchAll() as $dbEvent){ foreach ($statement->fetchAll() as $dbEvent) {
$event = new SimpleEvent( $event = new SimpleEvent(
$dbEvent['id'], $dbEvent['id'],
$dbEvent['name'], $dbEvent['name'],
DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $dbEvent['start']), \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $dbEvent['start']),
DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $dbEvent['stop']), \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $dbEvent['stop']),
$dbEvent['organiser'], $dbEvent['organiser'],
$dbEvent['location'], $dbEvent['location'],
$dbEvent['description'] $dbEvent['description'],
); );
$events[] = $event; $events[] = $event;
} }
return $events; return $events;
} }
public function getEventByID($id) { public function getEventByID(int $id): SimpleEvent {
$query = 'SELECT * FROM events WHERE id=:id LIMIT 1'; $query = 'SELECT * FROM events WHERE id=:id LIMIT 1';
$statement = $this->pdo->prepare($query); $statement = $this->pdo->prepare($query);
$statement->bindParam(':id', $id, PDO::PARAM_INT); $statement->bindParam(':id', $id, \PDO::PARAM_INT);
$statement->execute(); $statement->execute();
$dbEvent = $statement->fetch(); $dbEvent = $statement->fetch();
$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']
);
return $event; 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
';
public function getNextEventFrom(DateTimeImmutable $date) { return $this->retrieve($date, $query);
$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) { 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'; $query = '
return $this->retrieve($date, $query); SELECT
} id,
name,
start,
stop,
organiser,
location,
description
FROM events
WHERE
start < :date
ORDER BY start DESC
LIMIT 1
';
private function retrieve($date, $query) { return $this->retrieve($date, $query);
$stmt = $this->pdo->prepare($query); }
$stmt->execute(['date' => $date->format('Y-m-d H:i:s')]);
if ($result = $stmt->fetch(PDO::FETCH_ASSOC)){
$ev = 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 $ev;
}
return null;
}
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;
}
} }

View File

@@ -1,74 +1,140 @@
<?php <?php
declare(strict_types=1);
namespace pvv\side; namespace pvv\side;
use \PDO; use DateTimeImmutable;
class Door{ class DoorStatus {
private $pdo; private DateTimeImmutable $time;
private bool $open;
public function __construct(PDO $pdo){ public function __construct(DateTimeImmutable $time, bool $open) {
$this->pdo = $pdo; $this->time = $time;
} $this->open = $open;
}
public function getAll() { public function getTime(): DateTimeImmutable {
$query = 'SELECT time, open FROM door ORDER BY time DESC'; return $this->time;
$statement = $this->pdo->prepare($query); }
$statement->execute();
$doorEvents = []; public function getTimeStamp(): int {
foreach($statement->fetchAll() as $row){ return $this->time->getTimestamp();
$doorEvents[] = [ }
'time' => (int)$row['time'],
'open' => (bool)$row['open']
];
}
return $doorEvents; public function isOpen(): bool {
} return $this->open;
}
public function getEntriesAfter($startTime) { }
$query = 'SELECT time, open FROM door WHERE time > :startTime ORDER BY time DESC';
$statement = $this->pdo->prepare($query); class Door {
$statement->bindParam(':startTime', $startTime, PDO::PARAM_STR); private $pdo;
$statement->execute();
const DAYS_OF_DOOR_HISTORY = 7;
$doorEvents = [];
foreach($statement->fetchAll() as $row){ public function __construct(\PDO $pdo) {
$doorEvents[] = [ $this->pdo = $pdo;
'time' => (int)$row['time'], }
'open' => (bool)$row['open']
]; /**
} * @return DoorStatus[]
*/
return $doorEvents; public function getAll(): array {
} $query = '
SELECT
public function getCurrent() { time,
$query = 'SELECT time, open FROM door ORDER BY time DESC LIMIT 1'; open
$statement = $this->pdo->prepare($query); FROM door
$statement->execute(); ORDER BY time DESC
$row = $statement->fetch(); ';
return [ $statement = $this->pdo->prepare($query);
'time' => (int)$row['time'], $statement->execute();
'open' => (bool)$row['open']
]; $result = array_map(
} function ($row) {
return new DoorStatus(
private function removeOld() { (new DateTimeImmutable)->setTimestamp((int) $row['time']),
$firstValidTime = time() - 60*60*24*7; //One week before now (bool) $row['open'],
$query = 'DELETE FROM door WHERE time < :firstValid'; );
$statement = $this->pdo->prepare($query); },
$statement->bindParam(':firstValid', $firstValidTime, PDO::PARAM_STR); $statement->fetchAll(),
$statement->execute(); );
}
return $result;
public function createEvent($time, $open) { }
$query = 'INSERT INTO door(time, open) VALUES (:time, :open)';
$statement = $this->pdo->prepare($query); /**
$statement->bindParam(':time', $time, PDO::PARAM_STR); * @return DoorStatus[]
$statement->bindParam(':open', $open, PDO::PARAM_STR); */
$statement->execute(); public function getEntriesAfter(\DateTimeImmutable $startTime): array {
$timestamp = $startTime->getTimestamp();
$this->removeOld();
} $query = '
SELECT
time,
open
FROM door
WHERE time > :startTime
ORDER BY time DESC
';
$statement = $this->pdo->prepare($query);
$statement->bindParam(':startTime', $timestamp, \PDO::PARAM_INT);
$statement->execute();
$result = array_map(
function ($row) {
return 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;
}
$result = new DoorStatus(
(new DateTimeImmutable)->setTimestamp((int) $row['time']),
(bool) $row['open'],
);
return $result;
}
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->bindParam(':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->bindParam(':time', $time->getTimestamp(), \PDO::PARAM_INT);
$statement->bindParam(':open', $open, \PDO::PARAM_BOOL);
$statement->execute();
$this->removeOld();
}
} }

View File

@@ -1,53 +1,59 @@
<?php //declare(strict_types=1); <?php
declare(strict_types=1);
namespace pvv\side; namespace pvv\side;
use \DateTimeImmutable;
use \DateInterval;
abstract class Event { abstract class Event {
private \DateTimeImmutable $start;
private $start; public function __construct(\DateTimeImmutable $start) {
$this->start = $start;
}
public function __construct(DateTimeImmutable $start) { public function getStart(): \DateTimeImmutable {
$this->start = $start; return $this->start;
} }
public function getStart() { public function getRelativeDate(): string {
return $this->start; 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';
}
public function getRelativeDate() { return $this->getStart()->format('j. F');
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 strftime('%A', $this->getStart()->getTimestamp());
}
if (Agenda::isNextWeek($this->getStart())) {
return 'neste uke';
}
if (Agenda::isThisMonth($this->getStart())) {
return 'denne måneden';
}
return trim(strftime('%e. %B', $this->getStart()->getTimestamp()));
}
public abstract function getStop(); /* : DateTimeImmutable */ abstract public function getStop(): \DateTimeImmutable;
public abstract function getName(); abstract public function getName(): string;
public abstract function getLocation(); abstract public function getLocation(): string;
public abstract function getOrganiser(); abstract public function getOrganiser(): string;
public abstract function getURL(); /* : string */ abstract public function getURL(): string;
public abstract function getImageURL(); /* : string */ abstract public function getImageURL(): string;
public abstract function getDescription(); /* : string */ /**
* @return string[]
*/
abstract public function getDescription(): array;
public abstract function getColor(); /* : string */ abstract public function getColor(): string;
} }

View File

@@ -1,49 +1,106 @@
<?php <?php
declare(strict_types=1);
namespace pvv\side; namespace pvv\side;
use \PDO; class MOTDItem {
private string $title;
/** @var string[] */
private array $content;
class MOTD{ /**
private $pdo; * @param string[] $content
*/
public function __construct(string $title, array $content) {
$this->title = $title;
$this->content = $content;
}
public function __construct($pdo){ public function getTitle(): string {
$this->pdo = $pdo; return $this->title;
} }
public function setMOTD($title, $content) { /**
if (is_array($content)) { * @return string[]
$content = implode("_", $content); */
} public function getContent(): array {
$query = 'INSERT INTO motd(title, content) VALUES (:title, :content);'; return $this->content;
$statement = $this->pdo->prepare($query); }
$statement->bindParam(':title', $title, PDO::PARAM_STR); public function getContentAsString(): string {
$statement->bindParam(':content', $content, PDO::PARAM_STR); return implode("\n", $this->content);
}
$statement->execute(); }
}
class MOTD {
public function getMOTD() { private $pdo;
$query = 'SELECT motd.title, motd.content FROM motd ORDER BY motd.id DESC LIMIT 1';
$statement = $this->pdo->prepare($query); public function __construct(\PDO $pdo) {
$statement->execute(); $this->pdo = $pdo;
}
$data = $statement->fetch();
$motd = array("title" => $data[0], "content" => explode("\n", $data[1])); public function setMOTD(string $title, string $content): void {
if (\is_array($content)) {
return $motd; $content = implode('_', $content);
} }
$query = 'INSERT INTO motd(title, content) VALUES (:title, :content)';
public function getMOTD_history($limit = 5) { $statement = $this->pdo->prepare($query);
$query = 'SELECT motd.title, motd.content FROM motd ORDER BY motd.id DESC LIMIT :limit';
$statement = $this->pdo->prepare($query); $statement->bindParam(':title', $title, \PDO::PARAM_STR);
$statement->bindParam(':limit', $limit, PDO::PARAM_STR); $statement->bindParam(':content', $content, \PDO::PARAM_STR);
$statement->execute();
$statement->execute();
$data = $statement->fetch(); }
$motd = array("title" => $data[0], "content" => explode("\n", $data[1]));
public function getMOTD(): MOTDItem {
return $motd; $query = '
} SELECT
title,
content
FROM motd
ORDER BY id DESC
LIMIT 1
';
$statement = $this->pdo->prepare($query);
$statement->execute();
$data = $statement->fetch();
$result = new MOTDItem(
$data['title'],
explode("\n", $data['content']),
);
return $result;
}
/**
* @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->bindParam(':limit', $limit, \PDO::PARAM_STR);
$statement->execute();
$result = array_map(
function ($item) {
return new MOTDItem(
$item['title'],
explode("\n", $item['content']),
);
},
$statement->fetchAll(),
);
return $result;
}
} }

View File

@@ -1,29 +1,40 @@
<?php <?php
declare(strict_types=1);
namespace pvv\side; namespace pvv\side;
class Project{ class Project {
private $id, $name, $descr, $active; private int $id;
private string $name;
private array $descr;
private bool $active;
public function __construct($id, $name, $descr, $active){ public function __construct(
$this->id = $id; int $id,
$this->name = $name; string $name,
$this->descr = explode("\n", $descr); string $descr,
$this->active = $active; bool $active,
} ) {
$this->id = $id;
$this->name = $name;
$this->descr = explode("\n", $descr);
$this->active = $active;
}
public function getID(){ public function getID(): int {
return $this->id; return $this->id;
} }
public function getName(){ public function getName(): string {
return $this->name; return $this->name;
} }
public function getDescription(){ public function getDescription(): array {
return $this->descr; return $this->descr;
} }
public function getActive(){ public function getActive(): bool {
return $this->active; return $this->active;
} }
} }

View File

@@ -1,121 +1,132 @@
<?php <?php
declare(strict_types=1);
namespace pvv\side; namespace pvv\side;
use \PDO; class ProjectManager {
private $pdo;
class ProjectManager{ public function __construct(\PDO $pdo) {
private $pdo; $this->pdo = $pdo;
}
public function __construct(PDO $pdo){ /**
$this->pdo = $pdo; * @return Project[]
} */
public function getAll(): array {
$query = 'SELECT * FROM projects ORDER BY id ASC';
$statement = $this->pdo->prepare($query);
$statement->execute();
public function getAll() { $projects = [];
$query = 'SELECT * FROM projects ORDER BY id ASC'; foreach ($statement->fetchAll() as $dbProj) {
$statement = $this->pdo->prepare($query); $project = new Project(
$statement->execute(); $dbProj['id'],
$dbProj['name'],
$dbProj['description'],
(bool) $dbProj['active'],
);
$projects[] = $project;
}
$projects = []; return $projects;
foreach($statement->fetchAll() as $dbProj){ }
$project = new Project(
$dbProj['id'],
$dbProj['name'],
$dbProj['description'],
$dbProj['active']
);
$projects[] = $project;
}
return $projects; public function getByID(int $id): ?Project {
} $query = 'SELECT * FROM projects WHERE id=:id LIMIT 1';
$statement = $this->pdo->prepare($query);
$statement->bindParam(':id', $id, \PDO::PARAM_INT);
$statement->execute();
public function getByID($id){ $dbProj = $statement->fetch();
$query = 'SELECT * FROM projects WHERE id=:id LIMIT 1'; if (!$dbProj) {
$statement = $this->pdo->prepare($query); return null;
$statement->bindParam(':id', $id, PDO::PARAM_INT); }
$statement->execute();
$dbProj = $statement->fetch(); return new Project(
if (!$dbProj) { $dbProj['id'],
return false; $dbProj['name'],
} $dbProj['description'],
$project = new Project( (bool) $dbProj['active'],
$dbProj['id'], );
$dbProj['name'], }
$dbProj['description'],
$dbProj['active']
);
return $project; /**
} * @return Project[]
*/
public function getByOwner(string $uname): array {
$query = 'SELECT projectid FROM projectmembers WHERE uname=:uname';
$statement = $this->pdo->prepare($query);
$statement->bindParam(':uname', $uname, \PDO::PARAM_STR);
$statement->execute();
public function getByOwner($uname){ $projectIDs = $statement->fetchAll();
$query = 'SELECT projectid FROM projectmembers WHERE uname=:uname'; $projects = [];
$statement = $this->pdo->prepare($query); foreach ($projectIDs as $id) {
$statement->bindParam(':uname', $uname, PDO::PARAM_STR); $id = $id['projectid'];
$statement->execute();
$projectIDs = $statement->fetchAll(); $query = 'SELECT * FROM projects WHERE id=:id';
$projects = []; $statement = $this->pdo->prepare($query);
foreach($projectIDs as $id){ $statement->bindParam(':id', $id, \PDO::PARAM_INT);
$id = $id['projectid']; $statement->execute();
$query = 'SELECT * FROM projects WHERE id=:id';
$statement = $this->pdo->prepare($query);
$statement->bindParam(':id', $id, PDO::PARAM_INT);
$statement->execute();
foreach($statement->fetchAll() as $dbProj){
$project = new Project(
$dbProj['id'],
$dbProj['name'],
$dbProj['description'],
$dbProj['active']
);
$projects[] = $project;
}
}
return $projects; foreach ($statement->fetchAll() as $dbProj) {
} $project = new Project(
$dbProj['id'],
$dbProj['name'],
$dbProj['description'],
(bool) $dbProj['active'],
);
$projects[] = $project;
}
}
public function getProjectMembers($id){ return $projects;
$query = 'SELECT * FROM projectmembers WHERE projectid=:id'; }
$statement = $this->pdo->prepare($query);
$statement->bindParam(':id', $id, PDO::PARAM_STR);
$statement->execute();
$members = []; /**
foreach($statement->fetchAll() as $dbUsr){ * @return array<int,array>
$members[] = [ */
'name' => $dbUsr['name'], public function getProjectMembers(int $id): array {
'uname' => $dbUsr['uname'], $query = 'SELECT * FROM projectmembers WHERE projectid=:id';
'mail' => $dbUsr['mail'], $statement = $this->pdo->prepare($query);
'role' => $dbUsr['role'], $statement->bindParam(':id', $id, \PDO::PARAM_STR);
'lead' => $dbUsr['lead'], $statement->execute();
'owner' => $dbUsr['owner']
];
}
return $members; $members = [];
} foreach ($statement->fetchAll() as $dbUsr) {
$members[] = [
'name' => $dbUsr['name'],
'uname' => $dbUsr['uname'],
'mail' => $dbUsr['mail'],
'role' => $dbUsr['role'],
'lead' => (bool) $dbUsr['lead'],
'owner' => (bool) $dbUsr['owner'],
];
}
public function getProjectOwner($id){ return $members;
$query = 'SELECT * FROM projectmembers WHERE (projectid=:id AND owner=1)'; }
$statement = $this->pdo->prepare($query);
$statement->bindParam(':id', $id, PDO::PARAM_STR);
$statement->execute();
$dbOwner = $statement->fetch(); /**
$owner = [ * @return array<string,mixed>
'name' => $dbOwner['name'], */
'uname' => $dbOwner['uname'], public function getProjectOwner(int $id): array {
'mail' => $dbOwner['mail'], $query = 'SELECT * FROM projectmembers WHERE (projectid=:id AND owner=1)';
'role' => $dbOwner['role'], $statement = $this->pdo->prepare($query);
'lead' => $dbOwner['lead'], $statement->bindParam(':id', $id, \PDO::PARAM_STR);
'owner' => $dbOwner['owner'] $statement->execute();
];
return $owner; $dbOwner = $statement->fetch();
}
return [
'name' => $dbOwner['name'],
'uname' => $dbOwner['uname'],
'mail' => $dbOwner['mail'],
'role' => $dbOwner['role'],
'lead' => (bool) $dbOwner['lead'],
'owner' => (bool) $dbOwner['owner'],
];
}
} }

View File

@@ -1,63 +1,74 @@
<?php <?php
declare(strict_types=1);
namespace pvv\side; namespace pvv\side;
class SimpleEvent extends Event { 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;
private $id, $name, $descr, $start, $end, $org, $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 __construct($id, $name,\DateTimeImmutable $start,\DateTimeImmutable $end,$org, $loc, $descr, $isDBEvent = false){ public function getID(): int {
$this->id = $id; return $this->id;
$this->name = $name; }
$this->start = $start;
$this->end = $end;
$this->org = $org;
$this->loc = $loc;
$this->descr = explode("\n", $descr);
$this->isDBEvent = $isDBEvent;
}
public function getID(){ public function getStart(): \DateTimeImmutable {
return $this->id; return $this->start;
} }
public function getStart(){ public function getStop(): \DateTimeImmutable {
return $this->start; return $this->end;
} }
public function getStop(){ public function getOrganiser(): string {
return $this->end; return $this->org;
} }
public function getOrganiser(){ public function getLocation(): string {
return $this->org; return $this->loc;
} }
public function getLocation(){ public function getName(): string {
return $this->loc; return $this->name;
} }
public function getName(){ public function getURL(): string {
return $this->name; return '/hendelser/info.php?id=' . $this->id;
} }
public function getURL() { public function getImageURL(): string {
return ('/hendelser/info.php?id=' . $this->id); return '/';
} }
public function getImageURL() { public function getDescription(): array {
return null; return $this->descr;
} }
public function getDescription() {
return $this->descr;
}
public function isDBEvent() {
return $this->isDBEvent;
}
public function getColor() {
return "#3b7";
}
public function getColor(): string {
return '#3b7';
}
} }

View File

@@ -1,36 +1,53 @@
<?php //declare(strict_types=1); <?php
declare(strict_types=1);
namespace pvv\side\social; namespace pvv\side\social;
use \pvv\side\Activity; use pvv\side\Activity;
use \DateTimeImmutable;
use \DateInterval;
class AnimekveldActivity implements 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')));
}
public function nextDate(DateTimeImmutable $date) { return $date;
if ($date->format('H') > 20 || $date->format('H') == 19 && $date->format('i') > 30) }
return $this->nextDate($date->add(new DateInterval('P1D'))->setTime(19, 30, 0));
$date = $date->setTime(19, 30, 0);
if ($date->format('N') != 5)
return $this->nextDate($date->add(new DateInterval('P1D')));
return $date;
}
public function prevDate(DateTimeImmutable $date) { public function prevDate(\DateTimeImmutable $date): \DateTimeImmutable {
if ($date->format('H') < 19 || $date->format('H') == 20 && $date->format('i') < 30) if (
return $this->prevDate($date->sub(new DateInterval('P1D'))->setTime(19, 30, 0)); (int) $date->format('H') < 19
$date = $date->setTime(19, 30, 0); || ((int) $date->format('H') === 20 && (int) $date->format('i') < 30)
if ($date->format('N') != 5) ) {
return $this->prevDate($date->sub(new DateInterval('P1D'))); return $this->prevDate(
return $date; $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')));
}
public function getNextEventFrom(DateTimeImmutable $date) /* : Event */ { return $date;
return new AnimekveldEvent($this->nextDate($date)); }
}
public function getPreviousEventFrom(DateTimeImmutable $date) /* : Event */ { public function getNextEventFrom(\DateTimeImmutable $date): AnimekveldEvent {
return new AnimekveldEvent($this->prevDate($date)); return new AnimekveldEvent($this->nextDate($date));
} }
public function getPreviousEventFrom(
\DateTimeImmutable $date,
): AnimekveldEvent {
return new AnimekveldEvent($this->prevDate($date));
}
} }

View File

@@ -1,49 +1,48 @@
<?php //declare(strict_types=1); <?php
declare(strict_types=1);
namespace pvv\side\social; namespace pvv\side\social;
use \pvv\side\Event; use pvv\side\Event;
use \DateInterval;
class AnimekveldEvent extends Event { class AnimekveldEvent extends Event {
public function getStop(): \DateTimeImmutable {
return $this->getStart()->add(new \DateInterval('PT4H1800S'));
}
public function getStop() { public function getName(): string {
return $this->getStart()->add(new DateInterval('PT4H1800S')); return 'Animekveld';
} }
public function getName() /* : string */ { public function getLocation(): string {
return "Animekveld"; /* : Location */
} return 'Koserommet';
}
public function getLocation() /* : Location */ { public function getOrganiser(): string {
return "Koserommet"; return 'Christoffer Viken';
} }
public function getOrganiser() /* : User */ { public function getURL(): string {
return "Christoffer Viken"; return '/anime/';
} }
public function getURL() /* : string */ { public function getImageURL(): string {
return '/anime/'; return '/sosiale/animekveld.jpg';
} }
public function getImageURL() { public function getDescription(): array {
return '/sosiale/animekveld.jpg'; 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!',
public function getDescription() { '',
return [ 'Alle kan være med på å anbefale eller veto serier.',
'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.',
'',
'I disse tider blir visningene i all hovedsak holdt online på vår <a href="https://discord.gg/cx4aXU7">Discord server</a>'
];
}
public function getColor() {
return "#35a";
}
public function getColor(): string {
return '#35a';
}
} }

View File

@@ -1,41 +1,59 @@
<?php //declare(strict_types=1); <?php
declare(strict_types=1);
namespace pvv\side\social; namespace pvv\side\social;
use \pvv\side\Activity; use pvv\side\Activity;
use \DateTimeImmutable;
use \DateInterval;
class BrettspillActivity implements 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')));
}
public function nextDate(DateTimeImmutable $date) { return $date;
if ($date->format('H') > 17 || $date->format('H') == 16 && $date->format('i') > 15) }
return $this->nextDate($date->add(new DateInterval('P1D'))->setTime(16, 15, 0));
$date = $date->setTime(16, 15, 0);
if ($date->format('N') != 7)
return $this->nextDate($date->add(new DateInterval('P1D')));
if ($date->format('W') % 2 - 1)
return $this->nextDate($date->add(new DateInterval('P7D')));
return $date;
}
public function prevDate(DateTimeImmutable $date) { public function prevDate(\DateTimeImmutable $date): \DateTimeImmutable {
if ($date->format('H') < 16 || $date->format('H') == 17 && $date->format('i') < 15) if (
return $this->prevDate($date->sub(new DateInterval('P1D'))->setTime(16, 15, 0)); (int) $date->format('H') < 16
$date = $date->setTime(16, 15, 0); || ((int) $date->format('H') === 17 && (int) $date->format('i') < 15)
if ($date->format('N') != 7) ) {
return $this->prevDate($date->sub(new DateInterval('P1D'))); return $this->prevDate(
if ($date->format('W') % 2 - 1) $date->sub(new \DateInterval('P1D'))->setTime(16, 15, 0),
return $this->prevDate($date->sub(new DateInterval('P7D'))); );
}
$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; return $date;
} }
public function getNextEventFrom(DateTimeImmutable $date) /* : Event */ { public function getNextEventFrom(\DateTimeImmutable $date): BrettspillEvent {
return new BrettspillEvent($this->nextDate($date)); return new BrettspillEvent($this->nextDate($date));
} }
public function getPreviousEventFrom(DateTimeImmutable $date) /* : Event */ {
return new BrettspillEvent($this->prevDate($date));
}
public function getPreviousEventFrom(
\DateTimeImmutable $date,
): BrettspillEvent {
return new BrettspillEvent($this->prevDate($date));
}
} }

View File

@@ -1,65 +1,64 @@
<?php //declare(strict_types=1); <?php
declare(strict_types=1);
namespace pvv\side\social; namespace pvv\side\social;
use \pvv\side\Event; use pvv\side\Event;
use \DateInterval;
class BrettspillEvent extends Event { class BrettspillEvent extends Event {
public function getStop(): \DateTimeImmutable {
return $this->getStart()->add(new \DateInterval('PT4H1800S'));
}
public function getStop() { public function getName(): string {
return $this->getStart()->add(new DateInterval('PT4H1800S')); return 'Brettspillkveld';
} }
public function getName() /* : string */ { public function getLocation(): string {
return "Brettspillkveld"; return 'Programvareverkstedet';
} }
public function getLocation() /* : Location */ { public function getOrganiser(): string {
return "Programvareverkstedet"; return 'Programvareverkstedet';
} }
public function getOrganiser() /* : User */ { public function getURL(): string {
return "Programvareverkstedet"; return '/brettspill/';
} }
public function getURL() /* : string */ { public function getImageURL(): string {
return '/brettspill/'; return '/sosiale/brettspill.jpg';
} }
public function getImageURL() { public function getDescription(): array {
return '/sosiale/brettspill.jpg'; return [
} 'Er du en hardcore brettspillentusiast eller en nybegynner som har så vidt spilt ludo? '
. 'Da er vår brettspillkveld noe for deg! '
public function getDescription() { . 'Vi tar ut et par spill fra vårt samling of spiller så mye vi orker. Kom innom!',
return [ '',
'Er du en hardcore brettspillentusiast eller en nybegynner som har så vidt spilt ludo? '. '## Vår samling',
'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!', '* Dominion\\*',
'', '* Three cheers for master',
'## Vår samling', '* Avalon',
'', '* Hanabi',
'* Dominion\*', '* Cards aginst humanity\\*',
'* Three cheers for master', '* Citadels',
'* Avalon', '* Munchkin\\*\\*',
'* Hanabi', '* Exploding kittens\\*\\*',
'* Cards aginst humanity\*', '* Aye dark overlord',
'* Citadels', '* Settlers of catan\\*',
'* Munchkin\*\*', '* Risk\\*\\*',
'* Exploding kittens\*\*', '* og mange flere...',
'* Aye dark overlord', '',
'* Settlers of catan\*', '\\* Vi har flere ekspansjoner til spillet',
'* Risk\*\*', '',
'* og mange flere...', '\\*\\* Vi har flere varianter av spillet',
'', ];
'\* Vi har flere ekspansjoner til spillet', }
'',
'\*\* Vi har flere varianter av spillet',
];
}
public function getColor() {
return "#000";
}
public function getColor(): string {
return '#000';
}
} }

View File

@@ -1,40 +1,59 @@
<?php //declare(strict_types=1); <?php
declare(strict_types=1);
namespace pvv\side\social; namespace pvv\side\social;
use \pvv\side\Activity; use pvv\side\Activity;
use \DateTimeImmutable;
use \DateInterval;
class DriftkveldActivity implements 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')));
}
public function nextDate(DateTimeImmutable $date) { return $date;
if ($date->format('H') > 18 || $date->format('H') == 17 && $date->format('i') > 30) }
return $this->nextDate($date->add(new DateInterval('P1D'))->setTime(18, 15, 0));
$date = $date->setTime(18, 15, 0);
if ($date->format('N') != 6)
return $this->nextDate($date->add(new DateInterval('P1D')));
if ($date->format('W') % 2 - 1)
return $this->nextDate($date->add(new DateInterval('P7D')));
return $date;
}
public function prevDate(DateTimeImmutable $date) { public function prevDate(\DateTimeImmutable $date): \DateTimeImmutable {
if ($date->format('H') < 17 || $date->format('H') == 18 && $date->format('i') < 30) if (
return $this->prevDate($date->sub(new DateInterval('P1D'))->setTime(18, 15, 0)); (int) $date->format('H') < 17
$date = $date->setTime(18, 15, 0); || ((int) $date->format('H') === 18 && (int) $date->format('i') < 30)
if ($date->format('N') != 6) ) {
return $this->prevDate($date->sub(new DateInterval('P1D'))); return $this->prevDate(
if ($date->format('W') % 2 - 1) $date->sub(new \DateInterval('P1D'))->setTime(18, 15, 0),
return $this->prevDate($date->sub(new DateInterval('P7D'))); );
return $date; }
} $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')));
}
public function getNextEventFrom(DateTimeImmutable $date) /* : Event */ { return $date;
return new DriftkveldEvent($this->nextDate($date)); }
}
public function getPreviousEventFrom(DateTimeImmutable $date) /* : Event */ { public function getNextEventFrom(\DateTimeImmutable $date): DriftkveldEvent {
return new DriftkveldEvent($this->prevDate($date)); return new DriftkveldEvent($this->nextDate($date));
} }
public function getPreviousEventFrom(
\DateTimeImmutable $date,
): DriftkveldEvent {
return new DriftkveldEvent($this->prevDate($date));
}
} }

View File

@@ -1,49 +1,48 @@
<?php //declare(strict_types=1); <?php
declare(strict_types=1);
namespace pvv\side\social; namespace pvv\side\social;
use \pvv\side\Event; use pvv\side\Event;
use \DateInterval;
class DriftkveldEvent extends Event { class DriftkveldEvent extends Event {
public function getStop(): \DateTimeImmutable {
return $this->getStart()->add(new \DateInterval('PT4H1800S'));
}
public function getStop() { public function getName(): string {
return $this->getStart()->add(new DateInterval('PT4H1800S')); return 'Driftkveld';
} }
public function getName() /* : string */ { public function getLocation(): string {
return "Driftkveld"; return 'Terminalrommet / Discord / IRC';
} }
public function getLocation() /* : Location */ { public function getOrganiser(): string {
return "Terminalrommet / Discord / IRC"; return 'Torstein Nordgård-Hansen';
} }
public function getOrganiser() /* : User */ { public function getURL(): string {
return "Torstein Nordgård-Hansen"; return '/driftkveld/';
} }
public function getURL() /* : string */ { public function getImageURL(): string {
return '/driftkveld/'; return '/sosiale/drift.jpg';
} }
public function getImageURL() { public function getDescription(): array {
return '/sosiale/drift.jpg'; return [
} 'Vil du drifte?',
'Vil du være kul kis TM?',
public function getDescription() { 'Kom på driftkveld!',
return [ '',
'Vil du drifte?', 'Vi møtes annenhver uke for å ta unna driftarbeid og drikke kaffe.',
'Vil du være kul kis TM?', 'Alle PVVere er velkommene, enten de er erfarne driftere eller helt utenforstående!',
'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() {
return "#35a";
}
public function getColor(): string {
return '#35a';
}
} }

View File

@@ -1,40 +1,47 @@
<?php //declare(strict_types=1); <?php
declare(strict_types=1);
namespace pvv\side\social; namespace pvv\side\social;
use \pvv\side\Activity; use pvv\side\Activity;
use \DateTimeImmutable;
use \DateInterval;
class HackekveldActivity implements 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')));
}
public function nextDate(DateTimeImmutable $date) { return $date;
if ($date->format('H') > 18 || $date->format('H') == 17 && $date->format('i') > 30) }
return $this->nextDate($date->add(new DateInterval('P1D'))->setTime(18, 15, 0));
$date = $date->setTime(16, 15, 0);
if ($date->format('N') != 6)
return $this->nextDate($date->add(new DateInterval('P1D')));
if ($date->format('W') % 2)
return $this->nextDate($date->add(new DateInterval('P7D')));
return $date;
}
public function prevDate(DateTimeImmutable $date) { public function prevDate(\DateTimeImmutable $date): \DateTimeImmutable {
if ($date->format('H') < 17 || $date->format('H') == 18 && $date->format('i') < 30) 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)); return $this->prevDate($date->sub(new \DateInterval('P1D'))->setTime(18, 15, 0));
$date = $date->setTime(18, 15, 0); }
if ($date->format('N') != 6) $date = $date->setTime(18, 15, 0);
return $this->prevDate($date->sub(new DateInterval('P1D'))); if ((int) $date->format('N') !== 6) {
if ($date->format('W') % 2) return $this->prevDate($date->sub(new \DateInterval('P1D')));
return $this->prevDate($date->sub(new DateInterval('P7D'))); }
return $date; if ((int) $date->format('W') % 2) {
} return $this->prevDate($date->sub(new \DateInterval('P7D')));
}
public function getNextEventFrom(DateTimeImmutable $date) /* : Event */ { return $date;
return new HackekveldEvent($this->nextDate($date)); }
}
public function getPreviousEventFrom(DateTimeImmutable $date) /* : Event */ { public function getNextEventFrom(\DateTimeImmutable $date): HackekveldEvent {
return new HackekveldEvent($this->prevDate($date)); return new HackekveldEvent($this->nextDate($date));
} }
public function getPreviousEventFrom(\DateTimeImmutable $date): HackekveldEvent {
return new HackekveldEvent($this->prevDate($date));
}
} }

View File

@@ -1,45 +1,44 @@
<?php //declare(strict_types=1); <?php
declare(strict_types=1);
namespace pvv\side\social; namespace pvv\side\social;
use \pvv\side\Event; use pvv\side\Event;
use \DateInterval;
class HackekveldEvent extends Event { class HackekveldEvent extends Event {
public function getStop(): \DateTimeImmutable {
return $this->getStart()->add(new \DateInterval('PT4H1800S'));
}
public function getStop() { public function getName(): string {
return $this->getStart()->add(new DateInterval('PT4H1800S')); return 'Hackekveld';
} }
public function getName() /* : string */ { public function getLocation(): string {
return "Hackekveld"; return 'Terminalrommet / Discord / IRC';
} }
public function getLocation() /* : Location */ { public function getOrganiser(): string {
return "Terminalrommet / Discord / IRC"; return 'PVV';
} }
public function getOrganiser() /* : User */ { public function getURL(): string {
return "PVV"; return '#';
} }
public function getURL() /* : string */ { public function getImageURL(): string {
return '#'; return '/pvv-logo.png';
} }
public function getImageURL() { public function getDescription(): array {
return '/pvv-logo.png'; 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 getDescription() { ];
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() {
return "#35a";
}
public function getColor(): string {
return '#35a';
}
} }

View File

@@ -1,40 +1,48 @@
<?php //declare(strict_types=1); <?php
declare(strict_types=1);
namespace pvv\side\social; namespace pvv\side\social;
use \pvv\side\Activity; use pvv\side\Activity;
use \DateTimeImmutable; use pvv\side\Event;
use \DateInterval;
class NerdepitsaActivity implements Activity { 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')));
}
public function nextDate(DateTimeImmutable $date) { return $date;
if ($date->format('H') > 19) }
return $this->nextDate($date->add(new DateInterval('P1D'))->setTime(19, 0, 0));
$date = $date->setTime(19, 0, 0);
if ($date->format('N') != 5)
return $this->nextDate($date->add(new DateInterval('P1D')));
if ($date->format('W') % 2)
return $this->nextDate($date->add(new DateInterval('P7D')));
return $date;
}
public function prevDate(DateTimeImmutable $date) { public function prevDate(\DateTimeImmutable $date): \DateTimeImmutable {
if ($date->format('H') < 19) if ((int) $date->format('H') < 19) {
return $this->prevDate($date->sub(new DateInterval('P1D'))->setTime(19, 0, 0)); return $this->prevDate($date->sub(new \DateInterval('P1D'))->setTime(19, 0, 0));
$date = $date->setTime(19, 0, 0); }
if ($date->format('N') != 5) $date = $date->setTime(19, 0, 0);
return $this->prevDate($date->sub(new DateInterval('P1D'))); if ((int) $date->format('N') !== 5) {
if ($date->format('W') % 2) return $this->prevDate($date->sub(new \DateInterval('P1D')));
return $this->prevDate($date->sub(new DateInterval('P7D'))); }
return $date; if ((int) $date->format('W') % 2) {
} return $this->prevDate($date->sub(new \DateInterval('P7D')));
}
public function getNextEventFrom(DateTimeImmutable $date) /* : Event */ { return $date;
return new NerdepitsaEvent($this->nextDate($date)); }
}
public function getPreviousEventFrom(DateTimeImmutable $date) /* : Event */ { public function getNextEventFrom(\DateTimeImmutable $date): ?Event {
return new NerdepitsaEvent($this->prevDate($date)); return new NerdepitsaEvent($this->nextDate($date));
} }
public function getPreviousEventFrom(\DateTimeImmutable $date): ?Event {
return new NerdepitsaEvent($this->prevDate($date));
}
} }

View File

@@ -1,50 +1,49 @@
<?php //declare(strict_types=1); <?php
declare(strict_types=1);
namespace pvv\side\social; namespace pvv\side\social;
use \pvv\side\Event; use pvv\side\Event;
use \DateInterval;
class NerdepitsaEvent extends Event { class NerdepitsaEvent extends Event {
public function getStop(): \DateTimeImmutable {
return $this->getStart()->add(new \DateInterval('PT2H1800S'));
}
public function getStop() { public function getName(): string {
return $this->getStart()->add(new DateInterval('PT2H1800S')); return 'Nerdepitsa';
} }
public function getName() { public function getLocation(): string {
return "Nerdepitsa"; return 'Peppes Kjøpmansgata';
} }
public function getLocation() /* : Location */ { public function getOrganiser(): string {
return "Peppes Kjøpmansgata"; return 'Anders Christensen';
} }
public function getOrganiser() /* : User */ { public function getURL(): string {
return "Anders Christensen"; return '/nerdepitsa/';
} }
public function getURL() /* : string */ { public function getImageURL(): string {
return '/nerdepitsa/'; return '/sosiale/nerdepitsa.jpg';
} }
public function getImageURL() { public function getDescription(): array {
return '/sosiale/nerdepitsa.jpg'; 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!',
'',
public function getDescription() { '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.',
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!', '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 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.', '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!',
'', ];
'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() {
return "#c35";
}
public function getColor(): string {
return '#c35';
}
} }

View File

@@ -1,9 +1,12 @@
<?php //declare(strict_types=1); <?php
declare(strict_types=1);
namespace pvv\side\social; namespace pvv\side\social;
ini_set('date.timezone', 'Europe/Oslo'); ini_set('date.timezone', 'Europe/Oslo');
require implode(DIRECTORY_SEPARATOR, [dirname(dirname(dirname(__DIR__))), '', '_autoload.php']); require implode(\DIRECTORY_SEPARATOR, [\dirname(__DIR__, 3), '', '_autoload.php']);
$c = new AnimekveldActivity; $c = new AnimekveldActivity();
die($c->nextDate(new \DateTimeImmutable)->format(DATE_RFC2822)); exit($c->nextDate(new \DateTimeImmutable())->format(\DATE_RFC2822));

View File

@@ -1,9 +1,12 @@
<?php //declare(strict_types=1); <?php
declare(strict_types=1);
namespace pvv\side\social; namespace pvv\side\social;
ini_set('date.timezone', 'Europe/Oslo'); ini_set('date.timezone', 'Europe/Oslo');
require implode(DIRECTORY_SEPARATOR, [dirname(dirname(dirname(__DIR__))), '', '_autoload.php']); require implode(\DIRECTORY_SEPARATOR, [\dirname(__DIR__, 3), '', '_autoload.php']);
$c = new NerdepitsaActivity; $c = new NerdepitsaActivity();
die($c->prevDate(new \DateTimeImmutable)->format(DATE_RFC2822)); exit($c->prevDate(new \DateTimeImmutable())->format(\DATE_RFC2822));

View File

@@ -1,31 +0,0 @@
<?xml version="1.0"?>
<clientConfig version="1.1">
<emailProvider id="pvv.ntnu.no">
<domain>pvv.ntnu.no</domain>
<domain>pvv.org</domain>
<displayName>Programvareverkstedet</displayName>
<incomingServer type="imap">
<hostname>imap.pvv.ntnu.no</hostname>
<port>993</port>
<socketType>SSL</socketType>
<username>%EMAILLOCALPART%</username>
<authentication>password-cleartext</authentication>
</incomingServer>
<outgoingServer type="smtp">
<hostname>smtp.pvv.ntnu.no</hostname>
<port>587</port>
<socketType>STARTTLS</socketType>
<username>%EMAILLOCALPART%</username>
<authentication>password-cleartext</authentication>
<useGlobalPreferredServer>true</useGlobalPreferredServer>
</outgoingServer>
<documentation url="https://www.pvv.ntnu.no/pvv/Drift/Mail/IMAP_POP3">
<descr lang="en">Setup programvareverkstedet email user with IMAP or POP3</descr>
<descr lang="nb">Sett opp programvareverkstedet email bruker med IMAP eller POP3</descr>
</documentation>
</emailProvider>
</clientConfig>

View File

@@ -1,3 +0,0 @@
{
"m.server": "matrix.pvv.ntnu.no:443"
}

View File

@@ -1,19 +1,19 @@
<?php <?php
require __DIR__ . '/../../../src/_autoload.php'; require __DIR__ . '/../../../src/_autoload.php';
require __DIR__ . '/../../../sql_config.php'; require __DIR__ . '/../../../config.php';
$pdo = new \PDO($dbDsn, $dbUser, $dbPass); $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userManager = new \pvv\admin\UserManager($pdo); $userManager = new pvv\admin\UserManager($pdo);
require_once(__DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'); require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML_Auth_Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth(); $as->requireAuth();
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$uname = $attrs['uid'][0]; $uname = $attrs['uid'][0];
if(!$userManager->hasGroup($uname, 'aktiviteter')){ if (!$userManager->hasGroup($uname, 'aktiviteter')) {
echo 'Her har du ikke lov\'t\'å\'værra!!!'; echo 'Her har du ikke lov\'t\'å\'værra!!!';
exit(); exit;
} }
$eventID = $_GET['id']; $eventID = $_GET['id'];
@@ -25,4 +25,4 @@ $statement->execute();
header('Location: ' . $_SERVER['HTTP_REFERER']); header('Location: ' . $_SERVER['HTTP_REFERER']);
?> ?>
<a href=".?page=1">Om du ikke ble omdirigert tilbake klikk her</a> <a href=".?page=1">Om du ikke ble omdirigert tilbake klikk her</a>

View File

@@ -1,61 +1,60 @@
<?php <?php
date_default_timezone_set('Europe/Oslo'); date_default_timezone_set('Europe/Oslo');
setlocale(LC_ALL, 'nb_NO'); setlocale(\LC_ALL, 'nb_NO');
require __DIR__ . '/../../../inc/navbar.php'; require __DIR__ . '/../../../inc/navbar.php';
require __DIR__ . '/../../../src/_autoload.php'; require __DIR__ . '/../../../src/_autoload.php';
require __DIR__ . '/../../../sql_config.php'; require __DIR__ . '/../../../config.php';
$pdo = new \PDO($dbDsn, $dbUser, $dbPass); $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userManager = new \pvv\admin\UserManager($pdo); $userManager = new pvv\admin\UserManager($pdo);
require_once(__DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'); require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML_Auth_Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth(); $as->requireAuth();
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$uname = $attrs['uid'][0]; $uname = $attrs['uid'][0];
$name = $attrs['cn'][0]; $name = $attrs['cn'][0];
if(!$userManager->hasGroup($uname, 'aktiviteter')){ if (!$userManager->hasGroup($uname, 'aktiviteter')) {
echo 'Her har du ikke lov\'t\'å\'værra!!!'; echo 'Her har du ikke lov\'t\'å\'værra!!!';
exit(); exit;
} }
$customActivity = new \pvv\side\DBActivity($pdo); $customActivity = new pvv\side\DBActivity($pdo);
$new = 0; $new = 0;
if(isset($_GET['new'])){ if (isset($_GET['new'])) {
$new = $_GET['new']; $new = $_GET['new'];
} }
$eventID = 0; $eventID = 0;
if(isset($_GET['id'])){ if (isset($_GET['id'])) {
$eventID = $_GET['id']; $eventID = $_GET['id'];
}else if($new == 0){ } elseif ($new == 0) {
echo "\nID not set"; echo "\nID not set";
exit(); exit;
} }
$today = new DateTimeImmutable; $today = new DateTimeImmutable();
$today = $today->setTime(18, 15); $today = $today->setTime(18, 15);
$defaultStart = $today->format("Y-m-d H:15:00"); $defaultStart = $today->format('Y-m-d H:15:00');
$inTwoHours = $today->add(new DateInterval('PT1H45M')); $inTwoHours = $today->add(new DateInterval('PT1H45M'));
$defaultEnd = $inTwoHours->format("Y-m-d H:00:00"); $defaultEnd = $inTwoHours->format('Y-m-d H:00:00');
$event;
if($new == 0){ if ($new == 0) {
$event = $customActivity->getEventByID($eventID); $event = $customActivity->getEventByID($eventID);
} } else {
else { $event = new pvv\side\SimpleEvent(
$event = new \pvv\side\SimpleEvent( 0,
0, '',
'', $today,
$today, $inTwoHours,
$inTwoHours, '',
'', '',
'', ''
'' );
);
} }
@@ -86,49 +85,49 @@ else {
<h2>Aktivietsadministrasjon</h2> <h2>Aktivietsadministrasjon</h2>
<hr class="ruler"> <hr class="ruler">
<h2><?= ($new == 1 ? "Ny hendelse" : "Rediger hendelse"); ?></h2> <h2><?php echo $new == 1 ? 'Ny hendelse' : 'Rediger hendelse'; ?></h2>
<form action="update.php", method="post" class="gridsplit fullwidth_inputs"> <form action="update.php", method="post" class="gridsplit fullwidth_inputs">
<div class="gridl"> <div class="gridl">
<p class="subtitle">Tittel</p> <p class="subtitle">Tittel</p>
<input type="text" name="title" value="<?= $event->getName() ?>" class="boxinput" required placeholder="En kul hendelse"><br> <input type="text" name="title" value="<?php echo $event->getName(); ?>" class="boxinput" required placeholder="En kul hendelse"><br>
<div class="gridsplit5050"> <div class="gridsplit5050">
<div class="gridl"> <div class="gridl">
<p class="subtitle">Arrangør</p> <p class="subtitle">Arrangør</p>
<input type="text" name="organiser" value="<?= $event->getOrganiser() ?>" class="boxinput" required placeholder="<?= $name ?>"><br> <input type="text" name="organiser" value="<?php echo $event->getOrganiser(); ?>" class="boxinput" required placeholder="<?php echo $name; ?>"><br>
</div> </div>
<div class="gridr noborder"> <div class="gridr noborder">
<p class="subtitle">Sted</p> <p class="subtitle">Sted</p>
<input type="text" name="location" value="<?= $event->getLocation() ?>" class="boxinput" required placeholder="Terminalrommet"><br> <input type="text" name="location" value="<?php echo $event->getLocation(); ?>" class="boxinput" required placeholder="Terminalrommet"><br>
</div> </div>
</div> </div>
<p class="subtitle">Beskrivelse (<i>markdown</i>)</p> <p class="subtitle">Beskrivelse (<i>markdown</i>)</p>
<textarea name="desc" rows="8" class="boxinput" placeholder="Beskrivese" required><?= implode($event->getDescription(), "\n"); ?></textarea> <textarea name="desc" rows="8" class="boxinput" placeholder="Beskrivelse" required><?php echo implode("\n", $event->getDescription()); ?></textarea>
</div> </div>
<div class="gridr" style="line-height: 1.3em;"> <div class="gridr" style="line-height: 1.3em;">
<h4>Starttid</h4><br> <h4>Starttid</h4><br>
<i>Måned:</i><br> <i>Måned:</i><br>
<input name="start_mon" type="month" class="boxinput" required value="<?= $event->getStart()->format('Y-m') ?>"><br> <input name="start_mon" type="month" class="boxinput" required value="<?php echo $event->getStart()->format('Y-m'); ?>"><br>
<i>Dag:</i><br> <i>Dag:</i><br>
<input name="start_day" type="number" min="1" max="31" required class="boxinput" value="<?= $event->getStart()->format('d') ?>"><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> <i>Klokkeslett:</i><br>
<input name="start_time" type="time" class="boxinput" required value="<?= $event->getStart()->format('H:i:s') ?>"><br> <input name="start_time" type="time" class="boxinput" required value="<?php echo $event->getStart()->format('H:i:s'); ?>"><br>
<br> <br>
<h4>Varighet</h4><br> <h4>Varighet</h4><br>
<?php $diff = $event->getStart()->diff($event->getStop()); ?> <?php $diff = $event->getStart()->diff($event->getStop()); ?>
<i>Timer:</i><br> <i>Timer:</i><br>
<input name="lasts_hours" type="number" min="0" class="boxinput" required value="<?= $diff->h ?>"><br> <input name="lasts_hours" type="number" min="0" class="boxinput" required value="<?php echo $diff->h; ?>"><br>
<i>Minutter:</i><br> <i>Minutter:</i><br>
<input name="lasts_minutes" type="number" min="0" max="59" class="boxinput" required value="<?= $diff->i ?>"><br> <input name="lasts_minutes" type="number" min="0" max="59" class="boxinput" required value="<?php echo $diff->i; ?>"><br>
</div> </div>
<input type="hidden" name="id" value="<?= $event->getID() ?>" /> <input type="hidden" name="id" value="<?php echo $event->getID(); ?>" />
<div class="allgrids" style="margin-top: 2em;"> <div class="allgrids" style="margin-top: 2em;">
<hr class="ruler"> <hr class="ruler">
@@ -136,7 +135,7 @@ else {
</div> </div>
</form> </form>
<p> <p>
</main> </main>

View File

@@ -1,49 +1,47 @@
<?php <?php
date_default_timezone_set('Europe/Oslo'); date_default_timezone_set('Europe/Oslo');
setlocale(LC_ALL, 'nb_NO'); setlocale(\LC_ALL, 'nb_NO');
require __DIR__ . '/../../../inc/navbar.php'; require __DIR__ . '/../../../inc/navbar.php';
require __DIR__ . '/../../../src/_autoload.php'; require __DIR__ . '/../../../src/_autoload.php';
require __DIR__ . '/../../../sql_config.php'; require __DIR__ . '/../../../config.php';
$pdo = new \PDO($dbDsn, $dbUser, $dbPass); $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userManager = new \pvv\admin\UserManager($pdo); $userManager = new pvv\admin\UserManager($pdo);
require_once(__DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'); require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML_Auth_Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth(); $as->requireAuth();
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$uname = $attrs['uid'][0]; $uname = $attrs['uid'][0];
if(!$userManager->hasGroup($uname, 'aktiviteter')){ if (!$userManager->hasGroup($uname, 'aktiviteter')) {
echo 'Her har du ikke lov\'t\'å\'værra!!!'; echo 'Her har du ikke lov\'t\'å\'værra!!!';
exit(); exit;
} }
$customActivity = new \pvv\side\DBActivity($pdo); $customActivity = new pvv\side\DBActivity($pdo);
$events = $customActivity->getAllEvents(); $events = $customActivity->getAllEvents();
$page = 1; $page = 1;
if(isset($_GET['page'])){ if (isset($_GET['page'])) {
$page = $_GET['page']; $page = $_GET['page'];
} }
$filterTitle = ''; $filterTitle = '';
if(isset($_GET['title'])){ if (isset($_GET['title'])) {
$filterTitle = $_GET['title']; $filterTitle = $_GET['title'];
} }
$filterOrganiser = ''; $filterOrganiser = '';
if(isset($_GET['organiser'])){ if (isset($_GET['organiser'])) {
$filterOrganiser = $_GET['organiser']; $filterOrganiser = $_GET['organiser'];
} }
// filter // filter
$events = array_values(array_filter( $events = array_values(array_filter(
$events, $events,
function($event) use ($filterTitle, $filterOrganiser){ static fn($event) => (preg_match('/.*' . $filterTitle . '.*/i', $event->getName()) && preg_match('/.*' . $filterOrganiser . '.*/i', $event->getOrganiser()))
return (preg_match('/.*'.$filterTitle.'.*/i', $event->getName()) and preg_match('/.*'.$filterOrganiser.'.*/i', $event->getOrganiser()));
}
)); ));
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
@@ -62,7 +60,7 @@ $events = array_values(array_filter(
<header>Aktivitets&shy;administrasjons&shy;verk&shy;stedet</header> <header>Aktivitets&shy;administrasjons&shy;verk&shy;stedet</header>
<body> <body>
<nav> <nav>
<?php echo navbar(2, 'admin'); ?> <?php echo navbar(2, 'admin'); ?>
<?php echo loginbar(null, $pdo); ?> <?php echo loginbar(null, $pdo); ?>
@@ -79,53 +77,53 @@ $events = array_values(array_filter(
<ul class="event-list"> <ul class="event-list">
<?php <?php
$counter = 0; $counter = 0;
$pageLimit = 10; $pageLimit = 10;
for($i = ($pageLimit * ($page - 1)); $i < count($events) ;$i++){ for ($i = ($pageLimit * ($page - 1)); $i < count($events); ++$i) {
if($counter == $pageLimit){ if ($counter == $pageLimit) {
break; break;
} }
$event = $events[$i]; $event = $events[$i];
$eventID = $event->getID(); $eventID = $event->getID();
?> ?>
<li> <li>
<div class="event admin"> <div class="event admin">
<div class="event-info"> <div class="event-info">
<h3 class="no-chin"><?= $event->getName() . " (ID: " . $eventID . ")"; ?></h3> <h3 class="no-chin"><?php echo $event->getName() . ' (ID: ' . $eventID . ')'; ?></h3>
<p class="subnote"> <p class="subnote">
<?= $event->getStart()->format("(Y-m-d H:i:s)") . " - " . $event->getStop()->format("(Y-m-d H:i:s)"); ?> <?php echo $event->getStart()->format('(Y-m-d H:i:s)') . ' - ' . $event->getStop()->format('(Y-m-d H:i:s)'); ?>
</p> </p>
<?php <?php
$Parsedown = new \Parsedown(); $Parsedown = new Parsedown();
echo $Parsedown->text(implode("\n", $event->getDescription())); echo $Parsedown->text(implode("\n", $event->getDescription()));
?> ?>
</div> </div>
<div class="event-actions"> <div class="event-actions">
<a class="btn" href="edit.php?id=<?= $eventID ?>">Rediger</a><br> <a class="btn" href="edit.php?id=<?php echo $eventID; ?>">Rediger</a><br>
<a class="btn" href="delete.php?id=<?= $eventID ?>" onclick="return confirm('Knallsikker? (ID: <?= $eventID ?>)');">Slett</a> <a class="btn" href="delete.php?id=<?php echo $eventID; ?>" onclick="return confirm('Knallsikker? (ID: <?php echo $eventID; ?>)');">Slett</a>
</div> </div>
</div> </div>
</li> </li>
<?php <?php
$counter++; ++$counter;
} }
?> ?>
</ul> </ul>
<?php <?php
if($page != 1){ if ($page != 1) {
echo '<a class="btn float-left" href="?page=' . ($page - 1) . '&title=' . urlencode($filterTitle) . '&organiser=' . urlencode($filterOrganiser) . '">Forrige side</a>'; echo '<a class="btn float-left" href="?page=' . ($page - 1) . '&title=' . urlencode($filterTitle) . '&organiser=' . urlencode($filterOrganiser) . '">Forrige side</a>';
} }
if(($counter == $pageLimit) and (($pageLimit * $page) < count($events))){ 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>'; echo '<a class="btn float-right" href="?page=' . ($page + 1) . '&title=' . urlencode($filterTitle) . '&organiser=' . urlencode($filterOrganiser) . '">Neste side</a>';
} }
?> ?>
</div> </div>
<div class="gridr"> <div class="gridr">
@@ -134,9 +132,9 @@ $events = array_values(array_filter(
<h2>Filter</h2> <h2>Filter</h2>
<form action="." method="get"> <form action="." method="get">
<p class="no-chin">Navn</p> <p class="no-chin">Navn</p>
<?= '<input type="text" name="title" class="boxinput" value="' . $filterTitle . '">' ?><br> <?php echo '<input type="text" name="title" class="boxinput" value="' . $filterTitle . '">'; ?><br>
<p class="no-chin">Organisator</p> <p class="no-chin">Organisator</p>
<?= '<input type="text" name="organiser" class="boxinput" value="' . $filterOrganiser . '">' ?><br> <?php echo '<input type="text" name="organiser" class="boxinput" value="' . $filterOrganiser . '">'; ?><br>
<div style="margin-top: 2em;"> <div style="margin-top: 2em;">
<input type="submit" class="btn" value="Filtrer"></input> <input type="submit" class="btn" value="Filtrer"></input>

View File

@@ -1,45 +1,45 @@
<?php <?php
date_default_timezone_set('Europe/Oslo'); date_default_timezone_set('Europe/Oslo');
setlocale(LC_ALL, 'nb_NO'); setlocale(\LC_ALL, 'nb_NO');
require __DIR__ . '/../../../src/_autoload.php'; require __DIR__ . '/../../../src/_autoload.php';
require __DIR__ . '/../../../sql_config.php'; require __DIR__ . '/../../../config.php';
$pdo = new \PDO($dbDsn, $dbUser, $dbPass); $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userManager = new \pvv\admin\UserManager($pdo); $userManager = new pvv\admin\UserManager($pdo);
require_once(__DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'); require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML_Auth_Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth(); $as->requireAuth();
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$uname = $attrs['uid'][0]; $uname = $attrs['uid'][0];
if(!$userManager->hasGroup($uname, 'aktiviteter')){ if (!$userManager->hasGroup($uname, 'aktiviteter')) {
echo 'Her har du ikke lov\'t\'å\'værra!!!'; echo 'Her har du ikke lov\'t\'å\'værra!!!';
exit(); exit;
} }
if((!isset($_POST['title'])) if ((!isset($_POST['title']))
or (!isset($_POST['desc'])) || (!isset($_POST['desc']))
or (!isset($_POST['organiser'])) || (!isset($_POST['organiser']))
or (!isset($_POST['location'])) || (!isset($_POST['location']))
or (!isset($_POST['start_mon'])) || (!isset($_POST['start_mon']))
or (!isset($_POST['start_day'])) || (!isset($_POST['start_day']))
or (!isset($_POST['start_time'])) || (!isset($_POST['start_time']))
or (!isset($_POST['lasts_hours'])) || (!isset($_POST['lasts_hours']))
or (!isset($_POST['lasts_minutes']))) { || (!isset($_POST['lasts_minutes']))) {
header('Location: ' . $_SERVER['HTTP_REFERER']); header('Location: ' . $_SERVER['HTTP_REFERER']);
exit(); exit;
} }
$id = 0; $id = 0;
if(isset($_POST['id'])){ if (isset($_POST['id'])) {
$id = $_POST['id']; $id = $_POST['id'];
} }
$title = $_POST['title']; $title = $_POST['title'];
$desc = $_POST['desc']; $desc = $_POST['desc'];
//$start = $_POST['start']; // $start = $_POST['start'];
//$stop = $_POST['end']; // $stop = $_POST['end'];
$organiser = $_POST['organiser']; $organiser = $_POST['organiser'];
$location = $_POST['location']; $location = $_POST['location'];
@@ -50,12 +50,12 @@ $date_part_lasts_hours = $_POST['lasts_hours'];
$date_part_lasts_minutes = $_POST['lasts_minutes']; $date_part_lasts_minutes = $_POST['lasts_minutes'];
while (strlen($date_part_start_day) < 2) { while (strlen($date_part_start_day) < 2) {
$date_part_start_day = "0" . $date_part_start_day; $date_part_start_day = '0' . $date_part_start_day;
} }
$start = ($date_part_start_mon . "-" . $date_part_start_day . " " . $date_part_start_time); $start = ($date_part_start_mon . '-' . $date_part_start_day . ' ' . $date_part_start_time);
if (sizeof(explode(":", $date_part_start_time))==2) { if (count(explode(':', $date_part_start_time)) == 2) {
$start .= ":00"; $start .= ':00';
} }
$start_date = DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $start); $start_date = DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $start);
@@ -64,32 +64,49 @@ $start = $start_date->format('Y-m-d H:i:s');
$stop = $stop_date->format('Y-m-d H:i:s'); $stop = $stop_date->format('Y-m-d H:i:s');
if ($start_date >= $stop_date) { if ($start_date >= $stop_date) {
echo 'Invalid dates. End date must come after the start date!'; echo 'Invalid dates. End date must come after the start date!';
exit(); exit;
} }
$statement;
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->bindParam(':title', $title, PDO::PARAM_STR); if ($id == 0) {
$statement->bindParam(':desc', $desc, PDO::PARAM_STR); $query = '
$statement->bindParam(':start', $start, PDO::PARAM_STR); INSERT INTO
$statement->bindParam(':stop', $stop, PDO::PARAM_STR); events(name, start, stop, organiser, location, description)
$statement->bindParam(':organiser', $organiser, PDO::PARAM_STR); VALUES
$statement->bindParam(':loc', $location, PDO::PARAM_STR); (:title, :start, :stop, :organiser, :loc, :desc)
}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 = $pdo->prepare($query);
$statement->bindParam(':title', $title, PDO::PARAM_STR); $statement->bindParam(':title', $title, PDO::PARAM_STR);
$statement->bindParam(':desc', $desc, PDO::PARAM_STR); $statement->bindParam(':desc', $desc, PDO::PARAM_STR);
$statement->bindParam(':start', $start, PDO::PARAM_STR); $statement->bindParam(':start', $start, PDO::PARAM_STR);
$statement->bindParam(':stop', $stop, PDO::PARAM_STR); $statement->bindParam(':stop', $stop, PDO::PARAM_STR);
$statement->bindParam(':organiser', $organiser, PDO::PARAM_STR); $statement->bindParam(':organiser', $organiser, PDO::PARAM_STR);
$statement->bindParam(':loc', $location, PDO::PARAM_STR); $statement->bindParam(':loc', $location, PDO::PARAM_STR);
$statement->bindParam(':id', $id, PDO::PARAM_INT); } 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->bindParam(':title', $title, PDO::PARAM_STR);
$statement->bindParam(':desc', $desc, PDO::PARAM_STR);
$statement->bindParam(':start', $start, PDO::PARAM_STR);
$statement->bindParam(':stop', $stop, PDO::PARAM_STR);
$statement->bindParam(':organiser', $organiser, PDO::PARAM_STR);
$statement->bindParam(':loc', $location, PDO::PARAM_STR);
$statement->bindParam(':id', $id, PDO::PARAM_INT);
} }
$statement->execute(); $statement->execute();

View File

@@ -1,28 +1,28 @@
<?php <?php
ini_set('display_errors', '1'); ini_set('display_errors', '1');
date_default_timezone_set('Europe/Oslo'); date_default_timezone_set('Europe/Oslo');
setlocale(LC_ALL, 'nb_NO'); setlocale(\LC_ALL, 'nb_NO');
error_reporting(E_ALL); error_reporting(\E_ALL);
require __DIR__ . '/../../../inc/navbar.php'; require __DIR__ . '/../../../inc/navbar.php';
require __DIR__ . '/../../../src/_autoload.php'; require __DIR__ . '/../../../src/_autoload.php';
require __DIR__ . '/../../../sql_config.php'; require __DIR__ . '/../../../config.php';
require_once(__DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'); require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML_Auth_Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$pdo = new \PDO($dbDsn, $dbUser, $dbPass); $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userManager = new \pvv\admin\UserManager($pdo); $userManager = new pvv\admin\UserManager($pdo);
require_once(__DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'); require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML_Auth_Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth(); $as->requireAuth();
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$uname = $attrs['uid'][0]; $uname = $attrs['uid'][0];
if(!$userManager->isAdmin($uname)){ if (!$userManager->isAdmin($uname)) {
echo 'Her har du ikke lov\'t\'å\'værra!!!'; echo 'Her har du ikke lov\'t\'å\'værra!!!';
exit(); exit;
} }
$users = $userManager->getAllUserData(); $users = $userManager->getAllUserData();
@@ -59,38 +59,38 @@ $users = $userManager->getAllUserData();
</tr> </tr>
<?php <?php
$users_to_update = array(); $users_to_update = [];
foreach($users as $i => $data){ foreach ($users as $i => $data) {
$uname = $data['name']; $uname = $data['name'];
$groupFlag = $userManager->getUsergroups($uname); $groupFlag = $userManager->getUsergroups($uname);
array_push($users_to_update, $uname); $users_to_update[] = $uname;
?> ?>
<tr> <tr>
<td><?= $uname ?></td> <td><?php echo $uname; ?></td>
<?php <?php
foreach($userManager->usergroups as $name => $group){ foreach ($userManager->usergroups as $name => $group) {
echo '<td><input type="checkbox" ' . (($groupFlag & $group) ? 'checked' : '') . ' name="' . $uname . '_' . $name . '" class="usergroupcheckbox">' . $name . '</td>'; echo '<td><input type="checkbox" ' . (($groupFlag & $group) ? 'checked' : '') . ' name="' . $uname . '_' . $name . '" class="usergroupcheckbox">' . $name . '</td>';
} }
?> ?>
</tr> </tr>
<?php <?php
} }
foreach($users_to_update as $uname) { foreach ($users_to_update as $uname) {
echo '<input type="hidden" name="user_to_update" value="' . $uname . '" />'; echo '<input type="hidden" name="user_to_update" value="' . $uname . '" />';
} }
?> ?>
<tr class="newuserrow"> <tr class="newuserrow">
<td class="newuserelement"><input type="text" name="newuser" class="newuserinput"></td> <td class="newuserelement"><input type="text" name="newuser" class="newuserinput"></td>
<?php <?php
foreach($userManager->usergroups as $name => $group){ foreach ($userManager->usergroups as $name => $group) {
echo '<td><input type="checkbox" name="newuser_' . $name . '" class="usergroupcheckbox">' . $name . '</td>'; echo '<td><input type="checkbox" name="newuser_' . $name . '" class="usergroupcheckbox">' . $name . '</td>';
} }
?> ?>
</tr> </tr>
</table> </table>
<input type="submit" class="btn" value="Lagre"> <input type="submit" class="btn" value="Lagre">

View File

@@ -1,72 +1,73 @@
<?php <?php
ini_set('display_errors', '1'); ini_set('display_errors', '1');
date_default_timezone_set('Europe/Oslo'); date_default_timezone_set('Europe/Oslo');
setlocale(LC_ALL, 'nb_NO'); setlocale(\LC_ALL, 'nb_NO');
error_reporting(E_ALL); error_reporting(\E_ALL);
require __DIR__ . '/../../../src/_autoload.php'; require __DIR__ . '/../../../src/_autoload.php';
require __DIR__ . '/../../../sql_config.php'; require __DIR__ . '/../../../config.php';
$pdo = new \PDO($dbDsn, $dbUser, $dbPass); $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userManager = new \pvv\admin\UserManager($pdo); $userManager = new pvv\admin\UserManager($pdo);
require_once(__DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'); require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML_Auth_Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth(); $as->requireAuth();
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$uname = $attrs['uid'][0]; $uname = $attrs['uid'][0];
if(!$userManager->isAdmin($uname)){ if (!$userManager->isAdmin($uname)) {
echo 'Her har du ikke lov\'t\'å\'værra!!!'; echo 'Her har du ikke lov\'t\'å\'værra!!!';
exit(); exit;
} }
$newUser;
if(isset($_POST['newuser'])){ if (isset($_POST['newuser'])) {
$newUser = $_POST['newuser']; $newUser = $_POST['newuser'];
unset($_POST['newuser']); unset($_POST['newuser']);
} }
//$updatingUsers = explode('_', $_POST['users']); // $updatingUsers = explode('_', $_POST['users']);
$updatingUsers = array(); $updatingUsers = [];
foreach ($_POST as $key => $value) { if ($key === "user_to_update") { foreach ($_POST as $key => $value) {
array_push($updatingUsers, $value); if ($key === 'user_to_update') {
} $updatingUsers[] = $value;
}
} }
unset($_POST['user_to_update']); unset($_POST['user_to_update']);
// 2d array of usernames and their corresponding group flags // 2d array of usernames and their corresponding group flags
$userFlags = []; $userFlags = [];
if($newUser){ if ($newUser) {
$userFlags[$newUser] = 0; $userFlags[$newUser] = 0;
} }
foreach($_POST as $namegroup => $info){ foreach ($_POST as $namegroup => $info) {
$data = explode('_', $namegroup); $data = explode('_', $namegroup);
$group = array_pop($data); $group = array_pop($data);
$uname = implode("_", $data); $uname = implode('_', $data);
if($uname == 'newuser'){ if ($uname == 'newuser') {
if(!$newUser){ if (!$newUser) {
continue; continue;
} }
$uname = $newUser; $uname = $newUser;
} }
if(!isset($userFlags[$uname])){ if (!isset($userFlags[$uname])) {
$userFlags[$uname] = 0; $userFlags[$uname] = 0;
} }
$userFlags[$uname] = ($userFlags[$uname] | $userManager->usergroups[$group]); $userFlags[$uname] = ($userFlags[$uname] | $userManager->usergroups[$group]);
} }
foreach($updatingUsers as $uname) { foreach ($updatingUsers as $uname) {
if(!array_key_exists($uname, $userFlags)){ if (!array_key_exists($uname, $userFlags)) {
$userFlags[$uname] = 0; $userFlags[$uname] = 0;
} }
} }
foreach($userFlags as $uname => $flag){ foreach ($userFlags as $uname => $flag) {
$userManager->setGroups($uname, $flag); $userManager->setGroups($uname, $flag);
} }
header('Location: .'); header('Location: .');

View File

@@ -1,11 +1,11 @@
<?php <?php
require_once dirname(dirname(__DIR__)) . implode(DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']); require_once dirname(__DIR__, 2) . implode(\DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']);
$pdo = new \PDO($dbDsn, $dbUser, $dbPass); $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userManager = new \pvv\admin\UserManager($pdo); $userManager = new pvv\admin\UserManager($pdo);
$as = new SimpleSAML_Auth_Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth(); $as->requireAuth();
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$uname = $attrs['uid'][0]; $uname = $attrs['uid'][0];
@@ -14,10 +14,10 @@ $isAdmin = $userManager->isAdmin($uname);
$projectGroup = $userManager->hasGroup($uname, 'prosjekt'); $projectGroup = $userManager->hasGroup($uname, 'prosjekt');
$activityGroup = $userManager->hasGroup($uname, 'aktiviteter'); $activityGroup = $userManager->hasGroup($uname, 'aktiviteter');
if(!($isAdmin | $projectGroup | $activityGroup)){ if (!($isAdmin | $projectGroup | $activityGroup)) {
header('Content-Type: text/plain', true, 403); header('Content-Type: text/plain', true, 403);
echo "Her har du ikke lov't'å'værra!!!\r\n"; echo "Her har du ikke lov't'å'værra!!!\r\n";
exit(); exit;
} }
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
@@ -44,23 +44,21 @@ if(!($isAdmin | $projectGroup | $activityGroup)){
<main> <main>
<h2>Administrasjon</h2> <h2>Administrasjon</h2>
<ul class="tools"> <ul class="tools">
<?php <?php if ($isAdmin | $activityGroup) : ?>
if($isAdmin | $activityGroup){ <li><a class="btn" href="aktiviteter/?page=1">Aktiviteter/Hendelser</a></li>
echo '<li><a class="btn" href="aktiviteter/?page=1">Aktiviteter/Hendelser</a></li>'; <?php endif ?>
}
if($isAdmin | $projectGroup){ <?php if ($isAdmin | $projectGroup) : ?>
echo '<li><a class="btn" href="prosjekter/">Prosjekter</a></li>'; <li><a class="btn" href="prosjekter/?page=1">Prosjekter</a></li>
} <?php endif ?>
if($isAdmin) { <?php if ($isAdmin) : ?>
echo '<li><a class="btn" href="motd/">Dagens melding</a></li>'; <li><a class="btn" href="motd/">Dagens melding</a></li>
} <?php endif ?>
if($isAdmin){ <?php if ($isAdmin) : ?>
echo '<li><a class="btn" href="brukere/">Brukerrettigheter</a></li>'; <li><a class="btn" href="brukere/">Brukerrettigheter</a></li>
} <?php endif ?>
?>
<ul> <ul>
</main> </main>
</body> </body>

View File

@@ -1,31 +1,31 @@
<?php <?php
ini_set('display_errors', '1'); ini_set('display_errors', '1');
date_default_timezone_set('Europe/Oslo'); date_default_timezone_set('Europe/Oslo');
setlocale(LC_ALL, 'no_NO'); setlocale(\LC_ALL, 'no_NO');
error_reporting(E_ALL); error_reporting(\E_ALL);
require __DIR__ . '/../../../inc/navbar.php'; require __DIR__ . '/../../../inc/navbar.php';
require __DIR__ . '/../../../src/_autoload.php'; require __DIR__ . '/../../../src/_autoload.php';
require __DIR__ . '/../../../sql_config.php'; require __DIR__ . '/../../../config.php';
require_once(__DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'); require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML_Auth_Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$pdo = new \PDO($dbDsn, $dbUser, $dbPass); $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userManager = new \pvv\admin\UserManager($pdo); $userManager = new pvv\admin\UserManager($pdo);
require_once(__DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'); require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML_Auth_Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth(); $as->requireAuth();
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$uname = $attrs['uid'][0]; $uname = $attrs['uid'][0];
if(!$userManager->isAdmin($uname)){ if (!$userManager->isAdmin($uname)) {
echo 'Her har du ikke lov\'t\'å\'værra!!!'; echo 'Her har du ikke lov\'t\'å\'værra!!!';
exit(); exit;
} }
$motdfetcher = new \pvv\side\MOTD($pdo); $motdfetcher = new pvv\side\MOTD($pdo);
$motd = $motdfetcher->getMOTD(); $motd = $motdfetcher->getMOTD();
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
@@ -56,15 +56,15 @@ $motd = $motdfetcher->getMOTD();
<form action="update.php", method="post"> <form action="update.php", method="post">
<p class="subtitle no-chin">Tittel</p> <p class="subtitle no-chin">Tittel</p>
<p class="subnote">Ikke nødvendig</p> <p class="subnote">Ikke nødvendig</p>
<input type="text" name="title" value="<?= $motd['title'] ?>" class="boxinput" style="width:66%;"><br> <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> <p class="subtitle no-chin">Innhold (<i>markdown</i>)</p>
<textarea name="content" style="width:100%" rows="8" class="boxinput"><?= implode("\n", $motd["content"]) ?></textarea> <textarea name="content" style="width:100%" rows="8" class="boxinput"><?php echo $motd->getContentAsString(); ?></textarea>
<div style="margin-top: 2em;"> <div style="margin-top: 2em;">
<hr class="ruler"> <hr class="ruler">
<?= '<input type="submit" class="btn" value="Lagre endringer"></a>'; ?> <?php echo '<input type="submit" class="btn" value="Lagre endringer"></a>'; ?>
</div> </div>
</form> </form>
</main> </main>

View File

@@ -1,32 +1,32 @@
<?php <?php
ini_set('display_errors', '1'); ini_set('display_errors', '1');
date_default_timezone_set('Europe/Oslo'); date_default_timezone_set('Europe/Oslo');
setlocale(LC_ALL, 'no_NO'); setlocale(\LC_ALL, 'no_NO');
error_reporting(E_ALL); error_reporting(\E_ALL);
require __DIR__ . '/../../../src/_autoload.php'; require __DIR__ . '/../../../src/_autoload.php';
require __DIR__ . '/../../../sql_config.php'; require __DIR__ . '/../../../config.php';
$pdo = new \PDO($dbDsn, $dbUser, $dbPass); $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userManager = new \pvv\admin\UserManager($pdo); $userManager = new pvv\admin\UserManager($pdo);
require_once(__DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'); require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML_Auth_Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth(); $as->requireAuth();
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$uname = $attrs['uid'][0]; $uname = $attrs['uid'][0];
if(!isset($_POST['title']) or !isset($_POST['content'])){ if (!isset($_POST['title']) || !isset($_POST['content'])) {
header('Location: ' . $_SERVER['HTTP_REFERER']); header('Location: ' . $_SERVER['HTTP_REFERER']);
exit(); exit;
} }
if(!$userManager->isAdmin($uname)){ if (!$userManager->isAdmin($uname)) {
echo 'Her har du ikke lov\'t\'å\'værra!!!'; echo 'Her har du ikke lov\'t\'å\'værra!!!';
exit(); exit;
} }
$motdfetcher = new \pvv\side\MOTD($pdo); $motdfetcher = new pvv\side\MOTD($pdo);
$motdfetcher->setMOTD($_POST['title'], $_POST['content']); $motdfetcher->setMOTD($_POST['title'], $_POST['content']);
header('Location: .'); header('Location: .');

View File

@@ -1,19 +1,19 @@
<?php <?php
require __DIR__ . '/../../../src/_autoload.php'; require __DIR__ . '/../../../src/_autoload.php';
require __DIR__ . '/../../../sql_config.php'; require __DIR__ . '/../../../config.php';
$pdo = new \PDO($dbDsn, $dbUser, $dbPass); $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userManager = new \pvv\admin\UserManager($pdo); $userManager = new pvv\admin\UserManager($pdo);
require_once(__DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'); require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML_Auth_Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth(); $as->requireAuth();
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$uname = $attrs['uid'][0]; $uname = $attrs['uid'][0];
if(!$userManager->hasGroup($uname, 'prosjekt')){ if (!$userManager->hasGroup($uname, 'prosjekt')) {
echo 'Her har du ikke lov\'t\'å\'værra!!!'; echo 'Her har du ikke lov\'t\'å\'værra!!!';
exit(); exit;
} }
$projectID = $_GET['id']; $projectID = $_GET['id'];
@@ -25,4 +25,4 @@ $statement->execute();
header('Location: ' . $_SERVER['HTTP_REFERER']); header('Location: ' . $_SERVER['HTTP_REFERER']);
?> ?>
<a href=".?page=1">Om du ikke ble omdirigert tilbake klikk her</a> <a href=".?page=1">Om du ikke ble omdirigert tilbake klikk her</a>

View File

@@ -1,64 +1,64 @@
<?php <?php
date_default_timezone_set('Europe/Oslo'); date_default_timezone_set('Europe/Oslo');
setlocale(LC_ALL, 'nb_NO'); setlocale(\LC_ALL, 'nb_NO');
require __DIR__ . '/../../../inc/navbar.php'; require __DIR__ . '/../../../inc/navbar.php';
require __DIR__ . '/../../../src/_autoload.php'; require __DIR__ . '/../../../src/_autoload.php';
require __DIR__ . '/../../../sql_config.php'; require __DIR__ . '/../../../config.php';
$pdo = new \PDO($dbDsn, $dbUser, $dbPass); $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userManager = new \pvv\admin\UserManager($pdo); $userManager = new pvv\admin\UserManager($pdo);
require_once(__DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'); require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML_Auth_Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth(); $as->requireAuth();
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$uname = $attrs['uid'][0]; $uname = $attrs['uid'][0];
if(!$userManager->hasGroup($uname, 'prosjekt')){ if (!$userManager->hasGroup($uname, 'prosjekt')) {
echo 'Her har du ikke lov\'t\'å\'værra!!!'; echo 'Her har du ikke lov\'t\'å\'værra!!!';
exit(); exit;
} }
$projectManager = new \pvv\side\ProjectManager($pdo); $projectManager = new pvv\side\ProjectManager($pdo);
$projects = $projectManager->getAll(); $projects = $projectManager->getAll();
$new = 0; $new = 0;
if(isset($_GET['new'])){ if (isset($_GET['new'])) {
$new = $_GET['new']; $new = $_GET['new'];
} }
$projectID = 0; $projectID = 0;
if(isset($_GET['id'])){ if (isset($_GET['id'])) {
$projectID = $_GET['id']; $projectID = $_GET['id'];
}else if($new == 0){ } elseif ($new == 0) {
echo "\nID not set"; echo "\nID not set";
exit(); exit;
} }
$project = new \pvv\side\Project( $project = new pvv\side\Project(
0, 0,
'Kult Prosjekt', 'Kult Prosjekt',
'', '',
'kåre knoll', 'kåre knoll',
'pvvadmin', 'pvvadmin',
'drift@pvv.ntnu.no', 'drift@pvv.ntnu.no',
0 0
); );
if($new == 0){ if ($new == 0) {
$project = $projectManager->getByID($projectID); $project = $projectManager->getByID($projectID);
} }
$members = $projectManager->getProjectMembers($projectID); $members = $projectManager->getProjectMembers($projectID);
$owner = [ $owner = [
'name' => '', 'name' => '',
'uname' => '', 'uname' => '',
'mail' => '', 'mail' => '',
]; ];
foreach($members as $i => $data){ foreach ($members as $i => $data) {
if($data['owner']){ if ($data['owner']) {
$owner = $data; $owner = $data;
} }
} }
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
@@ -85,34 +85,34 @@ foreach($members as $i => $data){
<h2>Prosjektadministrasjon</h2> <h2>Prosjektadministrasjon</h2>
<hr class="ruler"> <hr class="ruler">
<h2><?= ($new == 1 ? "Nytt prosjekt" : "Rediger prosjekt"); ?></h2> <h2><?php echo $new == 1 ? 'Nytt prosjekt' : 'Rediger prosjekt'; ?></h2>
<form action="update.php", method="post" class="gridsplit5050"> <form action="update.php", method="post" class="gridsplit5050">
<div class="gridl"> <div class="gridl">
<p class="subtitle">Tittel</p> <p class="subtitle">Tittel</p>
<?= '<input type="text" name="title" value="' . $project->getName() . '" class="boxinput">' ?><br> <?php echo '<input type="text" name="title" value="' . $project->getName() . '" class="boxinput">'; ?><br>
<p class="subtitle">Beskrivelse (<i>markdown</i>)</p> <p class="subtitle">Beskrivelse (<i>markdown</i>)</p>
<textarea name="desc" cols="40" rows="5" class="boxinput"><?= implode($project->getDescription(), "\n"); ?></textarea> <textarea name="desc" cols="40" rows="5" class="boxinput"><?php echo implode("\n", $project->getDescription()); ?></textarea>
</div> </div>
<div class="gridr noborder"> <div class="gridr noborder">
<p class="subtitle">Prosjektleder (Brukernavn)</p> <p class="subtitle">Prosjektleder (Brukernavn)</p>
<?= '<input type="text" name="organiser" value="' . $owner['uname'] . '" class="boxinput">' ?><br> <?php echo '<input type="text" name="organiser" value="' . $owner['uname'] . '" class="boxinput">'; ?><br>
<p class="subtitle">Prosjektleder (Navn)</p> <p class="subtitle">Prosjektleder (Navn)</p>
<?= '<input type="text" name="organisername" value="' . $owner['name'] . '" class="boxinput">' ?> <?php echo '<input type="text" name="organisername" value="' . $owner['name'] . '" class="boxinput">'; ?>
<p class="subtitle">Prosjektleder E-post</p> <p class="subtitle">Prosjektleder E-post</p>
<?= '<input type="text" name="organiseremail" value="' . $owner['mail'] . '" class="boxinput">' ?><br> <?php echo '<input type="text" name="organiseremail" value="' . $owner['mail'] . '" class="boxinput">'; ?><br>
<p class="subtitle">Aktiv</p> <p class="subtitle">Aktiv</p>
<?= '<input type="checkbox" '. ($project->getActive() ? 'checked' : '') . ' name="active"/>' ?> <?php echo '<input type="checkbox" ' . ($project->getActive() ? 'checked' : '') . ' name="active"/>'; ?>
</div> </div>
<?= '<input type="hidden" name="id" value="' . $project->getID() . '" />' ?> <?php echo '<input type="hidden" name="id" value="' . $project->getID() . '" />'; ?>
<?php if(!$new){ ?> <?php if (!$new) { ?>
<div style="grid-column: span 2;"> <div style="grid-column: span 2;">
<hr class="ruler"> <hr class="ruler">
</div> </div>
@@ -121,11 +121,11 @@ foreach($members as $i => $data){
<table class="userlist" style="grid-column: span 2;"> <table class="userlist" style="grid-column: span 2;">
<tr><th>Brukernavn</th><th>Navn</th><th>Rolle</th></tr> <tr><th>Brukernavn</th><th>Navn</th><th>Rolle</th></tr>
<?php foreach($members as $i => $data) { ?> <?php foreach ($members as $i => $data) { ?>
<tr> <tr>
<td><?= $data['uname']; ?></td> <td><?php echo $data['uname']; ?></td>
<td><?= $data['name']; ?></td> <td><?php echo $data['name']; ?></td>
<td><?= $data['role']; ?></td> <td><?php echo $data['role']; ?></td>
</tr> </tr>
<?php } ?> <?php } ?>
@@ -136,7 +136,7 @@ foreach($members as $i => $data){
</tr> </tr>
</table> </table>
<?php } ?> <?php } ?>
<div class="allgrids" style="margin-top: 2em;"> <div class="allgrids" style="margin-top: 2em;">
<hr class="ruler"> <hr class="ruler">

View File

@@ -1,51 +1,49 @@
<?php <?php
date_default_timezone_set('Europe/Oslo'); date_default_timezone_set('Europe/Oslo');
setlocale(LC_ALL, 'nb_NO'); setlocale(\LC_ALL, 'nb_NO');
require __DIR__ . '/../../../inc/navbar.php'; require __DIR__ . '/../../../inc/navbar.php';
require __DIR__ . '/../../../src/_autoload.php'; require __DIR__ . '/../../../src/_autoload.php';
require __DIR__ . '/../../../sql_config.php'; require __DIR__ . '/../../../config.php';
$pdo = new \PDO($dbDsn, $dbUser, $dbPass); $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userManager = new \pvv\admin\UserManager($pdo); $userManager = new pvv\admin\UserManager($pdo);
require_once(__DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'); require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML_Auth_Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth(); $as->requireAuth();
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$uname = $attrs['uid'][0]; $uname = $attrs['uid'][0];
if(!$userManager->hasGroup($uname, 'prosjekt')){ if (!$userManager->hasGroup($uname, 'prosjekt')) {
echo 'Her har du ikke lov\'t\'å\'værra!!!'; echo 'Her har du ikke lov\'t\'å\'værra!!!';
exit(); exit;
} }
$projectManager = new \pvv\side\ProjectManager($pdo); $projectManager = new pvv\side\ProjectManager($pdo);
$projects = $projectManager->getAll(); $projects = $projectManager->getAll();
$page = 1; $page = 1;
if(isset($_GET['page'])){ if (isset($_GET['page'])) {
$page = $_GET['page']; $page = $_GET['page'];
} }
$filterTitle = ''; $filterTitle = '';
if(isset($_POST['title'])){ if (isset($_POST['title'])) {
$filterTitle = $_POST['title']; $filterTitle = $_POST['title'];
} }
/* Temporarily out of service :< /* Temporarily out of service :<
$filterOrganiser = ''; $filterOrganiser = '';
if(isset($_POST['organiser'])){ if(isset($_POST['organiser'])){
$filterOrganiser = $_POST['organiser']; $filterOrganiser = $_POST['organiser'];
} }
*/ */
// filter // filter
$projects = array_values(array_filter( $projects = array_values(array_filter(
$projects, $projects,
function($project) use ($filterTitle){ static fn($project) => preg_match('/.*' . $filterTitle . '.*/i', $project->getName())
return (preg_match('/.*'.$filterTitle.'.*/i', $project->getName()));
}
)); ));
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
@@ -79,52 +77,52 @@ $projects = array_values(array_filter(
<ul class="event-list"> <ul class="event-list">
<?php <?php
$counter = 0; $counter = 0;
$pageLimit = 4; $pageLimit = 4;
for($i = ($pageLimit * ($page - 1)); $i < count($projects); $i++){ for ($i = ($pageLimit * ($page - 1)); $i < count($projects); ++$i) {
if($counter == $pageLimit){ if ($counter == $pageLimit) {
break; break;
} }
$project = $projects[$i]; $project = $projects[$i];
$projectID = $project->getID(); $projectID = $project->getID();
$owner = $projectManager->getProjectOwner($projectID); $owner = $projectManager->getProjectOwner($projectID);
?> ?>
<li> <li>
<div class="event admin"> <div class="event admin">
<div class="event-info"> <div class="event-info">
<h3 class="no-chin"><?= $project->getName() . " (ID: " . $projectID . ")"; ?></h3> <h3 class="no-chin"><?php echo $project->getName() . ' (ID: ' . $projectID . ')'; ?></h3>
<p class="subnote"><?= 'Organisert av: ' . $owner['name']; ?></p> <p class="subnote"><?php echo 'Organisert av: ' . $owner['name']; ?></p>
<?php <?php
$Parsedown = new \Parsedown(); $Parsedown = new Parsedown();
echo $Parsedown->text(implode("\n", $project->getDescription())); echo $Parsedown->text(implode("\n", $project->getDescription()));
?> ?>
</div> </div>
<div class="event-actions"> <div class="event-actions">
<?= '<a href="edit.php?id=' . $projectID . '">🖊</a>'; ?> <?php echo '<a href="edit.php?id=' . $projectID . '">🖊</a>'; ?>
<?= '<a href="delete.php?id=' . $projectID . '" onclick="return confirm(\'Knallsikker? (ID: ' . $projectID . ')\');">🗑</a>'; ?> <?php echo '<a href="delete.php?id=' . $projectID . '" onclick="return confirm(\'Knallsikker? (ID: ' . $projectID . ')\');">🗑</a>'; ?>
</div> </div>
</div> </div>
</li> </li>
<?php <?php
$counter++; ++$counter;
} }
?> ?>
</ul> </ul>
<?php <?php
if($page != 1){ if ($page != 1) {
echo '<a class="btn float-left" href="?page=' . ($page - 1) . '">Forrige side</a>'; echo '<a class="btn float-left" href="?page=' . ($page - 1) . '">Forrige side</a>';
} }
if(($counter == $pageLimit) and (($pageLimit * $page) < count($projects))){ if (($counter == $pageLimit) && (($pageLimit * $page) < count($projects))) {
echo '<a class="btn float-right" href="?page=' . ($page + 1) . '">Neste side</a>'; echo '<a class="btn float-right" href="?page=' . ($page + 1) . '">Neste side</a>';
} }
?> ?>
</div> </div>
<div class="gridr"> <div class="gridr">
@@ -133,9 +131,9 @@ $projects = array_values(array_filter(
<h2>Filter</h2> <h2>Filter</h2>
<form action="." method="post"> <form action="." method="post">
<p class="no-chin">Prosjektnavn</p> <p class="no-chin">Prosjektnavn</p>
<?= '<input type="text" name="title" class="boxinput" value="' . $filterTitle . '">' ?><br> <?php echo '<input type="text" name="title" class="boxinput" value="' . $filterTitle . '">'; ?><br>
<p class="no-chin">Leders brukernavn</p> <p class="no-chin">Leders brukernavn</p>
<?= '<input type="text" name="organiser" class="boxinput" value="">' ?><br> <?php echo '<input type="text" name="organiser" class="boxinput" value="">'; ?><br>
<div style="margin-top: 2em;"> <div style="margin-top: 2em;">
<input type="submit" class="btn" value="Filtrer"></input> <input type="submit" class="btn" value="Filtrer"></input>

View File

@@ -1,31 +1,31 @@
<?php <?php
date_default_timezone_set('Europe/Oslo'); date_default_timezone_set('Europe/Oslo');
setlocale(LC_ALL, 'nb_NO'); setlocale(\LC_ALL, 'nb_NO');
require __DIR__ . '/../../../src/_autoload.php'; require __DIR__ . '/../../../src/_autoload.php';
require __DIR__ . '/../../../sql_config.php'; require __DIR__ . '/../../../config.php';
$pdo = new \PDO($dbDsn, $dbUser, $dbPass); $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userManager = new \pvv\admin\UserManager($pdo); $userManager = new pvv\admin\UserManager($pdo);
require_once(__DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'); require_once __DIR__ . '/../../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML_Auth_Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth(); $as->requireAuth();
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$uname = $attrs['uid'][0]; $uname = $attrs['uid'][0];
if(!$userManager->hasGroup($uname, 'prosjekt')){ if (!$userManager->hasGroup($uname, 'prosjekt')) {
echo 'Her har du ikke lov\'t\'å\'værra!!!'; echo 'Her har du ikke lov\'t\'å\'værra!!!';
exit(); exit;
} }
if(!isset($_POST['title']) or !isset($_POST['desc']) or !isset($_POST['organisername']) or !isset($_POST['organiser'])){ if (!isset($_POST['title']) || !isset($_POST['desc']) || !isset($_POST['organisername']) || !isset($_POST['organiser'])) {
header('Location: ' . $_SERVER['HTTP_REFERER']); header('Location: ' . $_SERVER['HTTP_REFERER']);
exit(); exit;
} }
$id = 0; $id = 0;
if(isset($_POST['id'])){ if (isset($_POST['id'])) {
$id = $_POST['id']; $id = $_POST['id'];
} }
$title = $_POST['title']; $title = $_POST['title'];
@@ -33,48 +33,74 @@ $desc = $_POST['desc'];
$name = $_POST['organisername']; $name = $_POST['organisername'];
$uname = $_POST['organiser']; $uname = $_POST['organiser'];
$mail = $_POST['organiseremail']; $mail = $_POST['organiseremail'];
$active = (isset($_POST['active']) ? $_POST['active'] : 0); $active = ($_POST['active'] ?? false);
$statement;
if($id == 0){
$query = 'INSERT INTO projects (name, description, active) VALUES (:title, :desc, :active)';
$statement = $pdo->prepare($query);
$statement->bindParam(':title', $title, PDO::PARAM_STR); if ($id == 0) {
$statement->bindParam(':desc', $desc, PDO::PARAM_STR); $query = '
$statement->bindParam(':active', $active, PDO::PARAM_INT); INSERT INTO
projects(name, description, active)
VALUES
(:title, :desc, :active)
';
$statement = $pdo->prepare($query);
$statement->execute(); $statement->bindParam(':title', $title, PDO::PARAM_STR);
$statement->bindParam(':desc', $desc, PDO::PARAM_STR);
$statement->bindParam(':active', $active, PDO::PARAM_BOOL);
$ownerQuery = 'INSERT INTO projectmembers (projectid, name, uname, mail, role, lead, owner) VALUES (last_insert_rowid(), :owner, :owneruname, :owneremail, \'Prosjektleder\', 1, 1)'; $statement->execute();
$statement = $pdo->prepare($ownerQuery);
$statement->bindParam(':owner', $name, PDO::PARAM_STR);
$statement->bindParam(':owneruname', $uname, PDO::PARAM_STR);
$statement->bindParam(':owneremail', $mail, PDO::PARAM_STR);
$statement->execute(); $ownerQuery = '
}else{ INSERT INTO
$query = 'UPDATE projects SET name=:title, description=:desc, active=:active WHERE id=:id'; projectmembers(projectid, name, uname, mail, role, lead, owner)
$statement = $pdo->prepare($query); VALUES
(last_insert_rowid(), :owner, :owneruname, :owneremail, \'Prosjektleder\', 1, 1)
';
$statement = $pdo->prepare($ownerQuery);
$statement->bindParam(':owner', $name, PDO::PARAM_STR);
$statement->bindParam(':owneruname', $uname, PDO::PARAM_STR);
$statement->bindParam(':owneremail', $mail, PDO::PARAM_STR);
$statement->bindParam(':title', $title, PDO::PARAM_STR); $statement->execute();
$statement->bindParam(':desc', $desc, PDO::PARAM_STR); } else {
$statement->bindParam(':active', $active, PDO::PARAM_INT); $query = '
$statement->bindParam(':id', $id, PDO::PARAM_INT); UPDATE
projects
SET
name = :title,
description = :desc,
active = :active
WHERE
id = :id
';
$statement = $pdo->prepare($query);
$statement->execute(); $statement->bindParam(':title', $title, PDO::PARAM_STR);
$statement->bindParam(':desc', $desc, PDO::PARAM_STR);
$statement->bindParam(':active', $active, PDO::PARAM_BOOL);
$statement->bindParam(':id', $id, PDO::PARAM_INT);
$query = 'UPDATE projectmembers SET name=:name, uname=:uname, mail=:mail'; $statement->execute();
$statement = $pdo->prepare($query);
$statement->bindParam(':name', $name, PDO::PARAM_STR); $query = '
$statement->bindParam(':uname', $uname, PDO::PARAM_STR); UPDATE
$statement->bindParam(':mail', $mail, PDO::PARAM_STR); projectmembers
SET
name = :name,
uname = :uname,
mail = :mail
';
$statement = $pdo->prepare($query);
$statement->execute(); $statement->bindParam(':name', $name, PDO::PARAM_STR);
$statement->bindParam(':uname', $uname, PDO::PARAM_STR);
$statement->bindParam(':mail', $mail, PDO::PARAM_STR);
$statement->execute();
} }
header('Location: .'); header('Location: .');
?> ?>
<a href=".?page=1">Om du ikke ble automatisk omdirigert tilbake klikk her</a> <a href=".?page=1">Om du ikke ble automatisk omdirigert tilbake klikk her</a>

View File

@@ -1,15 +1,18 @@
<?php namespace pvv\side; <?php
require_once dirname(dirname(__DIR__)) . implode(DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']);
namespace pvv\side;
require_once \dirname(__DIR__, 2) . implode(\DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']);
$year = (isset($_GET['year'])) $year = (isset($_GET['year']))
? $_GET['year'] ? $_GET['year']
: date("Y"); : date('Y');
$month = (isset($_GET['month'])) $month = (isset($_GET['month']))
? $_GET['month'] ? $_GET['month']
: date("m"); : date('m');
$day = (isset($_GET['day'])) $day = (isset($_GET['day']))
? $_GET['day'] ? $_GET['day']
: -1; : -1;
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
@@ -34,42 +37,47 @@ $day = (isset($_GET['day']))
<main> <main>
<?php <?php
use \DateTimeImmutable; 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; $events = ($day == -1)
foreach($events as $event) { ? $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> <article>
<h2> <h2>
<?php if (\pvv\side\Agenda::isToday($event->getStart())) { ?><strong><?php } ?> <?php if (Agenda::isToday($event->getStart())) { ?><strong><?php } ?>
<em><?= $event->getRelativeDate() ?></em> <em><?php echo $event->getRelativeDate(); ?></em>
<?php if (\pvv\side\Agenda::isToday($event->getStart())) { ?></strong><?php } ?> <?php if (Agenda::isToday($event->getStart())) { ?></strong><?php } ?>
<?php if ($event->getURL()) { ?> <?php if ($event->getURL()) { ?>
<a href="<?= $event->getURL() ?>"><?= $event->getName() ?></a> <br>
<a href="<?php echo $event->getURL(); ?>"><?php echo $event->getName(); ?></a>
<?php } else { ?> <?php } else { ?>
<?= $event->getName() ?> <?php echo $event->getName(); ?>
<?php } ?> <?php } ?>
<?php if ($event->getImageURL()) { ?> <?php if ($event->getImageURL()) { ?>
<img src="<?= $event->getImageURL() ?>"> <img src="<?php echo $event->getImageURL(); ?>">
<?php } ?> <?php } ?>
</h2> </h2>
<ul class="subtext"> <ul class="subtext">
<li>Tid: <strong><?= Agenda::getFormattedDate($event->getStart()) ?></strong></li> <li>Tid: <strong><?php echo Agenda::getFormattedDate($event->getStart()); ?></strong></li>
<li>Sted: <strong><?= $event->getLocation() ?></strong></li> <li>Sted: <strong><?php echo $event->getLocation(); ?></strong></li>
<li>Arrangør: <strong><?= $event->getOrganiser() ?></strong></li> <li>Arrangør: <strong><?php echo $event->getOrganiser(); ?></strong></li>
</ul> </ul>
<?php $description = $event->getDescription(); ?> <?php $description = $event->getDescription(); ?>
<?php if ($limit) array_splice($description, $limit); ?> <?php if ($limit) {
array_splice($description, $limit);
} ?>
<?php <?php
$Parsedown = new \Parsedown(); $Parsedown = new \Parsedown();
echo $Parsedown->text(implode("\n", $description)); echo $Parsedown->text(implode("\n", $description));
?> ?>
</article> </article>
<?php } ?> <?php } ?>

View File

@@ -1,6 +1,7 @@
<?php <?php
require_once dirname(dirname(__DIR__)) . implode(DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']); require_once dirname(__DIR__, 2) . implode(\DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']);
use \pvv\side\Agenda; use pvv\side\Agenda;
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="no"> <html lang="no">
@@ -20,40 +21,40 @@ use \pvv\side\Agenda;
<main> <main>
<?php <?php
$activity = new \pvv\side\social\AnimekveldActivity; $activity = new pvv\side\social\AnimekveldActivity();
$nextEvent = $activity->getNextEventFrom(new DateTimeImmutable); $nextEvent = $activity->getNextEventFrom(new DateTimeImmutable());
?> ?>
<article> <article>
<h2><em><?= $nextEvent->getRelativeDate()?></em> Animekveld <h2><em><?php echo $nextEvent->getRelativeDate(); ?></em> Animekveld
<?php if ($nextEvent->getImageURL()) { ?> <?php if ($nextEvent->getImageURL()) { ?>
<img src="<?= $nextEvent->getImageURL() ?>"> <img src="<?php echo $nextEvent->getImageURL(); ?>">
<?php } ?> <?php } ?>
</h2> </h2>
<ul class="subtext"> <ul class="subtext">
<li>Tid: <li>Tid:
<strong> <strong>
<?= Agenda::getFormattedDate($nextEvent->getStart());?> <?php echo Agenda::getFormattedDate($nextEvent->getStart()); ?>
</strong> </strong>
<li>Sted: <li>Sted:
<strong> <strong>
<?= $nextEvent->getLocation();?> <?php echo $nextEvent->getLocation(); ?>
</strong> </strong>
<li>Arrangør: <li>Arrangør:
<strong> <strong>
<?= $nextEvent->getOrganiser();?> <?php echo $nextEvent->getOrganiser(); ?>
</strong> </strong>
</ul> </ul>
<?php <?php
$Parsedown = new \Parsedown(); $Parsedown = new Parsedown();
echo $Parsedown->text(implode("\n", $nextEvent->getDescription())); echo $Parsedown->text(implode("\n", $nextEvent->getDescription()));
?> ?>
</article> </article>
</main> </main>
<nav> <nav>
<?= navbar(1, 'aktiviteter'); ?> <?php echo navbar(1, 'aktiviteter'); ?>
<?= loginbar($sp, $pdo); ?> <?php echo loginbar($sp, $pdo); ?>
</nav> </nav>

View File

@@ -1,6 +1,7 @@
<?php <?php
require_once dirname(dirname(__DIR__)) . implode(DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']); require_once dirname(__DIR__, 2) . implode(\DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']);
use \pvv\side\Agenda; use pvv\side\Agenda;
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="no"> <html lang="no">
@@ -20,41 +21,41 @@ use \pvv\side\Agenda;
<main> <main>
<?php <?php
$activity = new \pvv\side\social\BrettspillActivity; $activity = new pvv\side\social\BrettspillActivity();
$nextEvent = $activity->getNextEventFrom(new DateTimeImmutable); $nextEvent = $activity->getNextEventFrom(new DateTimeImmutable());
?> ?>
<article> <article>
<h2><em><?= $nextEvent->getRelativeDate()?></em> Brettspillkveld <h2><em><?php echo $nextEvent->getRelativeDate(); ?></em> Brettspillkveld
<?php if ($nextEvent->getImageURL()) { ?> <?php if ($nextEvent->getImageURL()) { ?>
<img src="<?= $nextEvent->getImageURL() ?>"> <img src="<?php echo $nextEvent->getImageURL(); ?>">
<?php } ?> <?php } ?>
</h2> </h2>
<ul class="subtext"> <ul class="subtext">
<li>Tid: <li>Tid:
<strong> <strong>
<?= Agenda::getFormattedDate($nextEvent->getStart());?> <?php echo Agenda::getFormattedDate($nextEvent->getStart()); ?>
</strong> </strong>
<li>Sted: <li>Sted:
<strong> <strong>
<?= $nextEvent->getLocation();?> <?php echo $nextEvent->getLocation(); ?>
</strong> </strong>
<li>Arrangør: <li>Arrangør:
<strong> <strong>
<?= $nextEvent->getOrganiser();?> <?php echo $nextEvent->getOrganiser(); ?>
</strong> </strong>
</ul> </ul>
<?php <?php
$Parsedown = new \Parsedown(); $Parsedown = new Parsedown();
echo $Parsedown->text(implode("\n", $nextEvent->getDescription())); echo $Parsedown->text(implode("\n", $nextEvent->getDescription()));
?> ?>
</article> </article>
</main> </main>
<nav> <nav>
<?= navbar(1, 'aktiviteter'); ?> <?php echo navbar(1, 'aktiviteter'); ?>
<?= loginbar($sp, $pdo); ?> <?php echo loginbar($sp, $pdo); ?>
</nav> </nav>

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17.01 14.258" enable-background="new 0 0 17.01 14.258"><style type="text/css">.st0{fill:#004166;}</style><path class="st0" d="M14.009 8.551l.01-.019.005-.023.003-.014-.001-.006-.004-.022-.007-.021-.002-.006-4.629-8.382-.006-.006-.009-.013-.01-.01-.012-.009-.006-.005-.006-.002-.013-.005-.015-.004-.016-.002-.006-.002h-1.642l-.015.003-.021.004-.02.01-.017.012-.015.017-.009.011-4.233 7.425-.002.006-.007.021-.005.022-.001.006v2.86l.003.014.005.023.009.019.012.018.017.015.011.009.008.003.009.004.039.008h1.421l.038-.008.009-.004.031-.021.001-.001.019-.025 1.017-1.844h5.067l1.007 1.844.019.025.002.001.03.02.009.004.038.008h1.125l.04-.008.011-.005.023-.015.01-.009.015-.023.006-.011.002-.004.649-1.869.009-.014zm-.843 1.734h-.859l.582-1.678h.859l-.582 1.678zm-1.996-1.855l-.015-.018-.017-.012-.019-.01-.023-.005-.014-.003h-5.2l-.015.003-.023.005-.019.01-.018.012-.015.018-.01.011-1.017 1.844h-1.161l5.679-9.944 4.44 8.041h-.846l-3.426-6.236-.006-.007-.014-.017-.018-.015-.006-.006-.012-.003-.022-.007-.021-.002-.021.002-.021.007-.012.003-.007.006-.017.014-.014.018-.006.006-2.776 5.035-.002.005-.006.021-.005.023-.001.005.003.014.005.024.009.018.012.018.017.015.012.01.007.003.008.003.039.007h3.788l.039-.008.009-.004.007-.003.011-.009.018-.015.012-.017.01-.019.005-.023.003-.015-.001-.006-.004-.022-.007-.022-.002-.005-1.842-3.315-.037-.038.768-1.392 3.335 6.073-.572 1.649-.936-1.714-.01-.011zm-7.647-.863l4.186-7.342h1.383l-5.569 9.75v-2.408zm3.619-1.127h2.653l.378.682h-3.407l.376-.682zm.124-.225l1.198-2.173 1.206 2.173h-2.404zM1.197 14.258l-.13-.325h-.729l-.13.325h-.208l.588-1.464h.226l.591 1.464h-.208zm-.494-1.276l-.312.788h.621l-.309-.788zM2.123 14.258v-1.464h.959v.162h-.776v.472h.762v.162h-.762v.667h-.183zM4.22 14.258v-1.302h-.463v-.162h1.111v.162h-.465v1.302h-.183zM5.637 14.258v-1.464h.959v.162h-.777v.472h.762v.162h-.762v.505h.777v.162h-.959zM8.261 14.258l-.373-.582h-.292v.582h-.183v-1.464h.588c.268 0 .459.171.459.441 0 .263-.18.408-.38.426l.395.597h-.214zm.011-1.023c0-.165-.119-.279-.292-.279h-.384v.56h.384c.173 0 .292-.117.292-.281zM9.275 14.258v-1.464h.182v1.302h.681v.162h-.863zM10.613 13.527c0-.433.292-.757.727-.757.432 0 .727.325.727.757 0 .433-.294.758-.727.758-.435-.001-.727-.326-.727-.758zm1.264 0c0-.342-.211-.595-.538-.595-.329 0-.538.252-.538.595 0 .34.209.595.538.595.328 0 .538-.255.538-.595zM12.644 13.527c0-.454.336-.757.753-.757.259 0 .439.114.569.275l-.145.09c-.092-.119-.248-.202-.424-.202-.321 0-.564.246-.564.595 0 .347.244.597.564.597.176 0 .321-.086.393-.158v-.299h-.503v-.162h.685v.529c-.136.151-.336.252-.575.252-.417-.001-.753-.306-.753-.76zM14.84 14.258v-1.464h.182v1.464h-.182zM15.699 13.527c0-.45.332-.757.753-.757.259 0 .439.125.555.29l-.154.086c-.083-.123-.235-.213-.402-.213-.321 0-.564.246-.564.595 0 .347.244.595.564.595.167 0 .318-.088.402-.213l.156.086c-.123.167-.299.29-.558.29-.421-.002-.752-.309-.752-.759z"/></svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -11,7 +11,6 @@ h2 em {
font-size: .5em; font-size: .5em;
line-height: 2em; line-height: 2em;
float: left; float: left;
margin-right: 1em;
border: .1em solid gray; border: .1em solid gray;
padding: 0 1em; padding: 0 1em;
border-radius: .25em; border-radius: .25em;
@@ -107,7 +106,6 @@ p + .subtext {
} }
@media screen and (max-width: 50rem) { @media screen and (max-width: 50rem) {
h2 { h2 {
text-align: center;
position: relative; position: relative;
border-bottom-left-radius: 0.3em; border-bottom-left-radius: 0.3em;
border-bottom-right-radius: 0.3em; border-bottom-right-radius: 0.3em;
@@ -133,4 +131,8 @@ p + .subtext {
article >.subtext { article >.subtext {
margin-top: -1em !important; margin-top: -1em !important;
} }
.subtext li {
display: block;
}
} }

View File

@@ -51,11 +51,9 @@ main {
font-size: 1.5em; font-size: 1.5em;
} }
/* #region modal */
.modal-target:hover {opacity: 0.7;} .modal-target:hover {opacity: 0.7;}
/* The Modal (background) */ /* Modal Background */
.modal { .modal {
display: none; /* Hidden by default */ display: none; /* Hidden by default */
position: fixed; /* Stay in place */ position: fixed; /* Stay in place */
@@ -70,14 +68,12 @@ main {
background-color: rgba(0,0,0,0.8); /* Black w/ opacity */ background-color: rgba(0,0,0,0.8); /* Black w/ opacity */
} }
/* Modal Content (image) */
.modal-content { .modal-content {
margin: auto; margin: auto;
display: block; display: block;
object-fit: scale-down; object-fit: scale-down;
overflow: visible; overflow: visible;
/* yolo, it all goes down from here */
min-width: 60vw; min-width: 60vw;
max-width: 90vw !important; max-width: 90vw !important;
min-height: 60vh; min-height: 60vh;
@@ -88,7 +84,6 @@ main {
opacity: 1 !important; opacity: 1 !important;
} }
/* Caption of Modal Image */
.modal-caption { .modal-caption {
margin: auto; margin: auto;
display: block; display: block;
@@ -133,9 +128,7 @@ main {
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
} }
/* #endregion modal */
/* #region screen-size media-rules */
@media only screen and (min-width:320px) { @media only screen and (min-width:320px) {
.gallery-container { grid-template-columns: repeat(1, minmax(0, 1fr)) !important; } .gallery-container { grid-template-columns: repeat(1, minmax(0, 1fr)) !important; }
main { padding: 1em; } main { padding: 1em; }
@@ -150,4 +143,3 @@ main {
@media only screen and (min-width: 1281px) { @media only screen and (min-width: 1281px) {
.gallery-container { grid-template-columns: repeat(4, minmax(0, 1fr)) !important; } .gallery-container { grid-template-columns: repeat(4, minmax(0, 1fr)) !important; }
} }
/* #endregion */

View File

@@ -65,49 +65,23 @@ img.float-right {
list-style: none; list-style: none;
} }
.calendar-events ul li :not(.date):not(.time) {
display: inline-block;
width: calc(100% - 7em);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.calendar-events ul .date {
color: rgba(0, 0, 0, 0.5);
font-size: 0.8em;
margin-top: 0.2em;
}
.calendar-events > li > p {
border-bottom: 0.1em dotted rgba(0, 0, 0, 0.2);
}
.calendar-events ul { .calendar-events ul {
list-style: none; list-style: none;
padding: 0; padding: 0;
} }
.calendar-events a, .calendar-events a {
#ticker a { color: rgba(0,0,0, 0.85);
text-decoration: none;
font-weight: bold;
color: black;
} }
.calendar-events a:hover, .calendar-events ul .datetime {
#ticker a:hover {
text-decoration: underline;
}
.calendar-events ul .time {
color: rgba(0, 0, 0, 0.5); color: rgba(0, 0, 0, 0.5);
float: right; float: right;
margin-left: 0.2em;
} }
.calendar-events ul .icon, .calendar-events ul li {
.calendar-events ul .date { margin-bottom: 0.4em;
float: right;
margin-right: 0.5em;
} }
main.contentsplit { main.contentsplit {

View File

@@ -1,73 +0,0 @@
ul#webmail {
margin-top: 0;
margin-left: auto;
margin-right: auto;
table-layout: fixed;
display: table;
width: 100%;
padding: 0;
}
ul#webmail li {
display: table-cell;
text-align: center;
}
ul#webmail li .mailname {
font-size: 1.2em;
}
@media all and (min-width: 980px) {
ul#webmail {
max-width: 1280px;
}
ul#webmail li {
display: table-cell;
text-align: center;
}
}
@media all and (max-width: 980px) {
ul#webmail {
max-width: 650px;
}
ul#webmail li {
display: table-row;
text-align: center;
}
}
ul#webmail li div {
position: relative;
background: white;
margin: 1em 1em;
box-shadow: rgba(0,0,0,.3) 0 .1em .17em;
border-radius: .5rem;
cursor: pointer;
}
ul#webmail li:hover div {
box-shadow: rgba(0,0,0,.5) 0 .15em .2em;
}
ul#webmail li div a {
padding-top: 10em;
display: block;
text-decoration: none;
color: black;
}
ul#webmail li#afterlogic div {
background: white url('afterlogic.png') no-repeat;
background: white url('afterlogic.svg') no-repeat;
background-size: auto 8em;
background-position: 50% 60%;
}
ul#webmail li#squirrelmail div {
background: white url('squirrelmail.png') no-repeat;
background-size: auto 10em;
background-position: 50% 0;
}
ul#webmail li#roundcube div {
background: white url('roundcube.png') no-repeat;
background-size: auto 10em;
background-position: 50% 0;
}
ul#webmail li#rainloop div {
background: white url('rainloop.png') no-repeat;
background-size: auto 10em;
background-position: 50% 0;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Some files were not shown because too many files have changed in this diff Show More