Compare commits
1 Commits
main
...
move-to-po
| Author | SHA1 | Date | |
|---|---|---|---|
|
ecdb89c096
|
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
26
.mailmap
@@ -1,26 +0,0 @@
|
||||
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>
|
||||
7
Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
||||
# 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
|
||||
32
README.md
@@ -4,8 +4,36 @@
|
||||
A website created with the latest and greatest web technologies.
|
||||
May contain blackjack and other things one tends to include in awesome projects.
|
||||
|
||||
See [Getting Started](./docs/getting-started.md) for help to hack on the project.
|
||||
## Installation
|
||||
|
||||
git clone --recursive https://github.com/Programvareverkstedet/nettsiden.git
|
||||
|
||||
Put it in a folder your webserver can find.
|
||||
|
||||
## Development setup
|
||||
|
||||
The development environment can be setup with:
|
||||
|
||||
nix develop
|
||||
|
||||
For this you will need to install the nix package manager and possibly set the experimental features in your nix config, likely located at /etc/nix/nix.conf or $HOME/.config/nix/nix.conf.
|
||||
|
||||
Installing nix with your package manager might not work without some tweaking, but the upstream script should just work which you can find [here](https://nixos.org/download/).
|
||||
|
||||
experimental-features = flakes nix-command
|
||||
|
||||
You can then run the server with:
|
||||
|
||||
runDev
|
||||
|
||||
### 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);"
|
||||
|
||||
## Hosting
|
||||
|
||||

|
||||

|
||||
|
||||
110
composer.lock
generated
@@ -1619,16 +1619,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/cache",
|
||||
"version": "v6.4.31",
|
||||
"version": "v6.4.30",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/cache.git",
|
||||
"reference": "a1b306757c34b96fe97c0c586f50dceed05c7adb"
|
||||
"reference": "eb3272ed2daed13ed24816e862d73f73d995972a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/cache/zipball/a1b306757c34b96fe97c0c586f50dceed05c7adb",
|
||||
"reference": "a1b306757c34b96fe97c0c586f50dceed05c7adb",
|
||||
"url": "https://api.github.com/repos/symfony/cache/zipball/eb3272ed2daed13ed24816e862d73f73d995972a",
|
||||
"reference": "eb3272ed2daed13ed24816e862d73f73d995972a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1695,7 +1695,7 @@
|
||||
"psr6"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/cache/tree/v6.4.31"
|
||||
"source": "https://github.com/symfony/cache/tree/v6.4.30"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1715,7 +1715,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-27T18:26:25+00:00"
|
||||
"time": "2025-12-01T16:41:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/cache-contracts",
|
||||
@@ -1874,16 +1874,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v6.4.31",
|
||||
"version": "v6.4.30",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "f9f8a889f54c264f9abac3fc0f7a371ffca51997"
|
||||
"reference": "1b2813049506b39eb3d7e64aff033fd5ca26c97e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/f9f8a889f54c264f9abac3fc0f7a371ffca51997",
|
||||
"reference": "f9f8a889f54c264f9abac3fc0f7a371ffca51997",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/1b2813049506b39eb3d7e64aff033fd5ca26c97e",
|
||||
"reference": "1b2813049506b39eb3d7e64aff033fd5ca26c97e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1948,7 +1948,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v6.4.31"
|
||||
"source": "https://github.com/symfony/console/tree/v6.4.30"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1968,20 +1968,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-22T08:30:34+00:00"
|
||||
"time": "2025-12-05T13:47:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dependency-injection",
|
||||
"version": "v6.4.31",
|
||||
"version": "v6.4.30",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dependency-injection.git",
|
||||
"reference": "10058832a74a33648870aa2057e3fdc8796a6566"
|
||||
"reference": "5328f994cbb0855ba25c3a54f4a31a279511640f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/10058832a74a33648870aa2057e3fdc8796a6566",
|
||||
"reference": "10058832a74a33648870aa2057e3fdc8796a6566",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/5328f994cbb0855ba25c3a54f4a31a279511640f",
|
||||
"reference": "5328f994cbb0855ba25c3a54f4a31a279511640f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2033,7 +2033,7 @@
|
||||
"description": "Allows you to standardize and centralize the way objects are constructed in your application",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/dependency-injection/tree/v6.4.31"
|
||||
"source": "https://github.com/symfony/dependency-injection/tree/v6.4.30"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2053,7 +2053,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-23T13:34:50+00:00"
|
||||
"time": "2025-12-07T09:29:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
@@ -2505,16 +2505,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v6.4.31",
|
||||
"version": "v6.4.27",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "5547f2e1f0ca8e2e7abe490156b62da778cfbe2b"
|
||||
"reference": "a1b6aa435d2fba50793b994a839c32b6064f063b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/5547f2e1f0ca8e2e7abe490156b62da778cfbe2b",
|
||||
"reference": "5547f2e1f0ca8e2e7abe490156b62da778cfbe2b",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/a1b6aa435d2fba50793b994a839c32b6064f063b",
|
||||
"reference": "a1b6aa435d2fba50793b994a839c32b6064f063b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2549,7 +2549,7 @@
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v6.4.31"
|
||||
"source": "https://github.com/symfony/finder/tree/v6.4.27"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2569,20 +2569,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-11T14:52:17+00:00"
|
||||
"time": "2025-10-15T18:32:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/framework-bundle",
|
||||
"version": "v6.4.31",
|
||||
"version": "v6.4.30",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/framework-bundle.git",
|
||||
"reference": "0ab60c05570b9e2bfab92b9944b938b8ffb5ba96"
|
||||
"reference": "3c212ec5cac588da8357f5c061194363a4e91010"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/framework-bundle/zipball/0ab60c05570b9e2bfab92b9944b938b8ffb5ba96",
|
||||
"reference": "0ab60c05570b9e2bfab92b9944b938b8ffb5ba96",
|
||||
"url": "https://api.github.com/repos/symfony/framework-bundle/zipball/3c212ec5cac588da8357f5c061194363a4e91010",
|
||||
"reference": "3c212ec5cac588da8357f5c061194363a4e91010",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2702,7 +2702,7 @@
|
||||
"description": "Provides a tight integration between Symfony components and the Symfony full-stack framework",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/framework-bundle/tree/v6.4.31"
|
||||
"source": "https://github.com/symfony/framework-bundle/tree/v6.4.30"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2722,20 +2722,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-23T14:16:13+00:00"
|
||||
"time": "2025-11-29T11:31:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-foundation",
|
||||
"version": "v6.4.31",
|
||||
"version": "v6.4.30",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-foundation.git",
|
||||
"reference": "a35ee6f47e4775179704d7877a8b0da3cb09241a"
|
||||
"reference": "0384c62b79d96e9b22d77bc1272c9e83342ba3a6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/a35ee6f47e4775179704d7877a8b0da3cb09241a",
|
||||
"reference": "a35ee6f47e4775179704d7877a8b0da3cb09241a",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/0384c62b79d96e9b22d77bc1272c9e83342ba3a6",
|
||||
"reference": "0384c62b79d96e9b22d77bc1272c9e83342ba3a6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2783,7 +2783,7 @@
|
||||
"description": "Defines an object-oriented layer for the HTTP specification",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-foundation/tree/v6.4.31"
|
||||
"source": "https://github.com/symfony/http-foundation/tree/v6.4.30"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2803,20 +2803,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-17T10:10:57+00:00"
|
||||
"time": "2025-12-01T20:07:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-kernel",
|
||||
"version": "v6.4.31",
|
||||
"version": "v6.4.30",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-kernel.git",
|
||||
"reference": "16b0d46d8e11f480345c15b229cfc827a8a0f731"
|
||||
"reference": "ceac681e74e824bbf90468eb231d40988d6d18a5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/16b0d46d8e11f480345c15b229cfc827a8a0f731",
|
||||
"reference": "16b0d46d8e11f480345c15b229cfc827a8a0f731",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/ceac681e74e824bbf90468eb231d40988d6d18a5",
|
||||
"reference": "ceac681e74e824bbf90468eb231d40988d6d18a5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2901,7 +2901,7 @@
|
||||
"description": "Provides a structured process for converting a Request into a Response",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-kernel/tree/v6.4.31"
|
||||
"source": "https://github.com/symfony/http-kernel/tree/v6.4.30"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2921,7 +2921,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-31T08:27:27+00:00"
|
||||
"time": "2025-12-07T15:49:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/intl",
|
||||
@@ -4018,16 +4018,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/twig-bridge",
|
||||
"version": "v6.4.31",
|
||||
"version": "v6.4.30",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/twig-bridge.git",
|
||||
"reference": "24a498d80fd2a28087fbac0a96e0721ce2756b65"
|
||||
"reference": "d77a78c7fffaf7cb0158d28db824ba78d89a9f34"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/twig-bridge/zipball/24a498d80fd2a28087fbac0a96e0721ce2756b65",
|
||||
"reference": "24a498d80fd2a28087fbac0a96e0721ce2756b65",
|
||||
"url": "https://api.github.com/repos/symfony/twig-bridge/zipball/d77a78c7fffaf7cb0158d28db824ba78d89a9f34",
|
||||
"reference": "d77a78c7fffaf7cb0158d28db824ba78d89a9f34",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4107,7 +4107,7 @@
|
||||
"description": "Provides integration for Twig with various Symfony components",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/twig-bridge/tree/v6.4.31"
|
||||
"source": "https://github.com/symfony/twig-bridge/tree/v6.4.30"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4127,20 +4127,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-11T18:16:47+00:00"
|
||||
"time": "2025-12-05T13:01:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-dumper",
|
||||
"version": "v7.4.3",
|
||||
"version": "v7.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/var-dumper.git",
|
||||
"reference": "7e99bebcb3f90d8721890f2963463280848cba92"
|
||||
"reference": "41fd6c4ae28c38b294b42af6db61446594a0dece"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/7e99bebcb3f90d8721890f2963463280848cba92",
|
||||
"reference": "7e99bebcb3f90d8721890f2963463280848cba92",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/41fd6c4ae28c38b294b42af6db61446594a0dece",
|
||||
"reference": "41fd6c4ae28c38b294b42af6db61446594a0dece",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4194,7 +4194,7 @@
|
||||
"dump"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/var-dumper/tree/v7.4.3"
|
||||
"source": "https://github.com/symfony/var-dumper/tree/v7.4.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4214,7 +4214,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-18T07:04:31+00:00"
|
||||
"time": "2025-10-27T20:36:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-exporter",
|
||||
@@ -4583,5 +4583,5 @@
|
||||
"prefer-lowest": false,
|
||||
"platform": {},
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.9.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
||||
45
dist/pvv_mysql.sql
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
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);
|
||||
49
dist/pvv_postgresql.sql
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
CREATE TABLE events (
|
||||
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||
name TEXT,
|
||||
start TEXT,
|
||||
stop TEXT,
|
||||
organiser TEXT,
|
||||
location TEXT,
|
||||
description TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE projects (
|
||||
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||
name TEXT,
|
||||
description TEXT,
|
||||
active BOOLEAN
|
||||
);
|
||||
|
||||
CREATE TABLE projectmembers (
|
||||
projectid INTEGER,
|
||||
name TEXT,
|
||||
uname TEXT,
|
||||
mail TEXT,
|
||||
role TEXT,
|
||||
lead BOOLEAN DEFAULT FALSE,
|
||||
owner BOOLEAN DEFAULT FALSE
|
||||
);
|
||||
|
||||
CREATE TABLE users (
|
||||
uname TEXT,
|
||||
groups INT DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE motd (
|
||||
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||
title TEXT,
|
||||
content TEXT
|
||||
);
|
||||
|
||||
-- INSERT example
|
||||
-- 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);
|
||||
54
dist/pvv_sqlite.sql
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
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);
|
||||
36
dist/simplesaml-dev/authsources.php
vendored
@@ -1,36 +0,0 @@
|
||||
<?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
10
dist/simplesaml-dev/saml20-idp-hosted.php
vendored
@@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$metadata['http://localhost:1080/simplesaml/idp'] = [
|
||||
'host' => '__DEFAULT__',
|
||||
'privatekey' => 'localhost.pem',
|
||||
'certificate' => 'localhost.crt',
|
||||
'auth' => 'example-userpass',
|
||||
];
|
||||
50
dist/simplesaml-dev/saml20-idp-remote.php
vendored
@@ -1,50 +0,0 @@
|
||||
<?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',
|
||||
];
|
||||
16
dist/simplesaml-dev/saml20-sp-remote.php
vendored
@@ -1,16 +0,0 @@
|
||||
<?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',
|
||||
],
|
||||
],
|
||||
];
|
||||
44
dist/sql/pvv_mysql.sql
vendored
@@ -1,44 +0,0 @@
|
||||
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
@@ -1,44 +0,0 @@
|
||||
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
@@ -1,15 +0,0 @@
|
||||
|
||||
-- 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'
|
||||
);
|
||||
21
docker-compose.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
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}"
|
||||
@@ -1,72 +0,0 @@
|
||||
# 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.
|
||||
6
flake.lock
generated
@@ -2,11 +2,11 @@
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1767364772,
|
||||
"narHash": "sha256-fFUnEYMla8b7UKjijLnMe+oVFOz6HjijGGNS1l7dYaQ=",
|
||||
"lastModified": 1765803225,
|
||||
"narHash": "sha256-xwaZV/UgJ04+ixbZZfoDE8IsOWjtvQZICh9aamzPnrg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "16c7794d0a28b5a37904d55bcca36003b9109aaa",
|
||||
"rev": "ac9a217389ee622d4e1e727c4efcc9c4bc9089ba",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
});
|
||||
|
||||
overlays.default = final: prev: {
|
||||
inherit (self.packages.${final.stdenv.hostPlatform.system}) pvv-nettsiden;
|
||||
inherit (self.packages.${final.system}) pvv-nettsiden;
|
||||
formats = prev.formats // {
|
||||
php = import ./nix/php-generator.nix { pkgs = prev; lib = prev.lib; };
|
||||
};
|
||||
|
||||
|
Before Width: | Height: | Size: 477 KiB After Width: | Height: | Size: 477 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
@@ -10,7 +10,7 @@ function navbar($depth, $active = null) {
|
||||
// 'Aktiviteter' => 'aktiviteter',
|
||||
'Prosjekter' => 'prosjekt',
|
||||
'Kontakt' => 'kontakt',
|
||||
// 'Webmail' => 'https://webmail.pvv.ntnu.no/roundcube/',
|
||||
'Webmail' => 'https://webmail.pvv.ntnu.no/roundcube/',
|
||||
'Galleri' => 'galleri',
|
||||
'Wiki' => 'https://wiki.pvv.ntnu.no/',
|
||||
'Git' => 'https://git.pvv.ntnu.no/',
|
||||
|
||||
@@ -4,38 +4,23 @@
|
||||
}:
|
||||
|
||||
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)
|
||||
]);
|
||||
};
|
||||
src = ./..;
|
||||
pname = "pvv-nettsiden";
|
||||
version = "0.0.1";
|
||||
vendorHash = "sha256-3+hX9tzC7IvU2bDKpPsfk/TH1ZxffTp+5k5ky5tP7yg=";
|
||||
vendorHash = "sha256-7I7Fdp5DvCwCdYY66Mv0hZ+a8xRzQt+WMUKG544k7Fc=";
|
||||
|
||||
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
|
||||
install -Dm644 dist/simplesamlphp-config.php $out/${passthru.simplesamlphpPath}/config/config.php
|
||||
install -Dm644 dist/simplesamlphp-authsources.php $out/${passthru.simplesamlphpPath}/config/authsources.php
|
||||
install -Dm644 dist/simplesamlphp-idp.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}"
|
||||
cp -r "${source_path}" "$out/${target_path}"
|
||||
''))
|
||||
(lib.concatStringsSep "\n")
|
||||
]}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ pkgs }:
|
||||
{ pkgs, lib }:
|
||||
let
|
||||
phpEnv = pkgs.php84.buildEnv {
|
||||
extensions = { enabled, all }: enabled ++ (with all; [ iconv mbstring pdo_mysql pdo_sqlite ]);
|
||||
@@ -12,6 +12,30 @@ pkgs.mkShellNoCC {
|
||||
php84Packages.php-cs-fixer
|
||||
sqlite-interactive
|
||||
sql-formatter
|
||||
openssl
|
||||
];
|
||||
|
||||
# Prepare dev environment with sqlite and config files
|
||||
shellHook = ''
|
||||
alias runDev='php -S localhost:1080 -d error_reporting=E_ALL -d display_errors=1 -t www/'
|
||||
|
||||
declare -a PROJECT_ROOT="$("${lib.getExe pkgs.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/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 $?
|
||||
|
||||
cp dist/simplesamlphp-authsources.php vendor/simplesamlphp/simplesamlphp/config/authsources.php
|
||||
cp dist/simplesamlphp-idp.php vendor/simplesamlphp/simplesamlphp/metadata/saml20-idp-remote.php
|
||||
cp dist/simplesamlphp-config.php vendor/simplesamlphp/simplesamlphp/config/config.php
|
||||
|
||||
cp dist/config.local.php config.php
|
||||
|
||||
ln -s ../vendor/simplesamlphp/simplesamlphp/public/ www/simplesaml
|
||||
popd
|
||||
fi
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
#!/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
|
||||
)
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/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"
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/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[@]}")
|
||||
@@ -1,48 +0,0 @@
|
||||
#!/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
|
||||
@@ -1,57 +0,0 @@
|
||||
#!/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
|
||||
@@ -56,41 +56,15 @@ class DBActivity implements Activity {
|
||||
}
|
||||
|
||||
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
|
||||
';
|
||||
$query
|
||||
= 'SELECT id,name,start,stop,organiser,location,description FROM events WHERE start > :date ORDER BY start ASC LIMIT 1';
|
||||
|
||||
return $this->retrieve($date, $query);
|
||||
}
|
||||
|
||||
public function getPreviousEventFrom(\DateTimeImmutable $date): ?Event {
|
||||
$query = '
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
start,
|
||||
stop,
|
||||
organiser,
|
||||
location,
|
||||
description
|
||||
FROM events
|
||||
WHERE
|
||||
start < :date
|
||||
ORDER BY start DESC
|
||||
LIMIT 1
|
||||
';
|
||||
$query
|
||||
= 'SELECT id,name,start,stop,organiser,location,description FROM events WHERE start < :date ORDER BY start DESC LIMIT 1';
|
||||
|
||||
return $this->retrieve($date, $query);
|
||||
}
|
||||
|
||||
@@ -4,135 +4,81 @@ declare(strict_types=1);
|
||||
|
||||
namespace pvv\side;
|
||||
|
||||
use DateTimeImmutable;
|
||||
|
||||
class DoorStatus {
|
||||
private DateTimeImmutable $time;
|
||||
private bool $open;
|
||||
|
||||
public function __construct(DateTimeImmutable $time, bool $open) {
|
||||
$this->time = $time;
|
||||
$this->open = $open;
|
||||
}
|
||||
|
||||
public function getTime(): DateTimeImmutable {
|
||||
return $this->time;
|
||||
}
|
||||
|
||||
public function getTimeStamp(): int {
|
||||
return $this->time->getTimestamp();
|
||||
}
|
||||
|
||||
public function isOpen(): bool {
|
||||
return $this->open;
|
||||
}
|
||||
}
|
||||
|
||||
class Door {
|
||||
private $pdo;
|
||||
|
||||
const DAYS_OF_DOOR_HISTORY = 7;
|
||||
|
||||
public function __construct(\PDO $pdo) {
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DoorStatus[]
|
||||
* @return array{time: int, open: bool}[]
|
||||
*/
|
||||
public function getAll(): array {
|
||||
$query = '
|
||||
SELECT
|
||||
time,
|
||||
open
|
||||
FROM door
|
||||
ORDER BY time DESC
|
||||
';
|
||||
$query = 'SELECT time, open FROM door ORDER BY time DESC';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->execute();
|
||||
|
||||
$result = array_map(
|
||||
function ($row) {
|
||||
return new DoorStatus(
|
||||
(new DateTimeImmutable)->setTimestamp((int) $row['time']),
|
||||
(bool) $row['open'],
|
||||
);
|
||||
},
|
||||
$statement->fetchAll(),
|
||||
);
|
||||
$doorEvents = [];
|
||||
foreach ($statement->fetchAll() as $row) {
|
||||
$doorEvents[] = [
|
||||
'time' => (int) $row['time'],
|
||||
'open' => (bool) $row['open'],
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
return $doorEvents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DoorStatus[]
|
||||
* @return array{time: int, open: bool}[]
|
||||
*/
|
||||
public function getEntriesAfter(\DateTimeImmutable $startTime): array {
|
||||
$timestamp = $startTime->getTimestamp();
|
||||
|
||||
$query = '
|
||||
SELECT
|
||||
time,
|
||||
open
|
||||
FROM door
|
||||
WHERE time > :startTime
|
||||
ORDER BY time DESC
|
||||
';
|
||||
$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->bindParam(':startTime', $startTime, \PDO::PARAM_STR);
|
||||
$statement->execute();
|
||||
|
||||
$result = array_map(
|
||||
function ($row) {
|
||||
return new DoorStatus(
|
||||
(new DateTimeImmutable)->setTimestamp((int) $row['time']),
|
||||
(bool) $row['open'],
|
||||
);
|
||||
},
|
||||
$statement->fetchAll(),
|
||||
);
|
||||
$doorEvents = [];
|
||||
foreach ($statement->fetchAll() as $row) {
|
||||
$doorEvents[] = [
|
||||
'time' => (int) $row['time'],
|
||||
'open' => (bool) $row['open'],
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
return $doorEvents;
|
||||
}
|
||||
|
||||
public function getCurrent(): ?DoorStatus {
|
||||
$query = '
|
||||
SELECT
|
||||
time,
|
||||
open
|
||||
FROM door
|
||||
ORDER BY time DESC
|
||||
LIMIT 1
|
||||
';
|
||||
/**
|
||||
* @return array{time: int, open: bool}
|
||||
*/
|
||||
public function getCurrent(): array {
|
||||
$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;
|
||||
return [
|
||||
'time' => (int) $row['time'],
|
||||
'open' => (bool) $row['open'],
|
||||
];
|
||||
}
|
||||
|
||||
private function removeOld(): void {
|
||||
$firstValidTime = time() - 60 * 60 * 24 * self::DAYS_OF_DOOR_HISTORY;
|
||||
$firstValidTime = time() - 60 * 60 * 24 * 7; // One week before now
|
||||
$query = 'DELETE FROM door WHERE time < :firstValid';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
$statement->bindParam(':firstValid', $firstValidTime, \PDO::PARAM_INT);
|
||||
$statement->bindParam(':firstValid', $firstValidTime, \PDO::PARAM_STR);
|
||||
$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->bindParam(':time', $time, \PDO::PARAM_STR);
|
||||
$statement->bindParam(':open', $open, \PDO::PARAM_STR);
|
||||
$statement->execute();
|
||||
|
||||
$this->removeOld();
|
||||
|
||||
@@ -4,35 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace pvv\side;
|
||||
|
||||
class MOTDItem {
|
||||
private string $title;
|
||||
/** @var string[] */
|
||||
private array $content;
|
||||
|
||||
/**
|
||||
* @param string[] $content
|
||||
*/
|
||||
public function __construct(string $title, array $content) {
|
||||
$this->title = $title;
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
public function getTitle(): string {
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getContent(): array {
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function getContentAsString(): string {
|
||||
return implode("\n", $this->content);
|
||||
}
|
||||
}
|
||||
|
||||
class MOTD {
|
||||
private $pdo;
|
||||
|
||||
@@ -44,7 +15,7 @@ class MOTD {
|
||||
if (\is_array($content)) {
|
||||
$content = implode('_', $content);
|
||||
}
|
||||
$query = 'INSERT INTO motd(title, content) VALUES (:title, :content)';
|
||||
$query = 'INSERT INTO motd(title, content) VALUES (:title, :content);';
|
||||
$statement = $this->pdo->prepare($query);
|
||||
|
||||
$statement->bindParam(':title', $title, \PDO::PARAM_STR);
|
||||
@@ -53,54 +24,32 @@ class MOTD {
|
||||
$statement->execute();
|
||||
}
|
||||
|
||||
public function getMOTD(): MOTDItem {
|
||||
$query = '
|
||||
SELECT
|
||||
title,
|
||||
content
|
||||
FROM motd
|
||||
ORDER BY id DESC
|
||||
LIMIT 1
|
||||
';
|
||||
/**
|
||||
* @return array{title: string, content: string[]}
|
||||
*/
|
||||
public function getMOTD(): array {
|
||||
$query
|
||||
= 'SELECT motd.title, motd.content FROM motd ORDER BY motd.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 ['title' => $data[0], 'content' => explode("\n", $data[1])];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MOTDItem[]
|
||||
* @return array{title: string, content: string[]}
|
||||
*/
|
||||
public function getMOTD_history(int $limit = 5): array {
|
||||
$query = '
|
||||
SELECT
|
||||
title,
|
||||
content
|
||||
FROM motd
|
||||
ORDER BY id DESC
|
||||
LIMIT :limit
|
||||
';
|
||||
$query
|
||||
= 'SELECT motd.title, motd.content FROM motd ORDER BY motd.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(),
|
||||
);
|
||||
$data = $statement->fetch();
|
||||
|
||||
return $result;
|
||||
return ['title' => $data[0], 'content' => explode("\n", $data[1])];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ class ProjectManager {
|
||||
$dbProj['id'],
|
||||
$dbProj['name'],
|
||||
$dbProj['description'],
|
||||
(bool) $dbProj['active'],
|
||||
$dbProj['active'],
|
||||
);
|
||||
$projects[] = $project;
|
||||
}
|
||||
@@ -48,7 +48,7 @@ class ProjectManager {
|
||||
$dbProj['id'],
|
||||
$dbProj['name'],
|
||||
$dbProj['description'],
|
||||
(bool) $dbProj['active'],
|
||||
$dbProj['active'],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ class ProjectManager {
|
||||
$dbProj['id'],
|
||||
$dbProj['name'],
|
||||
$dbProj['description'],
|
||||
(bool) $dbProj['active'],
|
||||
$dbProj['active'],
|
||||
);
|
||||
$projects[] = $project;
|
||||
}
|
||||
@@ -101,8 +101,8 @@ class ProjectManager {
|
||||
'uname' => $dbUsr['uname'],
|
||||
'mail' => $dbUsr['mail'],
|
||||
'role' => $dbUsr['role'],
|
||||
'lead' => (bool) $dbUsr['lead'],
|
||||
'owner' => (bool) $dbUsr['owner'],
|
||||
'lead' => $dbUsr['lead'],
|
||||
'owner' => $dbUsr['owner'],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -125,8 +125,8 @@ class ProjectManager {
|
||||
'uname' => $dbOwner['uname'],
|
||||
'mail' => $dbOwner['mail'],
|
||||
'role' => $dbOwner['role'],
|
||||
'lead' => (bool) $dbOwner['lead'],
|
||||
'owner' => (bool) $dbOwner['owner'],
|
||||
'lead' => $dbOwner['lead'],
|
||||
'owner' => $dbOwner['owner'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
31
www/.well-known/autoconfig/mail/config-v1.1.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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>
|
||||
3
www/.well-known/matrix/server
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"m.server": "matrix.pvv.ntnu.no:443"
|
||||
}
|
||||
@@ -25,4 +25,4 @@ $statement->execute();
|
||||
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>
|
||||
@@ -70,12 +70,7 @@ if ($start_date >= $stop_date) {
|
||||
|
||||
|
||||
if ($id == 0) {
|
||||
$query = '
|
||||
INSERT INTO
|
||||
events(name, start, stop, organiser, location, description)
|
||||
VALUES
|
||||
(:title, :start, :stop, :organiser, :loc, :desc)
|
||||
';
|
||||
$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);
|
||||
@@ -85,19 +80,7 @@ if ($id == 0) {
|
||||
$statement->bindParam(':organiser', $organiser, PDO::PARAM_STR);
|
||||
$statement->bindParam(':loc', $location, PDO::PARAM_STR);
|
||||
} else {
|
||||
$query = '
|
||||
UPDATE
|
||||
events
|
||||
SET
|
||||
name = :title,
|
||||
start = :start,
|
||||
stop = :stop,
|
||||
organiser = :organiser,
|
||||
location = :loc,
|
||||
description = :desc
|
||||
WHERE
|
||||
id = :id
|
||||
';
|
||||
$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);
|
||||
|
||||
@@ -44,21 +44,23 @@ if (!($isAdmin | $projectGroup | $activityGroup)) {
|
||||
<main>
|
||||
<h2>Administrasjon</h2>
|
||||
<ul class="tools">
|
||||
<?php if ($isAdmin | $activityGroup) : ?>
|
||||
<li><a class="btn" href="aktiviteter/?page=1">Aktiviteter/Hendelser</a></li>
|
||||
<?php endif ?>
|
||||
<?php
|
||||
if ($isAdmin | $activityGroup) {
|
||||
echo '<li><a class="btn" href="aktiviteter/?page=1">Aktiviteter/Hendelser</a></li>';
|
||||
}
|
||||
|
||||
<?php if ($isAdmin | $projectGroup) : ?>
|
||||
<li><a class="btn" href="prosjekter/?page=1">Prosjekter</a></li>
|
||||
<?php endif ?>
|
||||
if ($isAdmin | $projectGroup) {
|
||||
echo '<li><a class="btn" href="prosjekter/">Prosjekter</a></li>';
|
||||
}
|
||||
|
||||
<?php if ($isAdmin) : ?>
|
||||
<li><a class="btn" href="motd/">Dagens melding</a></li>
|
||||
<?php endif ?>
|
||||
if ($isAdmin) {
|
||||
echo '<li><a class="btn" href="motd/">Dagens melding</a></li>';
|
||||
}
|
||||
|
||||
<?php if ($isAdmin) : ?>
|
||||
<li><a class="btn" href="brukere/">Brukerrettigheter</a></li>
|
||||
<?php endif ?>
|
||||
if ($isAdmin) {
|
||||
echo '<li><a class="btn" href="brukere/">Brukerrettigheter</a></li>';
|
||||
}
|
||||
?>
|
||||
<ul>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
@@ -56,10 +56,10 @@ $motd = $motdfetcher->getMOTD();
|
||||
<form action="update.php", method="post">
|
||||
<p class="subtitle no-chin">Tittel</p>
|
||||
<p class="subnote">Ikke nødvendig</p>
|
||||
<input type="text" name="title" value="<?php echo $motd->getTitle(); ?>" class="boxinput" style="width:66%;"><br>
|
||||
<input type="text" name="title" value="<?php echo $motd['title']; ?>" class="boxinput" style="width:66%;"><br>
|
||||
|
||||
<p class="subtitle no-chin">Innhold (<i>markdown</i>)</p>
|
||||
<textarea name="content" style="width:100%" rows="8" class="boxinput"><?php echo $motd->getContentAsString(); ?></textarea>
|
||||
<textarea name="content" style="width:100%" rows="8" class="boxinput"><?php echo implode("\n", $motd['content']); ?></textarea>
|
||||
|
||||
<div style="margin-top: 2em;">
|
||||
<hr class="ruler">
|
||||
|
||||
@@ -25,4 +25,4 @@ $statement->execute();
|
||||
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>
|
||||
@@ -37,12 +37,7 @@ $active = ($_POST['active'] ?? false);
|
||||
|
||||
|
||||
if ($id == 0) {
|
||||
$query = '
|
||||
INSERT INTO
|
||||
projects(name, description, active)
|
||||
VALUES
|
||||
(:title, :desc, :active)
|
||||
';
|
||||
$query = 'INSERT INTO projects (name, description, active) VALUES (:title, :desc, :active)';
|
||||
$statement = $pdo->prepare($query);
|
||||
|
||||
$statement->bindParam(':title', $title, PDO::PARAM_STR);
|
||||
@@ -51,12 +46,7 @@ if ($id == 0) {
|
||||
|
||||
$statement->execute();
|
||||
|
||||
$ownerQuery = '
|
||||
INSERT INTO
|
||||
projectmembers(projectid, name, uname, mail, role, lead, owner)
|
||||
VALUES
|
||||
(last_insert_rowid(), :owner, :owneruname, :owneremail, \'Prosjektleder\', 1, 1)
|
||||
';
|
||||
$ownerQuery = 'INSERT INTO projectmembers (projectid, name, uname, mail, role, lead, owner) VALUES (last_insert_rowid(), :owner, :owneruname, :owneremail, \'Prosjektleder\', 1, 1)';
|
||||
$statement = $pdo->prepare($ownerQuery);
|
||||
$statement->bindParam(':owner', $name, PDO::PARAM_STR);
|
||||
$statement->bindParam(':owneruname', $uname, PDO::PARAM_STR);
|
||||
@@ -64,16 +54,7 @@ if ($id == 0) {
|
||||
|
||||
$statement->execute();
|
||||
} else {
|
||||
$query = '
|
||||
UPDATE
|
||||
projects
|
||||
SET
|
||||
name = :title,
|
||||
description = :desc,
|
||||
active = :active
|
||||
WHERE
|
||||
id = :id
|
||||
';
|
||||
$query = 'UPDATE projects SET name=:title, description=:desc, active=:active WHERE id=:id';
|
||||
$statement = $pdo->prepare($query);
|
||||
|
||||
$statement->bindParam(':title', $title, PDO::PARAM_STR);
|
||||
@@ -83,14 +64,7 @@ if ($id == 0) {
|
||||
|
||||
$statement->execute();
|
||||
|
||||
$query = '
|
||||
UPDATE
|
||||
projectmembers
|
||||
SET
|
||||
name = :name,
|
||||
uname = :uname,
|
||||
mail = :mail
|
||||
';
|
||||
$query = 'UPDATE projectmembers SET name=:name, uname=:uname, mail=:mail';
|
||||
$statement = $pdo->prepare($query);
|
||||
|
||||
$statement->bindParam(':name', $name, PDO::PARAM_STR);
|
||||
|
||||
1
www/css/afterlogic.svg
Normal file
@@ -0,0 +1 @@
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
73
www/css/mail.css
Normal file
@@ -0,0 +1,73 @@
|
||||
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;
|
||||
}
|
||||
BIN
www/css/rainloop.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
www/css/roundcube.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
@@ -4,88 +4,116 @@ main {
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
|
||||
.serviceGrid {
|
||||
.serviceWrapper {
|
||||
width: 80%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 1.5rem;
|
||||
padding: 2rem;
|
||||
margin: 50px 2%;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 1em;
|
||||
|
||||
margin: auto auto;
|
||||
margin-top: 4em;
|
||||
}
|
||||
|
||||
/* Base styles for all cards */
|
||||
.baseServiceCard {
|
||||
.categoryContainer {
|
||||
border: 4px solid #002244;
|
||||
border-radius: 5px;
|
||||
|
||||
box-shadow : 0 0 20px #002244;
|
||||
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.categoryLabel {
|
||||
padding-top: 5px;
|
||||
background-color: #002244;
|
||||
color: white;
|
||||
|
||||
padding-left: 10px;
|
||||
|
||||
font-family: monospace;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.service {
|
||||
border: 2px solid #002244;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
|
||||
display: flex;
|
||||
gap: 0.6rem;
|
||||
padding: 1rem;
|
||||
border-radius: 14px;
|
||||
|
||||
box-shadow: 0 8px 8px rgba(0, 0, 0, 0.3);
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
/* Category Title Card Styling */
|
||||
|
||||
.categoryTitleCard {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
|
||||
box-shadow: none;
|
||||
min-height: 140px;
|
||||
}
|
||||
|
||||
.categoryTitle {
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
/* Service Card Styling */
|
||||
|
||||
.serviceCard {
|
||||
display: flex;
|
||||
gap: 0.6rem;
|
||||
padding: 1rem;
|
||||
border-radius: 14px;
|
||||
|
||||
height: fit-content;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
/*.serviceCard:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.12);
|
||||
}*/
|
||||
|
||||
.serviceContent {
|
||||
flex: 1;
|
||||
flex-grow: 1;
|
||||
margin-right: 4%;
|
||||
}
|
||||
|
||||
.serviceTitle {
|
||||
margin: 0 0 0.5rem;
|
||||
font-size: 1.2rem;
|
||||
margin: 0.2em !important;
|
||||
}
|
||||
|
||||
.serviceDescription {
|
||||
margin: 0 0 1rem;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.5;
|
||||
margin-top: 0px !important;
|
||||
}
|
||||
|
||||
.serviceLink a {
|
||||
color: #0066cc;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
|
||||
.serviceDescription::before {
|
||||
content: " - ";
|
||||
font-size: 18px;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.serviceLink a:hover {
|
||||
text-decoration: underline;
|
||||
.serviceLink {
|
||||
width: 70%;
|
||||
padding-bottom: 5px;
|
||||
border-radius: 5px;
|
||||
border: 2px solid #002244;
|
||||
padding: 7px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.serviceLink > a {
|
||||
margin-bottom: 10px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.serviceImage {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
object-fit: contain;
|
||||
align-self: flex-start;
|
||||
flex-shrink: 1;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
|
||||
margin: auto auto;
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.serviceWrapper {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.categoryContainer {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.categoryContainer {
|
||||
border-radius: unset;
|
||||
border: unset;
|
||||
box-shadow: unset;
|
||||
margin-bottom: unset;
|
||||
}
|
||||
.serviceWrapper {
|
||||
width: 100%;
|
||||
}
|
||||
.serviceImage {
|
||||
width: 25%;
|
||||
height: auto;
|
||||
}
|
||||
.serviceContent {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 360px) {
|
||||
.serviceContent {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
BIN
www/css/squirrelmail.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
13
www/door/chart.min.js
vendored
Normal file
8
www/door/chartjs-adapter-moment.js
Normal file
@@ -0,0 +1,8 @@
|
||||
/*!
|
||||
* chartjs-adapter-moment v1.0.0
|
||||
* https://www.chartjs.org
|
||||
* (c) 2021 chartjs-adapter-moment Contributors
|
||||
* Released under the MIT license
|
||||
*/
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("moment"),require("chart.js")):"function"==typeof define&&define.amd?define(["moment","chart.js"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).moment,e.Chart)}(this,(function(e,t){"use strict";function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var f=n(e);const a={datetime:"MMM D, YYYY, h:mm:ss a",millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm a",hour:"hA",day:"MMM D",week:"ll",month:"MMM YYYY",quarter:"[Q]Q - YYYY",year:"YYYY"};t._adapters._date.override("function"==typeof f.default?{_id:"moment",formats:function(){return a},parse:function(e,t){return"string"==typeof e&&"string"==typeof t?e=f.default(e,t):e instanceof f.default||(e=f.default(e)),e.isValid()?e.valueOf():null},format:function(e,t){return f.default(e).format(t)},add:function(e,t,n){return f.default(e).add(t,n).valueOf()},diff:function(e,t,n){return f.default(e).diff(f.default(t),n)},startOf:function(e,t,n){return e=f.default(e),"isoWeek"===t?(n=Math.trunc(Math.min(Math.max(0,n),6)),e.isoWeekday(n).startOf("day").valueOf()):e.startOf(t).valueOf()},endOf:function(e,t){return f.default(e).endOf(t).valueOf()}}:{})}));
|
||||
//# sourceMappingURL=chartjs-adapter-moment.min.js.map
|
||||
145
www/door/graph.html
Normal file
@@ -0,0 +1,145 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Inngangsverkstedet</title>
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
width: 80vw;
|
||||
margin: auto auto;
|
||||
}
|
||||
#graphDiv {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>En kort analyse av nerders døgnrytme i deres naturlige habitat, PVV</h2>
|
||||
<div id="graphDiv">
|
||||
<h4>Siste 24 timer</h4>
|
||||
<canvas id="doorGraphDay"></canvas>
|
||||
<h4>Siste 7 dager</h4>
|
||||
<canvas id="doorGraphWeek"></canvas>
|
||||
</div>
|
||||
|
||||
<script src="chart.min.js"></script>
|
||||
<script src="moment.js"></script>
|
||||
<script src="chartjs-adapter-moment.js"></script>
|
||||
<script>
|
||||
|
||||
const graphElDay = document.getElementById("doorGraphDay");
|
||||
const graphElWeek = document.getElementById("doorGraphWeek");
|
||||
|
||||
const XHR = new XMLHttpRequest();
|
||||
const url="/door/?period=week";
|
||||
XHR.open("GET", url);
|
||||
XHR.send();
|
||||
|
||||
|
||||
XHR.onreadystatechange = ()=>{
|
||||
if (XHR.readyState == 4 && XHR.status == 200) {
|
||||
console.log("Response 200 from API")
|
||||
response = JSON.parse(XHR.responseText); //Should be try-catched?
|
||||
if (response.status != "OK") {
|
||||
console.log("Error when connecting to API.");
|
||||
return
|
||||
} else {
|
||||
const allDatapoints = response.entries;
|
||||
console.log("Success, " + allDatapoints.length + " datapoints received.");
|
||||
|
||||
const dayDatapoints = getLastDay(allDatapoints);
|
||||
|
||||
displayLineDiagram(graphElDay, dayDatapoints, "hour");
|
||||
displayLineDiagram(graphElWeek, allDatapoints, "day");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getLastDay(data) {
|
||||
let date = new Date();
|
||||
let curTime = date.getTime();
|
||||
let targetTime = parseInt(curTime/1e3) - (60*60*24);
|
||||
|
||||
let i;
|
||||
for (i = 0; i < data.length; i++) {
|
||||
if (data[i].time < targetTime) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return data.slice(0, i);
|
||||
}
|
||||
|
||||
function displayLineDiagram(canv, data, timeunit) {
|
||||
let ctx = canv.getContext("2d");
|
||||
let dotColor = data.map(entry => entry.open ? "rgb(10, 150, 10)" : "rgb(200, 100, 100)");
|
||||
|
||||
let chart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: data.map(entry=> 1e3 * entry.time),
|
||||
datasets: [{
|
||||
data: data.map(entry => entry.open),
|
||||
stepped: "before",
|
||||
borderColor: dotColor,
|
||||
backgroundColor: dotColor
|
||||
}],
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
xAxis: {
|
||||
type: "time",
|
||||
time: {
|
||||
unit: timeunit
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
suggestedMin: -0.1,
|
||||
suggestedMax: 1.1,
|
||||
grid: {display: false},
|
||||
ticks: {
|
||||
callback: function(label, index, labels) {
|
||||
if (label == 0) {
|
||||
return "Stengt";
|
||||
} else if (label == 1) {
|
||||
return "Åpent";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function(tooltipItem) {
|
||||
const value = tooltipItem.formattedValue;
|
||||
if (value == 0) {
|
||||
return "Stengt";
|
||||
} else if (value == 1) {
|
||||
return "Åpent";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,186 +0,0 @@
|
||||
<?php
|
||||
require_once dirname(__DIR__, 2) . implode(\DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']);
|
||||
?>
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="../css/normalize.css">
|
||||
<link rel="stylesheet" href="../css/style.css">
|
||||
<link rel="stylesheet" href="../css/nav.css">
|
||||
<link rel="stylesheet" href="../css/events.css">
|
||||
<meta name="theme-color" content="#024" />
|
||||
<title>Inngangsverkstedet</title>
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
width: 80vw;
|
||||
margin: auto auto;
|
||||
}
|
||||
|
||||
#graphDiv {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.graphbox {
|
||||
margin: 20px;
|
||||
padding: 10px;
|
||||
border: 5px solid #00407F;
|
||||
border-radius: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav id="navbar" class="">
|
||||
<?php echo navbar(1, ''); ?>
|
||||
<?php echo loginbar(null, $pdo); ?>
|
||||
</nav>
|
||||
|
||||
<main style="margin: 5em 0 2em 0;">
|
||||
<h2>En kort analyse av nerders døgnrytme i deres naturlige habitat, PVV</h2>
|
||||
<div id="graphDiv">
|
||||
<h4>Siste 24 timer</h4>
|
||||
<div class="graphbox">
|
||||
<canvas id="doorGraphDay"></canvas>
|
||||
</div>
|
||||
|
||||
<h4>Siste 7 dager</h4>
|
||||
<div class="graphbox">
|
||||
<canvas id="doorGraphWeek"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/chart.js@4.5.1/dist/chart.umd.min.js"
|
||||
integrity="sha384-jb8JQMbMoBUzgWatfe6COACi2ljcDdZQ2OxczGA3bGNeWe+6DChMTBJemed7ZnvJ"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/moment@2.30.1/moment.min.js"
|
||||
integrity="sha384-+EEFFjsGn4BnW70Nv0OvoMe1VZuqS4xvx90V2MTeuYUUZSEabg7FSMWl6s2DJTAO"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment@1.0.1/dist/chartjs-adapter-moment.min.js"
|
||||
integrity="sha384-s5cwu7c1MxOfC90RGRDWeB53/7VpDTxXi0YxKJF5y9oKA99+UYxMk0qvlqso188s"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
|
||||
<script>
|
||||
const graphElDay = document.getElementById("doorGraphDay");
|
||||
const graphElWeek = document.getElementById("doorGraphWeek");
|
||||
|
||||
const XHR = new XMLHttpRequest();
|
||||
const url = "/door/?period=week";
|
||||
XHR.open("GET", url);
|
||||
XHR.send();
|
||||
|
||||
XHR.onreadystatechange = () => {
|
||||
if (XHR.readyState == 4 && XHR.status == 200) {
|
||||
console.log("Response 200 from API");
|
||||
response = JSON.parse(XHR.responseText); //Should be try-catched?
|
||||
if (response.status != "OK") {
|
||||
console.log("Error when connecting to API.");
|
||||
return;
|
||||
} else {
|
||||
const allDatapoints = response.entries;
|
||||
console.log(
|
||||
"Success, " + allDatapoints.length + " datapoints received.",
|
||||
);
|
||||
|
||||
const dayDatapoints = getLastDay(allDatapoints);
|
||||
|
||||
displayLineDiagram(graphElDay, dayDatapoints, "hour");
|
||||
displayLineDiagram(graphElWeek, allDatapoints, "day");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function getLastDay(data) {
|
||||
let date = new Date();
|
||||
let curTime = date.getTime();
|
||||
let targetTime = parseInt(curTime / 1e3) - 60 * 60 * 24;
|
||||
|
||||
let i;
|
||||
for (i = 0; i < data.length; i++) {
|
||||
if (data[i].time < targetTime) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return data.slice(0, i);
|
||||
}
|
||||
|
||||
function displayLineDiagram(canv, data, timeunit) {
|
||||
let ctx = canv.getContext("2d");
|
||||
let dotColor = data.map((entry) =>
|
||||
entry.open ? "rgb(10, 150, 10)" : "rgb(200, 100, 100)",
|
||||
);
|
||||
|
||||
let chart = new Chart(ctx, {
|
||||
type: "line",
|
||||
data: {
|
||||
labels: data.map((entry) => 1e3 * entry.time),
|
||||
datasets: [
|
||||
{
|
||||
data: data.map((entry) => entry.open),
|
||||
stepped: "before",
|
||||
segment: {
|
||||
borderColor: (ctx) =>
|
||||
ctx.p0.parsed.y === 1
|
||||
? "rgb(10, 150, 10)"
|
||||
: "rgb(200, 100, 100)",
|
||||
},
|
||||
borderColor: dotColor,
|
||||
backgroundColor: dotColor,
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
x: {
|
||||
type: "time",
|
||||
display: true,
|
||||
time: {
|
||||
unit: timeunit,
|
||||
},
|
||||
ticks: {
|
||||
display: true,
|
||||
source: "data",
|
||||
},
|
||||
grid: {
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
y: {
|
||||
suggestedMin: -0.1,
|
||||
suggestedMax: 1.1,
|
||||
grid: { display: false },
|
||||
ticks: {
|
||||
callback: (label, index, labels) =>
|
||||
label === 1 ? "Åpent" : label === 0 ? "Stengt" : "",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: (tooltipItem) =>
|
||||
tooltipItem.formattedValue === "1" ? "Åpent" : "Stengt",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -31,13 +31,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$period = (string) htmlspecialchars($_GET['period']);
|
||||
|
||||
if ($period == 'day') {
|
||||
$startTime = (new \DateTimeImmutable())
|
||||
->setTimestamp(time())
|
||||
->sub(new \DateInterval('P1D'));
|
||||
$startTime = time() - (60 * 60 * 24);
|
||||
} elseif ($period == 'week') {
|
||||
$startTime = (new \DateTimeImmutable())
|
||||
->setTimestamp(time())
|
||||
->sub(new \DateInterval('P1W'));
|
||||
$startTime = time() - (60 * 60 * 24 * 7);
|
||||
} else {
|
||||
echo '{"status": "error", "message": "Invalid period"}';
|
||||
exit;
|
||||
@@ -50,28 +46,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'status' => 'OK',
|
||||
'entries' => array_map(
|
||||
function ($line) {
|
||||
return [
|
||||
'time' => $line->getTimestamp(),
|
||||
'open' => $line->isOpen(),
|
||||
];
|
||||
},
|
||||
$lines
|
||||
),
|
||||
'status' => 'OK',
|
||||
'entries' => $lines,
|
||||
]);
|
||||
} else {
|
||||
// Only last entry
|
||||
$line = $door->getCurrent();
|
||||
if (is_null($line)) {
|
||||
echo '{"status": "error", "message": "No door data"}';
|
||||
exit;
|
||||
}
|
||||
$line = (object) $door->getCurrent();
|
||||
echo json_encode([
|
||||
'status' => 'OK',
|
||||
'time' => $line->getTimestamp(),
|
||||
'open' => $line->isOpen(),
|
||||
'status' => 'OK',
|
||||
'time' => $line->time,
|
||||
'open' => $line->open,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -92,9 +76,7 @@ function handleSetState(): void {
|
||||
exit;
|
||||
}
|
||||
|
||||
$time = (new \DateTimeImmutable())->setTimestamp((int) $event->time);
|
||||
|
||||
$door->createEvent($time, $event->isDoorOpen);
|
||||
$door->createEvent((int) $event->time, $event->isDoorOpen ? 1 : 0);
|
||||
echo '{"status": "OK"}';
|
||||
}
|
||||
|
||||
@@ -103,9 +85,9 @@ function getChanges($items) {
|
||||
$res = [];
|
||||
|
||||
foreach ($items as $item) {
|
||||
if ($item->isOpen() !== $prevState) {
|
||||
if ($item['open'] !== $prevState) {
|
||||
$res[] = $item;
|
||||
$prevState = $item->isOpen();
|
||||
$prevState = $item['open'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
5670
www/door/moment.js
Normal file
@@ -1,7 +1,4 @@
|
||||
<?php
|
||||
|
||||
use pvv\side\DoorStatus;
|
||||
|
||||
require_once dirname(__DIR__) . implode(\DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']);
|
||||
|
||||
$translation = ['I dag', 'I morgen', 'Denne uka', 'Neste uke', 'Denne måneden', 'Neste måned'];
|
||||
@@ -12,24 +9,17 @@ $motdfetcher = new pvv\side\MOTD($pdo);
|
||||
$motd = $motdfetcher->getMOTD();
|
||||
|
||||
$door = new pvv\side\Door($pdo);
|
||||
$doorEntry = $door->getCurrent();
|
||||
if (is_null($doorEntry)) {
|
||||
$doorEntry = new DoorStatus(
|
||||
new DateTimeImmutable('@0'),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
if ($doorEntry->getTimestamp() < (time() - 60 * 30)) {
|
||||
$doorEntry = (object) $door->getCurrent();
|
||||
if ($doorEntry->time < (time() - 60 * 30)) {
|
||||
$doorStateText = 'Ingen data fra dørsensor';
|
||||
} else {
|
||||
if ($doorEntry->isOpen()) {
|
||||
if ($doorEntry->open) {
|
||||
$doorStateText = 'Døren er <b>åpen</b>';
|
||||
} else {
|
||||
$doorStateText = 'Døren er <b>ikke åpen</b>';
|
||||
}
|
||||
}
|
||||
$doorTime = $doorEntry->getTime()->format('H:i');
|
||||
$doorTime = date('H:i', $doorEntry->time);
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="no">
|
||||
@@ -65,7 +55,7 @@ $doorTime = $doorEntry->getTime()->format('H:i');
|
||||
<a class="btn" href="om/"><li>Om PVV</li></a>
|
||||
<a class="btn focus" href="paamelding/"><li>Bli medlem!</li></a>
|
||||
<a class="btn" href="https://use.mazemap.com/#config=ntnu&v=1&zlevel=2¢er=10.406281,63.417093&zoom=19.5&campuses=ntnu&campusid=1&sharepoitype=poi&sharepoi=38159&utm_medium=longurl">Veibeskrivelse</li></a>
|
||||
<div id="doorIndicator" class="<?php echo $doorEntry->isOpen() ? 'doorIndicator_OPEN' : 'doorIndicator_CLOSED'; ?>" onclick="location.href='/door/graph.php'">
|
||||
<div id="doorIndicator" class="<?php echo $doorEntry->open ? 'doorIndicator_OPEN' : 'doorIndicator_CLOSED'; ?>" onclick="location.href='/door/graph.html'">
|
||||
<p class="doorStateText"><?php echo $doorStateText; ?></p>
|
||||
<p class="doorStateTime">(Oppdatert <?php echo $doorTime; ?>)</p>
|
||||
</div>
|
||||
@@ -120,7 +110,7 @@ $doorTime = $doorEntry->getTime()->format('H:i');
|
||||
|
||||
<div class="gridl">
|
||||
<?php
|
||||
$title = $motd->getTitle();
|
||||
$title = $motd['title'];
|
||||
|
||||
echo '<h1>';
|
||||
if ($title == '') {
|
||||
@@ -131,7 +121,7 @@ $doorTime = $doorEntry->getTime()->format('H:i');
|
||||
echo '</h1>';
|
||||
|
||||
$Parsedown = new Parsedown();
|
||||
echo $Parsedown->text($motd->getContentAsString());
|
||||
echo $Parsedown->text(implode("\n", $motd['content']));
|
||||
?>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -30,7 +30,7 @@ $mail = $attrs['mail'][0];
|
||||
|
||||
|
||||
if ($id == 0) {
|
||||
$query = 'INSERT INTO projects (name, description, active) VALUES (:title, :desc, TRUE)';
|
||||
$query = 'INSERT INTO projects (name, description, active) VALUES (:title, :desc, 1)';
|
||||
$statement = $pdo->prepare($query);
|
||||
|
||||
$statement->bindParam(':title', $title, PDO::PARAM_STR);
|
||||
@@ -39,7 +39,7 @@ if ($id == 0) {
|
||||
$statement->execute();
|
||||
$new_id = $pdo->lastInsertId();
|
||||
|
||||
$ownerQuery = "INSERT INTO projectmembers (projectid, name, uname, mail, role, lead, owner) VALUES (:id, :owner, :owneruname, :owneremail, 'Prosjektleder', TRUE, TRUE)";
|
||||
$ownerQuery = "INSERT INTO projectmembers (projectid, name, uname, mail, role, lead, owner) VALUES (:id, :owner, :owneruname, :owneremail, 'Prosjektleder', 1, 1)";
|
||||
$statement = $pdo->prepare($ownerQuery);
|
||||
$statement->bindParam(':id', $new_id, PDO::PARAM_STR);
|
||||
$statement->bindParam(':owner', $name, PDO::PARAM_STR);
|
||||
@@ -62,7 +62,7 @@ if ($id == 0) {
|
||||
}
|
||||
}
|
||||
if ($is_member) {// leave
|
||||
$query = 'DELETE FROM projectmembers WHERE projectid=:id AND uname=:uname and lead=FALSE and owner=FALSE;';
|
||||
$query = 'DELETE FROM projectmembers WHERE projectid=:id AND uname=:uname and lead=0 and owner=0;';
|
||||
$statement = $pdo->prepare($query);
|
||||
$statement->bindParam(':id', $id, PDO::PARAM_STR);
|
||||
$statement->bindParam(':uname', $uname, PDO::PARAM_STR);
|
||||
@@ -70,7 +70,7 @@ if ($id == 0) {
|
||||
$statement->execute();
|
||||
echo 'leave';
|
||||
} else {// join
|
||||
$query = "INSERT INTO projectmembers (projectid, name, uname, mail, role, lead, owner) VALUES (:id, :name, :uname, :mail, 'Medlem', FALSE, FALSE)";
|
||||
$query = "INSERT INTO projectmembers (projectid, name, uname, mail, role, lead, owner) VALUES (:id, :name, :uname, :mail, 'Medlem', 0, 0)";
|
||||
$statement = $pdo->prepare($query);
|
||||
$statement->bindParam(':id', $id, PDO::PARAM_STR);
|
||||
$statement->bindParam(':name', $name, PDO::PARAM_STR);
|
||||
|
||||
@@ -9,15 +9,7 @@ $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$door = new pvv\side\Door($pdo);
|
||||
$doorEntry = $door->getCurrent();
|
||||
// if (!is_null($doorEntry)) {
|
||||
// $doorEntry = (object) $doorEntry;
|
||||
// } else {
|
||||
// $doorEntry = (object) [
|
||||
// 'time' => new DateTimeImmutable('@0'),
|
||||
// 'open' => false,
|
||||
// ];
|
||||
// }
|
||||
$doorEntry = (object) $door->getCurrent();
|
||||
|
||||
?>
|
||||
{
|
||||
@@ -43,9 +35,9 @@ $doorEntry = $door->getCurrent();
|
||||
},
|
||||
"issue_report_channels": ["email"],
|
||||
"state": {
|
||||
"open": <?php echo $doorEntry->isOpen() ? 'true' : 'false'; ?>,
|
||||
"lastchange": <?php echo $doorEntry->getTimeStamp(); ?>,
|
||||
"message": "<?php echo $doorEntry->isOpen() ? 'open for public, members are present' : 'closed'; ?>"
|
||||
"open": <?php echo $doorEntry->open ? 'true' : 'false'; ?>,
|
||||
"lastchange": <?php echo $doorEntry->time ? $doorEntry->time : 0; ?>,
|
||||
"message": "<?php echo $doorEntry->open ? 'open for public, members are present' : 'closed'; ?>"
|
||||
},
|
||||
"feeds": {
|
||||
"wiki": {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 239 B |
@@ -1,57 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="16" height="16" viewBox="0 0 4.2333332 4.2333335" version="1.1" id="svg1468" sodipodi:docname="codeberg-logo_icon_blue.svg" inkscape:version="1.2-alpha1 (b6a15bb, 2022-02-23)" inkscape:export-filename="/home/mray/Projects/Codeberg/logo/icon/png/codeberg-logo_icon_blue.png" inkscape:export-xdpi="384" inkscape:export-ydpi="384" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<title id="title16">Codeberg logo</title>
|
||||
<defs id="defs1462">
|
||||
<linearGradient xlink:href="#linearGradient6924" id="linearGradient6918" x1="42519.285" y1="-7078.7891" x2="42575.336" y2="-6966.9307" gradientUnits="userSpaceOnUse"/>
|
||||
<linearGradient id="linearGradient6924">
|
||||
<stop style="stop-color:#2185d0;stop-opacity:0" offset="0" id="stop6920"/>
|
||||
<stop id="stop6926" offset="0.49517274" style="stop-color:#2185d0;stop-opacity:0.48923996"/>
|
||||
<stop style="stop-color:#2185d0;stop-opacity:0.63279623" offset="1" id="stop6922"/>
|
||||
</linearGradient>
|
||||
<linearGradient xlink:href="#linearGradient6924-6" id="linearGradient6918-3" x1="42519.285" y1="-7078.7891" x2="42575.336" y2="-6966.9307" gradientUnits="userSpaceOnUse"/>
|
||||
<linearGradient id="linearGradient6924-6">
|
||||
<stop style="stop-color:#2185d0;stop-opacity:0;" offset="0" id="stop6920-7"/>
|
||||
<stop id="stop6926-5" offset="0.49517274" style="stop-color:#2185d0;stop-opacity:0.30000001;"/>
|
||||
<stop style="stop-color:#2185d0;stop-opacity:0.30000001;" offset="1" id="stop6922-3"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<sodipodi:namedview showborder="false" id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="22.627417" inkscape:cx="12.948893" inkscape:cy="12.661631" inkscape:document-units="px" inkscape:current-layer="svg1468" inkscape:document-rotation="0" showgrid="false" fit-margin-top="0" fit-margin-left="0" fit-margin-right="0" fit-margin-bottom="0" units="px" inkscape:snap-global="false" inkscape:snap-page="true" showguides="false" inkscape:window-width="1531" inkscape:window-height="873" inkscape:window-x="69" inkscape:window-y="27" inkscape:window-maximized="1" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1">
|
||||
<inkscape:grid type="xygrid" id="grid2067"/>
|
||||
</sodipodi:namedview>
|
||||
<metadata id="metadata1465">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title>Codeberg logo</dc:title>
|
||||
<cc:license rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/"/>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Robert Martinez</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>Codeberg and the Codeberg Logo are trademarks of Codeberg e.V.</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<dc:date>2020-04-09</dc:date>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>Codeberg e.V.</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:source>codeberg.org</dc:source>
|
||||
</cc:Work>
|
||||
<cc:License rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
|
||||
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
|
||||
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
|
||||
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g id="g370484" inkscape:label="logo" transform="matrix(0.06551432,0,0,0.06551432,-2.232417,-1.431776)">
|
||||
<path id="path6733-5" style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#linearGradient6918-3);fill-opacity:1;stroke:none;stroke-width:3.67846;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:2;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill;stop-color:#000000;stop-opacity:1" d="m 42519.285,-7078.7891 a 0.76086879,0.56791688 0 0 0 -0.738,0.6739 l 33.586,125.8886 a 87.182358,87.182358 0 0 0 39.381,-33.7636 l -71.565,-92.5196 a 0.76086879,0.56791688 0 0 0 -0.664,-0.2793 z" transform="matrix(0.37058478,0,0,0.37058478,-15690.065,2662.0533)" inkscape:label="berg"/>
|
||||
<path id="path360787" style="opacity:1;fill:#2185d0;fill-opacity:1;stroke-width:17.0055;paint-order:markers fill stroke;stop-color:#000000" d="m 11249.461,-1883.6961 c -12.74,0 -23.067,10.3275 -23.067,23.0671 0,4.3335 1.22,8.5795 3.522,12.2514 l 19.232,-24.8636 c 0.138,-0.1796 0.486,-0.1796 0.624,0 l 19.233,24.8646 c 2.302,-3.6721 3.523,-7.9185 3.523,-12.2524 0,-12.7396 -10.327,-23.0671 -23.067,-23.0671 z" sodipodi:nodetypes="sccccccs" inkscape:label="sky" transform="matrix(1.4006354,0,0,1.4006354,-15690.065,2662.0533)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.1 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 61 81" fill="#fff" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round"><style><![CDATA[.B{stroke:none}.C{fill:#000}.D{fill:#eceff1}.E{fill:url(#A)}.F{stroke-opacity:.34}.G{fill:#ffee58}.H{fill:#d9ff66}.I{fill:#4caf50}]]></style><use xlink:href="#C" x=".5" y=".5"/><defs><linearGradient id="A" x1="0%" y1="50%" x2="100%" y2="50%"><stop offset="0%" stop-color="#90a4ae"/><stop offset="100%" stop-color="#b0bec5"/></linearGradient><path id="B" d="M7.059 67.43c5.142 3.383 12.674 5.604 21.176 5.875"/></defs><symbol id="C" overflow="visible"><ellipse cx="30" cy="50" rx="30" ry="16.667" class="B D"/><g transform="translate(0 50)"><path d="M0 0v13.333C0 22.567 13.38 30 30 30s30-7.433 30-16.667V0c0 9.233-13.38 16.667-30 16.667S0 9.233 0 0z" class="B E"/></g><use xlink:href="#B" fill="none" class="F"/><g class="B"><ellipse cx="37.362" cy="73.34" rx="2.068" ry="1.993" class="G"/><ellipse cx="44.52" cy="71.326" rx="2.068" ry="1.993" class="H"/><ellipse cx="51.579" cy="68.66" rx="2.068" ry="1.993" class="I"/><ellipse cx="30" cy="33.334" rx="30" ry="16.667" class="D"/></g><g transform="translate(0 33.333)"><path d="M0 0v13.333C0 22.567 13.38 30 30 30s30-7.433 30-16.667V0c0 9.233-13.38 16.667-30 16.667S0 9.233 0 0z" class="B E"/></g><use xlink:href="#B" y="-16.667" fill="none" class="F"/><g class="B"><ellipse cx="37.362" cy="56.673" rx="2.068" ry="1.993" class="G"/><ellipse cx="44.52" cy="54.66" rx="2.068" ry="1.993" class="H"/><ellipse cx="51.579" cy="51.993" rx="2.068" ry="1.993" class="I"/><ellipse cx="30" cy="16.667" rx="30" ry="16.667" class="D"/></g><g transform="translate(0 16.667)"><path d="M0 0v13.333C0 22.567 13.38 30 30 30s30-7.433 30-16.667V0c0 9.233-13.38 16.667-30 16.667S0 9.233 0 0z" class="B E"/></g><use xlink:href="#B" y="-33.334" fill="none" class="F"/><g class="B"><ellipse cx="37.362" cy="40.007" rx="2.068" ry="1.993" class="G"/><ellipse cx="44.52" cy="37.993" rx="2.068" ry="1.993" class="H"/><ellipse cx="51.579" cy="35.326" rx="2.068" ry="1.993" class="I"/><ellipse cx="30" cy="16.666" rx="26.471" ry="13.333" fill="#cfd8dc"/></g></symbol></svg>
|
||||
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 475 KiB |
BIN
www/tjenester/img/discord.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="Discord-Logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 126.644 96"><defs><style>.cls-1{fill:#5865f2;}</style></defs><path id="Discord-Symbol-Blurple" class="cls-1" d="M81.15,0c-1.2376,2.1973-2.3489,4.4704-3.3591,6.794-9.5975-1.4396-19.3718-1.4396-28.9945,0-.985-2.3236-2.1216-4.5967-3.3591-6.794-9.0166,1.5407-17.8059,4.2431-26.1405,8.0568C2.779,32.5304-1.6914,56.3725.5312,79.8863c9.6732,7.1476,20.5083,12.603,32.0505,16.0884,2.6014-3.4854,4.8998-7.1981,6.8698-11.0623-3.738-1.3891-7.3497-3.1318-10.8098-5.1523.9092-.6567,1.7932-1.3386,2.6519-1.9953,20.281,9.547,43.7696,9.547,64.0758,0,.8587.7072,1.7427,1.3891,2.6519,1.9953-3.4601,2.0457-7.0718,3.7632-10.835,5.1776,1.97,3.8642,4.2683,7.5769,6.8698,11.0623,11.5419-3.4854,22.3769-8.9156,32.0509-16.0631,2.626-27.2771-4.496-50.9172-18.817-71.8548C98.9811,4.2684,90.1918,1.5659,81.1752.0505l-.0252-.0505ZM42.2802,65.4144c-6.2383,0-11.4159-5.6575-11.4159-12.6535s4.9755-12.6788,11.3907-12.6788,11.5169,5.708,11.4159,12.6788c-.101,6.9708-5.026,12.6535-11.3907,12.6535ZM84.3576,65.4144c-6.2637,0-11.3907-5.6575-11.3907-12.6535s4.9755-12.6788,11.3907-12.6788,11.4917,5.708,11.3906,12.6788c-.101,6.9708-5.026,12.6535-11.3906,12.6535Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 57 KiB |
BIN
www/tjenester/img/element.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
@@ -1,6 +0,0 @@
|
||||
<svg width="54" height="54" viewBox="0 0 54 54" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.4414 3.24C19.4414 1.4506 20.892 0 22.6814 0C34.6108 0 44.2814 9.67065 44.2814 21.6C44.2814 23.3894 42.8308 24.84 41.0414 24.84C39.252 24.84 37.8014 23.3894 37.8014 21.6C37.8014 13.2494 31.032 6.48 22.6814 6.48C20.892 6.48 19.4414 5.0294 19.4414 3.24Z" fill="#0DBD8B"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M34.5586 50.76C34.5586 52.5494 33.108 54 31.3186 54C19.3893 54 9.71861 44.3294 9.71861 32.4C9.71861 30.6106 11.1692 29.16 12.9586 29.16C14.748 29.16 16.1986 30.6106 16.1986 32.4C16.1986 40.7505 22.9681 47.52 31.3186 47.52C33.108 47.52 34.5586 48.9706 34.5586 50.76Z" fill="#0DBD8B"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.24 34.5601C1.4506 34.5601 -6.34076e-08 33.1095 -1.41625e-07 31.3201C-6.63074e-07 19.3907 9.67065 9.72007 21.6 9.72007C23.3894 9.72007 24.84 11.1707 24.84 12.9601C24.84 14.7495 23.3894 16.2001 21.6 16.2001C13.2495 16.2001 6.48 22.9695 6.48 31.3201C6.48 33.1095 5.0294 34.5601 3.24 34.5601Z" fill="#0DBD8B"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M50.76 19.4399C52.5494 19.4399 54 20.8905 54 22.6799C54 34.6093 44.3294 44.2799 32.4 44.2799C30.6106 44.2799 29.16 42.8293 29.16 41.0399C29.16 39.2505 30.6106 37.7999 32.4 37.7999C40.7505 37.7999 47.52 31.0305 47.52 22.6799C47.52 20.8905 48.9706 19.4399 50.76 19.4399Z" fill="#0DBD8B"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
BIN
www/tjenester/img/esxi.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
www/tjenester/img/gitea.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
@@ -1 +0,0 @@
|
||||
<svg version="1.1" id="main_outline" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" style="enable-background:new 0 0 640 640;" xml:space="preserve" viewBox="5.67 143.05 628.65 387.55"> <g> <path id="teabag" style="fill:#FFFFFF" d="M395.9,484.2l-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5,21.2-17.9,33.8-11.8 c17.2,8.3,27.1,13,27.1,13l-0.1-109.2l16.7-0.1l0.1,117.1c0,0,57.4,24.2,83.1,40.1c3.7,2.3,10.2,6.8,12.9,14.4 c2.1,6.1,2,13.1-1,19.3l-61,126.9C423.6,484.9,408.4,490.3,395.9,484.2z"></path> <g> <g> <path style="fill:#609926" d="M622.7,149.8c-4.1-4.1-9.6-4-9.6-4s-117.2,6.6-177.9,8c-13.3,0.3-26.5,0.6-39.6,0.7c0,39.1,0,78.2,0,117.2 c-5.5-2.6-11.1-5.3-16.6-7.9c0-36.4-0.1-109.2-0.1-109.2c-29,0.4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5 c-9.8-0.6-22.5-2.1-39,1.5c-8.7,1.8-33.5,7.4-53.8,26.9C-4.9,212.4,6.6,276.2,8,285.8c1.7,11.7,6.9,44.2,31.7,72.5 c45.8,56.1,144.4,54.8,144.4,54.8s12.1,28.9,30.6,55.5c25,33.1,50.7,58.9,75.7,62c63,0,188.9-0.1,188.9-0.1s12,0.1,28.3-10.3 c14-8.5,26.5-23.4,26.5-23.4s12.9-13.8,30.9-45.3c5.5-9.7,10.1-19.1,14.1-28c0,0,55.2-117.1,55.2-231.1 C633.2,157.9,624.7,151.8,622.7,149.8z M125.6,353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6,321.8,60,295.4 c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5,38.5-30c13.8-3.7,31-3.1,31-3.1s7.1,59.4,15.7,94.2c7.2,29.2,24.8,77.7,24.8,77.7 S142.5,359.9,125.6,353.9z M425.9,461.5c0,0-6.1,14.5-19.6,15.4c-5.8,0.4-10.3-1.2-10.3-1.2s-0.3-0.1-5.3-2.1l-112.9-55 c0,0-10.9-5.7-12.8-15.6c-2.2-8.1,2.7-18.1,2.7-18.1L322,273c0,0,4.8-9.7,12.2-13c0.6-0.3,2.3-1,4.5-1.5c8.1-2.1,18,2.8,18,2.8 l110.7,53.7c0,0,12.6,5.7,15.3,16.2c1.9,7.4-0.5,14-1.8,17.2C474.6,363.8,425.9,461.5,425.9,461.5z"></path> <path style="fill:#609926" d="M326.8,380.1c-8.2,0.1-15.4,5.8-17.3,13.8c-1.9,8,2,16.3,9.1,20c7.7,4,17.5,1.8,22.7-5.4 c5.1-7.1,4.3-16.9-1.8-23.1l24-49.1c1.5,0.1,3.7,0.2,6.2-0.5c4.1-0.9,7.1-3.6,7.1-3.6c4.2,1.8,8.6,3.8,13.2,6.1 c4.8,2.4,9.3,4.9,13.4,7.3c0.9,0.5,1.8,1.1,2.8,1.9c1.6,1.3,3.4,3.1,4.7,5.5c1.9,5.5-1.9,14.9-1.9,14.9 c-2.3,7.6-18.4,40.6-18.4,40.6c-8.1-0.2-15.3,5-17.7,12.5c-2.6,8.1,1.1,17.3,8.9,21.3c7.8,4,17.4,1.7,22.5-5.3 c5-6.8,4.6-16.3-1.1-22.6c1.9-3.7,3.7-7.4,5.6-11.3c5-10.4,13.5-30.4,13.5-30.4c0.9-1.7,5.7-10.3,2.7-21.3 c-2.5-11.4-12.6-16.7-12.6-16.7c-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3c4.7-9.7,9.4-19.3,14.1-29 c-4.1-2-8.1-4-12.2-6.1c-4.8,9.8-9.7,19.7-14.5,29.5c-6.7-0.1-12.9,3.5-16.1,9.4c-3.4,6.3-2.7,14.1,1.9,19.8 C343.2,346.5,335,363.3,326.8,380.1z"></path> </g> </g> </g> </svg>
|
||||
|
Before Width: | Height: | Size: 2.5 KiB |
BIN
www/tjenester/img/github.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
@@ -1 +0,0 @@
|
||||
<svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#24292f"/></svg>
|
||||
|
Before Width: | Height: | Size: 963 B |
|
Before Width: | Height: | Size: 233 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 560 KiB |
@@ -1,49 +0,0 @@
|
||||
<svg id="logo.svg" xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
|
||||
<defs>
|
||||
<linearGradient id="gradient" gradientUnits="userSpaceOnUse" x1="0" x2="100" y1="100" y2="0">
|
||||
<stop offset="0%" stop-color="#0a00b2"/>
|
||||
<stop offset="50%" stop-color="#ff0000"/>
|
||||
<stop offset="100%" stop-color="#fffc00"/>
|
||||
</linearGradient>
|
||||
<style>
|
||||
.petal {
|
||||
opacity: 0.65;
|
||||
}
|
||||
.petals {
|
||||
fill: url(#gradient);
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g id="petals" class="petals">
|
||||
<path class="petal" d="M35.922,12.956a16.3,16.3,0,0,0,2.344,10.436,10.462,10.462,0,0,0,5.924,4.351,2.587,2.587,0,0,0,2.144-.521,11.022,11.022,0,0,0,3.635-9.771c-0.831-7.014-5.024-11.8-10.361-16.357A30.253,30.253,0,0,0,35.922,12.956Z"/>
|
||||
<path class="petal" d="M28.485,16.676A16.327,16.327,0,0,0,32.959,26.4a10.491,10.491,0,0,0,6.7,3.031,2.581,2.581,0,0,0,1.988-.953,11.006,11.006,0,0,0,1.513-10.309c-2.279-6.689-7.38-10.5-13.554-13.857A30.215,30.215,0,0,0,28.485,16.676Z"/>
|
||||
<path class="petal" d="M21.988,21.853A16.374,16.374,0,0,0,28.4,30.439a10.512,10.512,0,0,0,7.191,1.579,2.574,2.574,0,0,0,1.745-1.343,11,11,0,0,0-.675-10.4C33.031,14.206,27.245,11.533,20.5,9.526A30.218,30.218,0,0,0,21.988,21.853Z"/>
|
||||
<path class="petal" d="M16.716,28.26a16.426,16.426,0,0,0,8.063,7.073,10.519,10.519,0,0,0,7.364.057,2.566,2.566,0,0,0,1.426-1.675,11.014,11.014,0,0,0-2.833-10.03C25.919,18.5,19.7,17.079,12.687,16.509A30.261,30.261,0,0,0,16.716,28.26Z"/>
|
||||
<path class="petal" d="M12.9,35.618a16.476,16.476,0,0,0,9.366,5.251A10.512,10.512,0,0,0,29.478,39.4a2.559,2.559,0,0,0,1.045-1.933,11.038,11.038,0,0,0-4.868-9.225c-5.8-4.079-12.176-4.18-19.154-3.286A30.339,30.339,0,0,0,12.9,35.618Z"/>
|
||||
<path class="petal" d="M10.7,43.6a16.515,16.515,0,0,0,10.258,3.2,10.493,10.493,0,0,0,6.751-2.927,2.553,2.553,0,0,0,.618-2.107,11.068,11.068,0,0,0-6.69-8.017c-6.522-2.791-12.783-1.571-19.422.746A30.434,30.434,0,0,0,10.7,43.6Z"/>
|
||||
<path class="petal" d="M10.222,51.871a16.535,16.535,0,0,0,10.7,1.008,10.464,10.464,0,0,0,5.991-4.259,2.55,2.55,0,0,0,.164-2.189,11.1,11.1,0,0,0-8.219-6.458C11.9,38.591,6.028,41.08.019,44.719A30.534,30.534,0,0,0,10.222,51.871Z"/>
|
||||
<path class="petal" d="M11.481,60.056a16.533,16.533,0,0,0,10.68-1.228,10.431,10.431,0,0,0,4.97-5.405,2.551,2.551,0,0,0-.3-2.175,11.133,11.133,0,0,0-9.39-4.617c-7.1.089-12.32,3.737-17.438,8.539A30.618,30.618,0,0,0,11.481,60.056Z"/>
|
||||
<path class="petal" d="M14.423,67.8a16.51,16.51,0,0,0,10.19-3.41,10.4,10.4,0,0,0,3.732-6.315,2.555,2.555,0,0,0-.745-2.066,11.155,11.155,0,0,0-10.15-2.575c-6.926,1.555-11.27,6.2-15.272,11.959A30.673,30.673,0,0,0,14.423,67.8Z"/>
|
||||
<path class="petal" d="M18.92,74.769a16.471,16.471,0,0,0,9.254-5.442,10.374,10.374,0,0,0,2.33-6.948,2.561,2.561,0,0,0-1.161-1.867,11.166,11.166,0,0,0-10.466-.419c-6.45,2.953-9.727,8.4-12.438,14.856A30.693,30.693,0,0,0,18.92,74.769Z"/>
|
||||
<path class="petal" d="M24.775,80.654a16.42,16.42,0,0,0,7.914-7.237,10.36,10.36,0,0,0,.827-7.279,2.569,2.569,0,0,0-1.525-1.586,11.162,11.162,0,0,0-10.325,1.754c-5.691,4.222-7.759,10.226-9.061,17.1A30.668,30.668,0,0,0,24.775,80.654Z"/>
|
||||
<path class="petal" d="M31.733,85.2a16.368,16.368,0,0,0,6.229-8.716,10.36,10.36,0,0,0-.713-7.29,2.576,2.576,0,0,0-1.824-1.236,11.144,11.144,0,0,0-9.733,3.851c-4.684,5.307-5.452,11.607-5.288,18.6A30.607,30.607,0,0,0,31.733,85.2Z"/>
|
||||
<path class="petal" d="M39.488,88.208a16.323,16.323,0,0,0,4.271-9.814,10.373,10.373,0,0,0-2.221-6.984,2.583,2.583,0,0,0-2.042-.832,11.116,11.116,0,0,0-8.715,5.78C27.309,82.519,27.874,88.84,29.5,95.65A30.518,30.518,0,0,0,39.488,88.208Z"/>
|
||||
<path class="petal" d="M47.7,89.546a16.293,16.293,0,0,0,2.126-10.482A10.4,10.4,0,0,0,46.2,72.692a2.588,2.588,0,0,0-2.171-.391,11.082,11.082,0,0,0-7.316,7.456c-2.109,6.743-.234,12.81,2.776,19.135A30.421,30.421,0,0,0,47.7,89.546Z"/>
|
||||
<path class="petal" d="M56.018,89.156a16.283,16.283,0,0,0-.111-10.693,10.429,10.429,0,0,0-4.885-5.481,2.589,2.589,0,0,0-2.206.067,11.049,11.049,0,0,0-5.6,8.806C42.565,88.887,45.667,94.432,49.934,100A30.324,30.324,0,0,0,56.018,89.156Z"/>
|
||||
<path class="petal" d="M64.07,87.055a16.3,16.3,0,0,0-2.344-10.436A10.462,10.462,0,0,0,55.8,72.268a2.587,2.587,0,0,0-2.144.521,11.022,11.022,0,0,0-3.635,9.771c0.831,7.014,5.024,11.8,10.361,16.357A30.254,30.254,0,0,0,64.07,87.055Z"/>
|
||||
<path class="petal" d="M71.507,83.335a16.327,16.327,0,0,0-4.474-9.723,10.491,10.491,0,0,0-6.7-3.031,2.581,2.581,0,0,0-1.988.953,11.006,11.006,0,0,0-1.513,10.309c2.279,6.689,7.38,10.5,13.554,13.857A30.215,30.215,0,0,0,71.507,83.335Z"/>
|
||||
<path class="petal" d="M78,78.158a16.374,16.374,0,0,0-6.409-8.586A10.512,10.512,0,0,0,64.4,67.994a2.574,2.574,0,0,0-1.745,1.343,11,11,0,0,0,.675,10.4c3.627,6.071,9.414,8.745,16.154,10.752A30.218,30.218,0,0,0,78,78.158Z"/>
|
||||
<path class="petal" d="M83.276,71.751a16.426,16.426,0,0,0-8.064-7.073,10.519,10.519,0,0,0-7.364-.057A2.566,2.566,0,0,0,66.423,66.3a11.014,11.014,0,0,0,2.833,10.03C74.073,81.515,80.292,82.933,87.3,83.5A30.263,30.263,0,0,0,83.276,71.751Z"/>
|
||||
<path class="petal" d="M87.094,64.393a16.476,16.476,0,0,0-9.366-5.251,10.512,10.512,0,0,0-7.215,1.467,2.559,2.559,0,0,0-1.045,1.933,11.037,11.037,0,0,0,4.868,9.225c5.8,4.079,12.176,4.18,19.154,3.287A30.338,30.338,0,0,0,87.094,64.393Z"/>
|
||||
<path class="petal" d="M89.291,56.407a16.515,16.515,0,0,0-10.258-3.2,10.493,10.493,0,0,0-6.751,2.927,2.553,2.553,0,0,0-.618,2.107,11.068,11.068,0,0,0,6.69,8.017c6.522,2.791,12.783,1.571,19.422-.746A30.435,30.435,0,0,0,89.291,56.407Z"/>
|
||||
<path class="petal" d="M89.77,48.14a16.534,16.534,0,0,0-10.7-1.008,10.465,10.465,0,0,0-5.991,4.259,2.551,2.551,0,0,0-.164,2.189,11.1,11.1,0,0,0,8.219,6.458c6.963,1.382,12.832-1.107,18.842-4.747A30.533,30.533,0,0,0,89.77,48.14Z"/>
|
||||
<path class="petal" d="M88.511,39.956a16.533,16.533,0,0,0-10.68,1.228,10.431,10.431,0,0,0-4.97,5.405,2.551,2.551,0,0,0,.3,2.175,11.133,11.133,0,0,0,9.39,4.617c7.1-.089,12.32-3.737,17.438-8.539A30.618,30.618,0,0,0,88.511,39.956Z"/>
|
||||
<path class="petal" d="M85.569,32.21a16.51,16.51,0,0,0-10.19,3.41,10.4,10.4,0,0,0-3.732,6.315A2.555,2.555,0,0,0,72.393,44a11.155,11.155,0,0,0,10.15,2.574c6.926-1.555,11.27-6.2,15.272-11.959A30.673,30.673,0,0,0,85.569,32.21Z"/>
|
||||
<path class="petal" d="M81.072,25.242a16.471,16.471,0,0,0-9.254,5.442,10.374,10.374,0,0,0-2.33,6.948A2.561,2.561,0,0,0,70.648,39.5a11.166,11.166,0,0,0,10.466.419c6.45-2.953,9.727-8.4,12.438-14.856A30.7,30.7,0,0,0,81.072,25.242Z"/>
|
||||
<path class="petal" d="M75.217,19.357A16.42,16.42,0,0,0,67.3,26.594a10.36,10.36,0,0,0-.827,7.279A2.568,2.568,0,0,0,68,35.459,11.162,11.162,0,0,0,78.326,33.7c5.691-4.223,7.759-10.226,9.061-17.1A30.668,30.668,0,0,0,75.217,19.357Z"/>
|
||||
<path class="petal" d="M68.259,14.811a16.368,16.368,0,0,0-6.229,8.716,10.36,10.36,0,0,0,.713,7.29,2.576,2.576,0,0,0,1.824,1.236A11.144,11.144,0,0,0,74.3,28.2c4.684-5.307,5.452-11.607,5.288-18.6A30.608,30.608,0,0,0,68.259,14.811Z"/>
|
||||
<path class="petal" d="M60.5,11.8a16.324,16.324,0,0,0-4.271,9.814A10.374,10.374,0,0,0,58.454,28.6a2.583,2.583,0,0,0,2.042.832,11.115,11.115,0,0,0,8.715-5.78c3.473-6.16,2.907-12.481,1.284-19.291A30.519,30.519,0,0,0,60.5,11.8Z"/>
|
||||
<path class="petal" d="M52.288,10.465a16.294,16.294,0,0,0-2.126,10.482,10.4,10.4,0,0,0,3.632,6.372,2.588,2.588,0,0,0,2.171.391,11.082,11.082,0,0,0,7.316-7.456c2.109-6.744.234-12.809-2.776-19.135A30.42,30.42,0,0,0,52.288,10.465Z"/>
|
||||
<path class="petal" d="M43.973,10.855a16.283,16.283,0,0,0,.111,10.693,10.429,10.429,0,0,0,4.885,5.482,2.589,2.589,0,0,0,2.206-.066,11.049,11.049,0,0,0,5.6-8.806C57.427,11.125,54.325,5.579,50.058.014A30.324,30.324,0,0,0,43.973,10.855Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 7.4 KiB |
BIN
www/tjenester/img/proxmox.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="9.14 141.8 573.65 573.65">
|
||||
<style type="text/css">
|
||||
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#404F54;}
|
||||
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#E5E5E5;}
|
||||
.st2{fill-rule:evenodd;clip-rule:evenodd;fill:#CCCCCC;}
|
||||
.st3{fill-rule:evenodd;clip-rule:evenodd;fill:#37BEFF;}
|
||||
</style>
|
||||
<polygon class="st3" points="582.79,549.77 295.96,384.1 295.96,207.27 582.79,372.95 "/>
|
||||
<polygon class="st0" points="9.14,549.77 295.96,384.1 295.96,207.27 9.14,372.95 "/>
|
||||
<path class="st2" d="M295.96,141.8c109.56,0,198.41,88.85,198.41,198.41c0,109.56-88.85,198.41-198.41,198.41 c-109.56,0-198.41-88.85-198.41-198.41C97.55,230.65,186.4,141.8,295.96,141.8"/>
|
||||
<path class="st1" d="M295.96,141.8c109.6,0,198.48,88.85,198.48,198.41c0,109.56-88.88,198.41-198.48,198.41 c-62.91-42.34-88.94-127.64-88.94-198.3S233.05,184.22,295.96,141.8"/>
|
||||
<polygon class="st3" points="582.79,372.95 295.96,538.62 295.96,715.45 582.79,549.77 "/>
|
||||
<polygon class="st0" points="9.14,372.95 295.96,538.62 295.96,715.45 9.14,549.77 "/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
BIN
www/tjenester/img/rss.png
Normal file
|
After Width: | Height: | Size: 117 KiB |
@@ -1,5 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
aria-label="RSS" role="img"
|
||||
viewBox="0 0 512 512"><path
|
||||
d="m0 0H512V512H0"
|
||||
fill="#f80"/><path fill="#fff" d="m109 271A132 133 0 01241 403h60A192 193 0 00109 211v-54A246 247 0 01355 403h60A306 307 0 00109 97m35 235a35 35 0 102 0"/></svg>
|
||||
|
Before Width: | Height: | Size: 276 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.0" viewBox="64 94 384.4 308"><style>path,rect{fill:#000}@media (prefers-color-scheme:dark){path,rect{fill:#000}rect{transform:scale(1,-1)}}</style><g transform="matrix(.1 0 0 -.1 0 512)"><path d="M933 3908c-150-150-276-281-279-291-5-16 51-77 272-298l279-279h177c98 0 178 3 178 7s-89 97-197 206c-157 157-195 200-183 207 9 6 257 10 613 10h597v134c0 113-2 135-16 140-9 3-283 6-610 6s-594 3-594 8c0 4 90 97 199 206 110 110 198 203 195 208-3 4-84 8-181 8h-176zm2627 265c0-4 88-96 196-204 115-115 194-201 190-208-5-8-178-11-611-11-540 0-603-2-609-16-3-9-6-67-6-129 0-103 2-115 19-125 13-6 224-10 615-10 328 0 596-3 596-8 0-4-90-97-200-207s-200-203-200-207c0-5 82-8 182-8h182l285 286 285 285-285 285-284 284h-177c-98 0-178-3-178-7"/><path d="M640 2317V1154l28-27 28-27h3730l27 28 27 28v1156c0 636-4 1159-8 1162-5 3-41-27-80-67l-72-72-2-1030-3-1030H805l-3 1030-2 1030-72 72c-40 40-76 73-80 73-5 0-8-523-8-1163"/><path d="M1290 2972c0-4 84-92 188-195l187-187h1790l188 188c103 103 187 191 187 195s-75 7-168 7h-168l-69-70-69-70H1764l-69 70-69 70h-168c-93 0-168-3-168-8"/><rect width="105.704" height="113.393" x="965.825" y="-1995.056" ry="0"/><rect width="105.704" height="113.393" x="968.171" y="-1775.339" ry="0"/><rect width="105.704" height="113.393" x="1544.743" y="-1770.834" ry="0"/><rect width="105.704" height="113.393" x="1201.284" y="-2214.654" ry="0"/><rect width="105.704" height="113.393" x="1529.886" y="-2211.156" ry="0"/><rect width="105.704" height="113.393" x="1766.14" y="-2213.186" ry="0"/><rect width="105.704" height="113.393" x="1767.395" y="-1976.642" ry="0"/><rect width="105.704" height="113.393" x="2112.529" y="-2219.311" ry="0"/><rect width="105.704" height="113.393" x="2677.813" y="-2214.965" ry="0"/><rect width="105.704" height="113.393" x="2672.628" y="-1988.655" ry="0"/><rect width="105.704" height="113.393" x="2673.453" y="-1762.207" ry="0"/><rect width="105.704" height="113.393" x="2898.873" y="-2216.276" ry="0"/><rect width="105.704" height="113.393" x="3249.094" y="-2212.257" ry="0"/><rect width="105.704" height="113.393" x="3251.061" y="-1984.478" ry="0"/><rect width="105.704" height="113.393" x="3251.56" y="-1774.923" ry="0"/><rect width="105.704" height="113.393" x="3470.185" y="-2214.272" ry="0"/><rect width="105.704" height="113.393" x="3829.944" y="-2215.038" ry="0"/><rect width="105.704" height="113.393" x="4044.099" y="-2214.53" ry="0"/><rect width="105.704" height="113.393" x="4041.513" y="-1999.062" ry="0"/><rect width="105.704" height="113.393" x="4043.404" y="-1785.199" ry="0"/><rect width="105.704" height="113.393" x="3830.52" y="-1781.447" ry="0"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 50 KiB |
BIN
www/tjenester/img/trac.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
@@ -1,74 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg version="1.1" viewBox="0 0 256 256" id="svg383" sodipodi:docname="vaultwarden-icon.svg" inkscape:version="1.2.1 (9c6d41e410, 2022-07-14, custom)" width="256" height="256" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs id="defs387" />
|
||||
<sodipodi:namedview id="namedview385" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:showpageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1" showgrid="false" inkscape:zoom="3.3359375" inkscape:cx="128" inkscape:cy="128" inkscape:window-width="1874" inkscape:window-height="1056" inkscape:window-x="46" inkscape:window-y="24" inkscape:window-maximized="1" inkscape:current-layer="svg383" />
|
||||
<title id="title287">Vaultwarden Icon</title>
|
||||
<g id="logo" transform="matrix(2.4381018,0,0,2.4381018,128,128)">
|
||||
<g id="gear" mask="url(#holes)">
|
||||
<path d="m-31.1718-33.813208 26.496029 74.188883h9.3515399l26.49603-74.188883h-9.767164l-16.728866 47.588948q-1.662496 4.571864-2.805462 8.624198-1.142966 3.948427-1.870308 7.585137-.72734199-3.63671-1.8703079-7.689043-1.142966-4.052334-2.805462-8.728104l-16.624959-47.381136z" stroke="#000" stroke-width="4.51171" id="path289" />
|
||||
<circle transform="scale(-1,1)" r="43" fill="none" stroke="#000" stroke-width="9" id="circle291" />
|
||||
<g id="cogs" transform="scale(-1,1)">
|
||||
<polygon id="cog" points="51 0 46 -3 46 3" stroke="#000" stroke-linejoin="round" stroke-width="3" />
|
||||
<use transform="rotate(11.25)" xlink:href="#cog" id="use294" />
|
||||
<use transform="rotate(22.5)" xlink:href="#cog" id="use296" />
|
||||
<use transform="rotate(33.75)" xlink:href="#cog" id="use298" />
|
||||
<use transform="rotate(45)" xlink:href="#cog" id="use300" />
|
||||
<use transform="rotate(56.25)" xlink:href="#cog" id="use302" />
|
||||
<use transform="rotate(67.5)" xlink:href="#cog" id="use304" />
|
||||
<use transform="rotate(78.75)" xlink:href="#cog" id="use306" />
|
||||
<use transform="rotate(90)" xlink:href="#cog" id="use308" />
|
||||
<use transform="rotate(101.25)" xlink:href="#cog" id="use310" />
|
||||
<use transform="rotate(112.5)" xlink:href="#cog" id="use312" />
|
||||
<use transform="rotate(123.75)" xlink:href="#cog" id="use314" />
|
||||
<use transform="rotate(135)" xlink:href="#cog" id="use316" />
|
||||
<use transform="rotate(146.25)" xlink:href="#cog" id="use318" />
|
||||
<use transform="rotate(157.5)" xlink:href="#cog" id="use320" />
|
||||
<use transform="rotate(168.75)" xlink:href="#cog" id="use322" />
|
||||
<use transform="scale(-1)" xlink:href="#cog" id="use324" />
|
||||
<use transform="rotate(191.25)" xlink:href="#cog" id="use326" />
|
||||
<use transform="rotate(202.5)" xlink:href="#cog" id="use328" />
|
||||
<use transform="rotate(213.75)" xlink:href="#cog" id="use330" />
|
||||
<use transform="rotate(225)" xlink:href="#cog" id="use332" />
|
||||
<use transform="rotate(236.25)" xlink:href="#cog" id="use334" />
|
||||
<use transform="rotate(247.5)" xlink:href="#cog" id="use336" />
|
||||
<use transform="rotate(258.75)" xlink:href="#cog" id="use338" />
|
||||
<use transform="rotate(-90)" xlink:href="#cog" id="use340" />
|
||||
<use transform="rotate(-78.75)" xlink:href="#cog" id="use342" />
|
||||
<use transform="rotate(-67.5)" xlink:href="#cog" id="use344" />
|
||||
<use transform="rotate(-56.25)" xlink:href="#cog" id="use346" />
|
||||
<use transform="rotate(-45)" xlink:href="#cog" id="use348" />
|
||||
<use transform="rotate(-33.75)" xlink:href="#cog" id="use350" />
|
||||
<use transform="rotate(-22.5)" xlink:href="#cog" id="use352" />
|
||||
<use transform="rotate(-11.25)" xlink:href="#cog" id="use354" />
|
||||
</g>
|
||||
<g id="mounts" transform="scale(-1,1)">
|
||||
<polygon id="mount" points="0 -35 7 -42 -7 -42" stroke="#000" stroke-linejoin="round" stroke-width="6" />
|
||||
<use transform="rotate(72)" xlink:href="#mount" id="use358" />
|
||||
<use transform="rotate(144)" xlink:href="#mount" id="use360" />
|
||||
<use transform="rotate(216)" xlink:href="#mount" id="use362" />
|
||||
<use transform="rotate(-72)" xlink:href="#mount" id="use364" />
|
||||
</g>
|
||||
</g>
|
||||
<mask id="holes">
|
||||
<rect x="-60" y="-60" width="120" height="120" fill="#fff" id="rect368" />
|
||||
<circle id="hole" cy="-40" r="3" />
|
||||
<use transform="rotate(72)" xlink:href="#hole" id="use371" />
|
||||
<use transform="rotate(144)" xlink:href="#hole" id="use373" />
|
||||
<use transform="rotate(216)" xlink:href="#hole" id="use375" />
|
||||
<use transform="rotate(-72)" xlink:href="#hole" id="use377" />
|
||||
</mask>
|
||||
</g>
|
||||
<metadata id="metadata381">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:title>Vaultwarden Icon</dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Mathijs van Veluw</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:relation>Rust Logo</dc:relation>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 105 KiB |
@@ -3,422 +3,201 @@
|
||||
namespace pvv\side;
|
||||
|
||||
require_once \dirname(__DIR__, 2) . implode(\DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']);
|
||||
|
||||
$colorPalette = [
|
||||
'#FFB3BA',
|
||||
'#FFCFAA',
|
||||
'#FFFFBA',
|
||||
'#BAFFC9',
|
||||
'#BAE1FF',
|
||||
'#E2BAFF',
|
||||
];
|
||||
|
||||
function rgbToHsl(int $r, int $g, int $b): array
|
||||
{
|
||||
// Assert valid RGB range
|
||||
if ($r < 0 || $r > 255 || $g < 0 || $g > 255 || $b < 0 || $b > 255) {
|
||||
throw new \InvalidArgumentException('RGB values must be between 0 and 255');
|
||||
}
|
||||
|
||||
$r /= 255;
|
||||
$g /= 255;
|
||||
$b /= 255;
|
||||
|
||||
$max = max($r, $g, $b);
|
||||
$min = min($r, $g, $b);
|
||||
$delta = $max - $min;
|
||||
|
||||
$l = ($max + $min) / 2;
|
||||
|
||||
if ($delta == 0) {
|
||||
$h = 0;
|
||||
$s = 0;
|
||||
} else {
|
||||
$s = $delta / (1 - abs(2 * $l - 1));
|
||||
|
||||
if ($max === $r) {
|
||||
$h = 60 * (($g - $b) / $delta);
|
||||
if ($h < 0) {
|
||||
$h += 360;
|
||||
}
|
||||
} elseif ($max === $g) {
|
||||
$h = 60 * ((($b - $r) / $delta) + 2);
|
||||
} else {
|
||||
$h = 60 * ((($r - $g) / $delta) + 4);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'h' => round($h, 2),
|
||||
's' => round($s * 100, 2),
|
||||
'l' => round($l * 100, 2),
|
||||
];
|
||||
}
|
||||
|
||||
function hslToRgb(float $h, float $s, float $l): array
|
||||
{
|
||||
// Assert valid HSL ranges
|
||||
if ($h < 0 || $h > 360) {
|
||||
throw new \InvalidArgumentException('Hue must be between 0 and 360');
|
||||
}
|
||||
if ($s < 0 || $s > 100 || $l < 0 || $l > 100) {
|
||||
throw new \InvalidArgumentException('Saturation and Lightness must be between 0 and 100');
|
||||
}
|
||||
|
||||
$s /= 100;
|
||||
$l /= 100;
|
||||
|
||||
$c = (1 - abs(2 * $l - 1)) * $s;
|
||||
$m = $l - $c / 2;
|
||||
|
||||
// Determine hue sector explicitly
|
||||
if ($h < 60) {
|
||||
$r1 = $c;
|
||||
$g1 = ($h / 60) * $c;
|
||||
$b1 = 0;
|
||||
} elseif ($h < 120) {
|
||||
$r1 = (2 - $h / 60) * $c;
|
||||
$g1 = $c;
|
||||
$b1 = 0;
|
||||
} elseif ($h < 180) {
|
||||
$r1 = 0;
|
||||
$g1 = $c;
|
||||
$b1 = (($h - 120) / 60) * $c;
|
||||
} elseif ($h < 240) {
|
||||
$r1 = 0;
|
||||
$g1 = (4 - $h / 60) * $c;
|
||||
$b1 = $c;
|
||||
} elseif ($h < 300) {
|
||||
$r1 = (($h - 240) / 60) * $c;
|
||||
$g1 = 0;
|
||||
$b1 = $c;
|
||||
} else { // h < 360
|
||||
$r1 = $c;
|
||||
$g1 = 0;
|
||||
$b1 = (6 - $h / 60) * $c;
|
||||
}
|
||||
|
||||
return [
|
||||
'r' => (int) round(($r1 + $m) * 255),
|
||||
'g' => (int) round(($g1 + $m) * 255),
|
||||
'b' => (int) round(($b1 + $m) * 255),
|
||||
];
|
||||
}
|
||||
|
||||
function generateHighlightColor(string $hexColor): string {
|
||||
$r = hexdec(substr($hexColor, 1, 2));
|
||||
$g = hexdec(substr($hexColor, 3, 2));
|
||||
$b = hexdec(substr($hexColor, 5, 2));
|
||||
$a = hexdec(substr($hexColor, 7, 2));
|
||||
if (!$a) {
|
||||
$a = 255;
|
||||
}
|
||||
|
||||
$hsl = rgbToHsl($r, $g, $b);
|
||||
|
||||
// Increase lightness by 8%, cap at 100%
|
||||
$hsl['l'] = min(100, $hsl['l'] + 8);
|
||||
|
||||
$rgb = hslToRgb($hsl['h'], $hsl['s'], $hsl['l']);
|
||||
|
||||
return sprintf(
|
||||
"#%02x%02x%02x%02x",
|
||||
$rgb['r'],
|
||||
$rgb['g'],
|
||||
$rgb['b'],
|
||||
$a,
|
||||
);
|
||||
}
|
||||
|
||||
$services = [
|
||||
"vcs" => [
|
||||
"title" => "Versjonskontroll og utvikling",
|
||||
"services" => [
|
||||
[
|
||||
"name" => "Gitea",
|
||||
"description" => "Vår interne git-tjener, åpen for alle medlemmer. Kommer med CI/CD, nettside-artifakter, pakke-register og mye mer.",
|
||||
"link" => "https://git.pvv.ntnu.no",
|
||||
"link_text" => "Gå til git.pvv.ntnu.no",
|
||||
"image" => "img/gitea.svg",
|
||||
],
|
||||
[
|
||||
"name" => "GitHub",
|
||||
"description" => "Speiling av våre mest interessante prosjekter på GitHub",
|
||||
"link" => "https://github.com/Programvareverkstedet/",
|
||||
"link_text" => "Gå til GitHub",
|
||||
"image" => "img/github.svg",
|
||||
],
|
||||
[
|
||||
"name" => "Codeberg",
|
||||
"description" => "Speiling av våre mest interessante prosjekter på Codeberg",
|
||||
"link" => "https://codeberg.org/Programvareverkstedet/",
|
||||
"link_text" => "Gå til Codeberg",
|
||||
"image" => "img/codeberg.svg",
|
||||
]
|
||||
]
|
||||
],
|
||||
"webmail" => [
|
||||
"title" => "Epostklienter",
|
||||
"services" => [
|
||||
[
|
||||
"name" => "Roundcube",
|
||||
"description" => "En av våre webmail-klienter for epost.",
|
||||
"link" => "https://webmail.pvv.ntnu.no/",
|
||||
"link_text" => "Gå til Roundcube",
|
||||
"image" => "img/roundcube.svg",
|
||||
],
|
||||
[
|
||||
"name" => "Snappymail",
|
||||
"description" => "En annen av våre webmail-klienter for epost.",
|
||||
"link" => "https://snappymail.pvv.ntnu.no/",
|
||||
"link_text" => "Gå til Snappymail",
|
||||
"image" => "img/snappymail.svg",
|
||||
],
|
||||
[
|
||||
"name" => "Alps",
|
||||
"description" => "Jaggu enda en webmail-klient for epost.",
|
||||
"link" => "https://alps.pvv.ntnu.no/",
|
||||
"link_text" => "Gå til Alps",
|
||||
"image" => "img/alps.svg",
|
||||
],
|
||||
],
|
||||
],
|
||||
"communication" => [
|
||||
"title" => "Kommunikasjon",
|
||||
"services" => [
|
||||
[
|
||||
"name" => "Matrix via Element",
|
||||
"description" => implode(
|
||||
" ",
|
||||
[
|
||||
"Åpen kommunikasjonsprotokoll som støtter ende-til-ende-kryptering og utallige kule funksjoner.",
|
||||
"Vårt space er bridget sammen med Discord, så du får alle de samme meldingene.",
|
||||
"#pvv:pvv.ntnu.no",
|
||||
],
|
||||
),
|
||||
"link" => "https://chat.pvv.ntnu.no",
|
||||
"link_text" => "Gå til chat.pvv.ntnu.no",
|
||||
"image" => "img/element.svg",
|
||||
],
|
||||
[
|
||||
"name" => "Discord",
|
||||
"description" => "Vår hovedkanal, her finner du alt fra ofisielle announcements til memes og driftsdiskusjoner.",
|
||||
"link" => "https://discord.gg/WpaHGV8K",
|
||||
"link_text" => "Gå til Discord",
|
||||
"image" => "img/discord.svg",
|
||||
],
|
||||
[
|
||||
"name" => "Epost",
|
||||
"description" => "Som PVV-medlem får du din egen @pvv.ntnu.no-adresse, som kan brukes med alle vanlige epostprotokoller.",
|
||||
"link" => "https://webmail.pvv.ntnu.no/",
|
||||
"link_text" => "Gå til Rouncubcube webmail",
|
||||
"image" => "img/email.png",
|
||||
],
|
||||
[
|
||||
"name" => "IRC",
|
||||
"description" => "Hvis Discord er for proprietært og Matrix er for hypermoderne er kanskje IRC for deg. Vi har en kanal på IRCNet, #pvv.",
|
||||
"link" => "irc://irc.pvv.ntnu.no/pvv",
|
||||
"link_text" => "Koble til med IRC",
|
||||
"image" => "img/irc.png",
|
||||
],
|
||||
],
|
||||
],
|
||||
"hosting" => [
|
||||
"title" => "Verting og nettsider",
|
||||
"services" => [
|
||||
[
|
||||
"name" => "Brukernettsider",
|
||||
"description" => "Alle brukere får automatisk en egen side for html og php. Denne er offentlig på pvv.ntnu.no/~brukernavn.",
|
||||
"link" => "https://wiki.pvv.ntnu.no/wiki/Tjenester/Hjemmesider",
|
||||
"link_text" => "Gå til dokumentasjon på wiki",
|
||||
"image" => "img/php.png",
|
||||
],
|
||||
[
|
||||
"name" => "Gopherhull",
|
||||
"description" => "PVV driver en egen gopher-tjener for nostalgikere og retroentusiaster.",
|
||||
"link" => "https://wiki.pvv.ntnu.no/wiki/Tjenester/Gopherhull",
|
||||
"link_text" => "Se dokumentasjon for gophertjening",
|
||||
"image" => "img/gopher.png",
|
||||
],
|
||||
[
|
||||
"name" => "Brukerdatabaser",
|
||||
"description" => "PVV har en MariaDB server som er tilgjengelig for bruk av alle medlemmer, gjennom et spesielt administatorverktøy.",
|
||||
"link" => "https://git.pvv.ntnu.no/Projects/muscl",
|
||||
"link_text" => "Se prosjektsiden til administatorverktøyet",
|
||||
"image" => "img/database.svg",
|
||||
],
|
||||
[
|
||||
"name" => "Wiki",
|
||||
"description" => "PVVs wiki er åpen for alle medlemmer, og kan brukes til dokumentasjon, notater, prosjektsider og mye mer.",
|
||||
"link" => "https://wiki.pvv.ntnu.no",
|
||||
"link_text" => "Gå til wiki.pvv.ntnu.no",
|
||||
"image" => "img/mediawiki.svg",
|
||||
],
|
||||
[
|
||||
"name" => "PVV-siden",
|
||||
"description" => "Du befinner deg nå på PVV sin offisielle hjemmeside. Den er skrevet i PHP og kjører på en egen server.",
|
||||
"link" => "https://git.pvv.ntnu.no/Projects/nettsiden",
|
||||
"link_text" => "Se koden på gitea",
|
||||
"image" => "../pvv-logo.png",
|
||||
],
|
||||
],
|
||||
],
|
||||
"physical" => [
|
||||
"title" => "Fysiske tjenester",
|
||||
"services" => [
|
||||
[
|
||||
"name" => "Dibbler",
|
||||
"description" => "PVV har en liten kiosk-datamaskin som lar deg kjøpe godis og pølser, drevet av PVVVV-samlespleisegruppa.",
|
||||
"link" => "https://wiki.pvv.ntnu.no/wiki/Tjenester/Dibbler",
|
||||
"link_text" => "Se dokumentasjon på wiki",
|
||||
"image" => "img/dibbler.png",
|
||||
],
|
||||
// [
|
||||
// "name" => "Worblehat",
|
||||
// "description" => "Bibliotekssystemet vårt, som lar deg finne og låne bøker i PVVs bibliotek.",
|
||||
// "link" => "https://wiki.pvv.ntnu.no/wiki/Tjenester/Worblehat",
|
||||
// "link_text" => "Se dokumentasjon på wiki",
|
||||
// "image" => "img/worblehat.png",
|
||||
// ],
|
||||
[
|
||||
"name" => "Grzegorz",
|
||||
"description" => "Grzegorz er en musikkspiller, den spiller mye dank. Du kan styre den med vevgrensesnitt og diverse API-er.",
|
||||
"link" => "https://georg.pvv.ntnu.no",
|
||||
"link_text" => "Gå til Georg's vevgrensesnitt",
|
||||
"image" => "img/grzegorz.png",
|
||||
],
|
||||
[
|
||||
"name" => "Dørbjelle",
|
||||
"description" => "PVVs dørbjelle er koblet til internett, og lar deg ringe på hvis du spør botten pent på Discordh eller Matrix",
|
||||
"link" => "https://wiki.pvv.ntnu.no/wiki/Tjenester/D%C3%B8rbjelle",
|
||||
"link_text" => "Se dokumentasjon på wiki",
|
||||
"image" => "img/doorbell.png",
|
||||
],
|
||||
[
|
||||
"name" => "Terminaler",
|
||||
"description" => "PVV har flere terminaler plassert på terminalrommet; her kan du logge inn med PVV-brukeren din og gjøre øvinger eller lære om Linux.",
|
||||
"link" => "https://wiki.pvv.ntnu.no/wiki/Tjenester/Terminaler",
|
||||
"link_text" => "Se dokumentasjon på wiki",
|
||||
"image" => "img/terminal.png",
|
||||
],
|
||||
],
|
||||
],
|
||||
"other" => [
|
||||
"title" => "Annet",
|
||||
"services" => [
|
||||
[
|
||||
"name" => "Minecraft",
|
||||
"description" => "Vi har en egen Minecraft-server for medlemmer, som du kan koble til med IP-adressen minecraft.pvv.ntnu.no. Spør om whitelist på matrix/discord.",
|
||||
"link" => "https://minecraft.pvv.ntnu.no",
|
||||
"link_text" => "Gå til verdenskartet vårt",
|
||||
"image" => "img/minecraft.png",
|
||||
],
|
||||
[
|
||||
"name" => "Mapcrafter",
|
||||
"description" => "Det finnes enda et verdenskart for minecraft, mapcrafter. Her kan du se verdenskartet fra en mer isometrisk vinkel.",
|
||||
"link" => "http://isvegg.pvv.ntnu.no/kart",
|
||||
"link_text" => "Gå til det andre verdenskartet vårt",
|
||||
"image" => "img/mapcrafter.webp",
|
||||
],
|
||||
// [
|
||||
// "name" => "MiniFlux RSS reader",
|
||||
// "description" => "Trenger du en cross-platform RSS/Atom-leser for å følge med på omverdenen som det er 1990? ",
|
||||
// "link" => "https://feeds.pvv.ntnu.no",
|
||||
// "link_text" => "Gå til MiniFlux",
|
||||
// "image" => "img/rss.svg",
|
||||
// ],
|
||||
[
|
||||
"name" => "Bildegalleri",
|
||||
"description" => "PVV har et felles bildegalleri, der alle kan legge relevante bilder, som automatisk blir inkludert på nettsiden.",
|
||||
"link" => "https://www.pvv.ntnu.no/galleri/",
|
||||
"link_text" => "Se galleriet",
|
||||
"image" => "img/gallery.png",
|
||||
],
|
||||
[
|
||||
"name" => "Vaultwarden",
|
||||
"description" => implode(
|
||||
" ",
|
||||
[
|
||||
"PVV har en passordlagringstjeneste, hvor medlemmer kan lagre passordene sine, og drift kan dele passord mellom seg.",
|
||||
"Passordene blir kryptert og dekryptert på klientsiden, så det er ikke mulig for drift å snoke rundt i passordene dine."
|
||||
],
|
||||
),
|
||||
"link" => "https://pw.pvv.ntnu.no/",
|
||||
"link_text" => "Gå til vevgrensesnittet",
|
||||
"image" => "img/vaultwarden.svg",
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$servicesArrayKeys = array_keys($services);
|
||||
for ($i = 0; $i < count($services); $i++) {
|
||||
$servicesKey = $servicesArrayKeys[$i];
|
||||
$services[$servicesKey]['bgcolor'] = $colorPalette[$i % count($colorPalette)];
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="no">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<link rel="stylesheet" href="/css/normalize.css">
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<link rel="stylesheet" href="/css/services.css">
|
||||
<meta name="theme-color" content="#024" />
|
||||
<title>Tjenesteverkstedet</title>
|
||||
<style>
|
||||
<?php foreach ($services as $categoryId => $category):
|
||||
$categoryClass = '.category-' . htmlspecialchars($categoryId);
|
||||
?>
|
||||
<?php echo $categoryClass; ?> {
|
||||
background: linear-gradient(135deg, <?php echo generateHighlightColor($category['bgcolor']) ?>, <?php echo $category['bgcolor']; ?>);
|
||||
}
|
||||
<?php endforeach; ?>
|
||||
</style>
|
||||
</head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<link rel="stylesheet" href="/css/normalize.css">
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<link rel="stylesheet" href="/css/services.css">
|
||||
<meta name="theme-color" content="#024" />
|
||||
<title>Tjenesteverkstedet</title>
|
||||
|
||||
<header>Tjenesteverkstedet</header>
|
||||
|
||||
<body>
|
||||
<nav>
|
||||
<?php echo navbar(1, 'tjenester'); ?>
|
||||
<?php echo loginbar($sp, $pdo); ?>
|
||||
</nav>
|
||||
<main>
|
||||
<div class="serviceGrid">
|
||||
<?php foreach ($services as $categoryId => $category):
|
||||
$categoryClass = 'category-' . htmlspecialchars($categoryId);
|
||||
?>
|
||||
<nav>
|
||||
<?php echo navbar(1, 'tjenester'); ?>
|
||||
<?php echo loginbar($sp, $pdo); ?>
|
||||
</nav>
|
||||
<main>
|
||||
|
||||
<div class="baseServiceCard categoryTitleCard <?php echo $categoryClass; ?>">
|
||||
<h3 class="categoryTitle">
|
||||
<?php echo htmlspecialchars($category['title']); ?>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="serviceWrapper">
|
||||
|
||||
<div class="categoryContainer">
|
||||
<div class="categoryLabel">Versjonskontroll og utvikling</div>
|
||||
<div class="categoryContent">
|
||||
|
||||
<div class="service">
|
||||
<div class="serviceContent">
|
||||
<h2 class="serviceTitle">Gitea</h2>
|
||||
<p class="serviceDescription">Vår interne git-tjener, åpen for alle medlemmer</p>
|
||||
<div class="serviceLink"><a href="https://git.pvv.ntnu.no" target="_blank">Gå til git.pvv.ntnu.no</a></div>
|
||||
</div>
|
||||
<img class="serviceImage" src="img/gitea.png" alt="Gitea-logo">
|
||||
</div>
|
||||
|
||||
<div class="service">
|
||||
<div class="serviceContent">
|
||||
<h2 class="serviceTitle">GitHub</h2>
|
||||
<p class="serviceDescription">Våre offentlige kodebrønner, åpent for verden!</p>
|
||||
<div class="serviceLink"><a href="https://github.com/Programvareverkstedet/" target="_blank">Gå til GitHub</a></div>
|
||||
</div>
|
||||
<img class="serviceImage" src="img/github.png" alt="GitHub-logo">
|
||||
</div>
|
||||
|
||||
<?php foreach ($category['services'] as $service): ?>
|
||||
<div class="baseServiceCard serviceCard <?php echo $categoryClass; ?>">
|
||||
<div class="serviceContent">
|
||||
<h3 class="serviceTitle"><?php echo htmlspecialchars($service['name']); ?></h3>
|
||||
<p class="serviceDescription"><?php echo htmlspecialchars($service['description']); ?></p>
|
||||
<div class="serviceLink">
|
||||
<a href="<?php echo htmlspecialchars($service['link']); ?>" target="_blank">
|
||||
<?php echo htmlspecialchars($service['link_text']); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img class="serviceImage"
|
||||
src="<?php echo htmlspecialchars($service['image']); ?>"
|
||||
alt="<?php echo htmlspecialchars($service['name']); ?> logo">
|
||||
<div class="categoryContainer">
|
||||
<div class="categoryLabel">Kommunikasjon</div>
|
||||
<div class="categoryContent">
|
||||
|
||||
<div class="service">
|
||||
<div class="serviceContent">
|
||||
<h2 class="serviceTitle">Matrix via Element</h2>
|
||||
<p class="serviceDescription">Åpen kommunikasjonsprotokoll som støtter ende-til-ende-kryptering og utallige kule funksjoner. Vårt space er bridget sammen med Discord, så du får alle de samme meldingene. <b>#pvv:pvv.ntnu.no</b></p>
|
||||
<div class="serviceLink">
|
||||
<a href="https://chat.pvv.ntnu.no" target="_blank">Gå til chat.pvv.ntnu.no(medlem)</a>
|
||||
</div>
|
||||
<div class="serviceLink">
|
||||
<a href="https://matrix.to/#/#pvv:pvv.ntnu.no" target="_blank">Gå til #pvv:pvv.ntnu.no(offentlig)</a>
|
||||
</div>
|
||||
</div>
|
||||
<img class="serviceImage" src="img/element.png" alt="Element-logo">
|
||||
</div>
|
||||
|
||||
<div class="service">
|
||||
<div class="serviceContent">
|
||||
<h2 class="serviceTitle">Discord</h2>
|
||||
<p class="serviceDescription">Vår hovedkanal, her finner du alt fra ofisielle announcements til memes og driftsdiskusjoner.</p>
|
||||
<div class="serviceLink"><a href="https://discord.gg/WpaHGV8K" target="_blank">Gå til Discord</a></div>
|
||||
</div>
|
||||
<img class="serviceImage" src="img/discord.png" alt="Discord-logo">
|
||||
</div>
|
||||
|
||||
<div class="service">
|
||||
<div class="serviceContent">
|
||||
<h2 class="serviceTitle">Epost</h2>
|
||||
<p class="serviceDescription">Som PVV-medlem får du din egen @pvv.ntnu.no-adresse, som kan brukes med alle vanlige epostprotokoller.</p>
|
||||
<div class="serviceLink">
|
||||
<a href="https://www.pvv.ntnu.no/mail/" target="_blank">Gå til Webmail</a>
|
||||
</div>
|
||||
<div class="serviceLink">
|
||||
<a href="https://wiki.pvv.ntnu.no/wiki/Drift/Mail/IMAP_POP3" target="_blank">IMAP/POP/SMTP-innstillinger</a>
|
||||
</div>
|
||||
</div>
|
||||
<img class="serviceImage" src="img/email.png" alt="Epost-ikon">
|
||||
</div>
|
||||
|
||||
<div class="service">
|
||||
<div class="serviceContent">
|
||||
<h2 class="serviceTitle">IRC</h2>
|
||||
<p class="serviceDescription">Hvis Discord er for proprietært og Matrix er for hypermoderne er kanskje IRC for deg. Vi har en kanal på IRCNet, <b>#pvv</b>.</p>
|
||||
<div class="serviceLink"><a href="irc://irc.pvv.ntnu.no/pvv" target="_blank">Koble til med IRC</a></div>
|
||||
</div>
|
||||
<img class="serviceImage" src="img/irc.png" alt="IRC-ikon">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="categoryContainer">
|
||||
<div class="categoryLabel">Hosting</div>
|
||||
<div class="categoryContent">
|
||||
|
||||
<div class="service">
|
||||
<div class="serviceContent">
|
||||
<h2 class="serviceTitle">Brukernettsider</h2>
|
||||
<p class="serviceDescription">Alle brukere får automatisk en egen side for html og php. Denne er offentlig på pvv.ntnu.no/~brukernavn.</p>
|
||||
<div class="serviceLink"><a href="https://wiki.pvv.ntnu.no/wiki/Tjenester/Hjemmesider" target="_blank">Gå til dokumentasjon på wiki</a></div>
|
||||
</div>
|
||||
<img class="serviceImage" src="img/php.png" alt="En elephpant">
|
||||
</div>
|
||||
|
||||
<div class="service">
|
||||
<div class="serviceContent">
|
||||
<h2 class="serviceTitle">PVV-siden</h2>
|
||||
<p class="serviceDescription">Du befinner deg nå på PVV sin offisielle hjemmeside. Den er skrevet i PHP og kjører på en egen server.</p>
|
||||
<div class="serviceLink"><a href="https://git.pvv.ntnu.no/Projects/nettsiden" target="_blank">Se koden på gitea</a></div>
|
||||
</div>
|
||||
<img class="serviceImage" src="../pvv-logo.png" alt="PVV-logo">
|
||||
</div>
|
||||
|
||||
<div class="service">
|
||||
<div class="serviceContent">
|
||||
<h2 class="serviceTitle">Proxmox @blossom</h2>
|
||||
<p class="serviceDescription">Blossom er den sterkeste av våre VM-tjenere, her kan du kjøre enten fulle VM-er eller konteinere. Bare Drift har tilgang på disse tjenerne.</p>
|
||||
<div class="serviceLink"><a href="https://blossom.pvv.ntnu.no:8006" target="_blank">Gå til blossom.pvv.ntnu.no</a></div>
|
||||
</div>
|
||||
<img class="serviceImage" src="img/proxmox.png" alt="Proxmox-logo">
|
||||
</div>
|
||||
|
||||
<div class="service">
|
||||
<div class="serviceContent">
|
||||
<h2 class="serviceTitle">Proxmox @bubbles</h2>
|
||||
<p class="serviceDescription">Bubbles er den svakeste av våre VM-tjenere.</p>
|
||||
<div class="serviceLink"><a href="https://bubbles.pvv.ntnu.no:8006" target="_blank">Gå til bubbles.pvv.ntnu.no</a></div>
|
||||
</div>
|
||||
<img class="serviceImage" src="img/proxmox.png" alt="Proxmox-logo">
|
||||
</div>
|
||||
|
||||
<div class="service">
|
||||
<div class="serviceContent">
|
||||
<h2 class="serviceTitle">Proxmox @buttercup</h2>
|
||||
<p class="serviceDescription">Buttercup er en av våre VM-tjenere.</p>
|
||||
<div class="serviceLink"><a href="https://buttercup.pvv.ntnu.no:8006" target="_blank">Gå til buttercup.pvv.ntnu.no</a></div>
|
||||
</div>
|
||||
<img class="serviceImage" src="img/proxmox.png" alt="Proxmox-logo">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="categoryContainer">
|
||||
<div class="categoryLabel">Underholdning</div>
|
||||
<div class="categoryContent">
|
||||
|
||||
<div class="service">
|
||||
<div class="serviceContent">
|
||||
<h2 class="serviceTitle">Minecraft</h2>
|
||||
<p class="serviceDescription">Vi har en egen Minecraft-server <b>for medlemmer</b>, som du kan koble til med IP-adressen <b>minecraft.pvv.ntnu.no</b>. Spør om whitelist på matrix/discord.</p>
|
||||
<div class="serviceLink"><a href="https://minecraft.pvv.ntnu.no" target="_blank">Gå til verdenskartet vårt</a></div>
|
||||
</div>
|
||||
<img class="serviceImage" src="img/minecraft.png" alt="Minecraft-logo">
|
||||
</div>
|
||||
|
||||
<div class="service">
|
||||
<div class="serviceContent">
|
||||
<h2 class="serviceTitle">MiniFlux RSS reader</h2>
|
||||
<p class="serviceDescription">Trenger du en cross-platform RSS/Atom-leser for å følge med på omverdenen som det er 1990? </p>
|
||||
<div class="serviceLink"><a href="https://feeds.pvv.ntnu.no" target="_blank">Gå til MiniFlux</a></div>
|
||||
</div>
|
||||
<img class="serviceImage" src="img/rss.png" alt="RSS-Ikon">
|
||||
</div>
|
||||
|
||||
<div class="service">
|
||||
<div class="serviceContent">
|
||||
<h2 class="serviceTitle">Bildegalleri</h2>
|
||||
<p class="serviceDescription">PVV har et felles bildegalleri, der alle kan legge relevante bilder, som automatisk blir inkludert på nettsiden.</p>
|
||||
<div class="serviceLink">
|
||||
<a href="https://www.pvv.ntnu.no/galleri/" target="_blank">Se galleriet</a>
|
||||
</div>
|
||||
<div class="serviceLink">
|
||||
<a href="https://wiki.pvv.ntnu.no/wiki/Bildedeling" target="_blank">Opplasting</a>
|
||||
</div>
|
||||
</div>
|
||||
<img class="serviceImage" src="img/gallery.png" alt="RSS-Ikon">
|
||||
</div>
|
||||
|
||||
<!-- Bokhylle /brzeczyszczykiewicz ? -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</main>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||