5 Commits

22 changed files with 933 additions and 637 deletions

110
composer.lock generated
View File

@@ -1619,16 +1619,16 @@
}, },
{ {
"name": "symfony/cache", "name": "symfony/cache",
"version": "v6.4.31", "version": "v6.4.30",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/cache.git", "url": "https://github.com/symfony/cache.git",
"reference": "a1b306757c34b96fe97c0c586f50dceed05c7adb" "reference": "eb3272ed2daed13ed24816e862d73f73d995972a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/a1b306757c34b96fe97c0c586f50dceed05c7adb", "url": "https://api.github.com/repos/symfony/cache/zipball/eb3272ed2daed13ed24816e862d73f73d995972a",
"reference": "a1b306757c34b96fe97c0c586f50dceed05c7adb", "reference": "eb3272ed2daed13ed24816e862d73f73d995972a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1695,7 +1695,7 @@
"psr6" "psr6"
], ],
"support": { "support": {
"source": "https://github.com/symfony/cache/tree/v6.4.31" "source": "https://github.com/symfony/cache/tree/v6.4.30"
}, },
"funding": [ "funding": [
{ {
@@ -1715,7 +1715,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-12-27T18:26:25+00:00" "time": "2025-12-01T16:41:59+00:00"
}, },
{ {
"name": "symfony/cache-contracts", "name": "symfony/cache-contracts",
@@ -1874,16 +1874,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v6.4.31", "version": "v6.4.30",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "f9f8a889f54c264f9abac3fc0f7a371ffca51997" "reference": "1b2813049506b39eb3d7e64aff033fd5ca26c97e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/f9f8a889f54c264f9abac3fc0f7a371ffca51997", "url": "https://api.github.com/repos/symfony/console/zipball/1b2813049506b39eb3d7e64aff033fd5ca26c97e",
"reference": "f9f8a889f54c264f9abac3fc0f7a371ffca51997", "reference": "1b2813049506b39eb3d7e64aff033fd5ca26c97e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1948,7 +1948,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v6.4.31" "source": "https://github.com/symfony/console/tree/v6.4.30"
}, },
"funding": [ "funding": [
{ {
@@ -1968,20 +1968,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-12-22T08:30:34+00:00" "time": "2025-12-05T13:47:41+00:00"
}, },
{ {
"name": "symfony/dependency-injection", "name": "symfony/dependency-injection",
"version": "v6.4.31", "version": "v6.4.30",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/dependency-injection.git", "url": "https://github.com/symfony/dependency-injection.git",
"reference": "10058832a74a33648870aa2057e3fdc8796a6566" "reference": "5328f994cbb0855ba25c3a54f4a31a279511640f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/10058832a74a33648870aa2057e3fdc8796a6566", "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/5328f994cbb0855ba25c3a54f4a31a279511640f",
"reference": "10058832a74a33648870aa2057e3fdc8796a6566", "reference": "5328f994cbb0855ba25c3a54f4a31a279511640f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2033,7 +2033,7 @@
"description": "Allows you to standardize and centralize the way objects are constructed in your application", "description": "Allows you to standardize and centralize the way objects are constructed in your application",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/dependency-injection/tree/v6.4.31" "source": "https://github.com/symfony/dependency-injection/tree/v6.4.30"
}, },
"funding": [ "funding": [
{ {
@@ -2053,7 +2053,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-12-23T13:34:50+00:00" "time": "2025-12-07T09:29:59+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
@@ -2505,16 +2505,16 @@
}, },
{ {
"name": "symfony/finder", "name": "symfony/finder",
"version": "v6.4.31", "version": "v6.4.27",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/finder.git", "url": "https://github.com/symfony/finder.git",
"reference": "5547f2e1f0ca8e2e7abe490156b62da778cfbe2b" "reference": "a1b6aa435d2fba50793b994a839c32b6064f063b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/5547f2e1f0ca8e2e7abe490156b62da778cfbe2b", "url": "https://api.github.com/repos/symfony/finder/zipball/a1b6aa435d2fba50793b994a839c32b6064f063b",
"reference": "5547f2e1f0ca8e2e7abe490156b62da778cfbe2b", "reference": "a1b6aa435d2fba50793b994a839c32b6064f063b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2549,7 +2549,7 @@
"description": "Finds files and directories via an intuitive fluent interface", "description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/finder/tree/v6.4.31" "source": "https://github.com/symfony/finder/tree/v6.4.27"
}, },
"funding": [ "funding": [
{ {
@@ -2569,20 +2569,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-12-11T14:52:17+00:00" "time": "2025-10-15T18:32:00+00:00"
}, },
{ {
"name": "symfony/framework-bundle", "name": "symfony/framework-bundle",
"version": "v6.4.31", "version": "v6.4.30",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/framework-bundle.git", "url": "https://github.com/symfony/framework-bundle.git",
"reference": "0ab60c05570b9e2bfab92b9944b938b8ffb5ba96" "reference": "3c212ec5cac588da8357f5c061194363a4e91010"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/framework-bundle/zipball/0ab60c05570b9e2bfab92b9944b938b8ffb5ba96", "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/3c212ec5cac588da8357f5c061194363a4e91010",
"reference": "0ab60c05570b9e2bfab92b9944b938b8ffb5ba96", "reference": "3c212ec5cac588da8357f5c061194363a4e91010",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2702,7 +2702,7 @@
"description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/framework-bundle/tree/v6.4.31" "source": "https://github.com/symfony/framework-bundle/tree/v6.4.30"
}, },
"funding": [ "funding": [
{ {
@@ -2722,20 +2722,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-12-23T14:16:13+00:00" "time": "2025-11-29T11:31:32+00:00"
}, },
{ {
"name": "symfony/http-foundation", "name": "symfony/http-foundation",
"version": "v6.4.31", "version": "v6.4.30",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/http-foundation.git", "url": "https://github.com/symfony/http-foundation.git",
"reference": "a35ee6f47e4775179704d7877a8b0da3cb09241a" "reference": "0384c62b79d96e9b22d77bc1272c9e83342ba3a6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/a35ee6f47e4775179704d7877a8b0da3cb09241a", "url": "https://api.github.com/repos/symfony/http-foundation/zipball/0384c62b79d96e9b22d77bc1272c9e83342ba3a6",
"reference": "a35ee6f47e4775179704d7877a8b0da3cb09241a", "reference": "0384c62b79d96e9b22d77bc1272c9e83342ba3a6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2783,7 +2783,7 @@
"description": "Defines an object-oriented layer for the HTTP specification", "description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/http-foundation/tree/v6.4.31" "source": "https://github.com/symfony/http-foundation/tree/v6.4.30"
}, },
"funding": [ "funding": [
{ {
@@ -2803,20 +2803,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-12-17T10:10:57+00:00" "time": "2025-12-01T20:07:31+00:00"
}, },
{ {
"name": "symfony/http-kernel", "name": "symfony/http-kernel",
"version": "v6.4.31", "version": "v6.4.30",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/http-kernel.git", "url": "https://github.com/symfony/http-kernel.git",
"reference": "16b0d46d8e11f480345c15b229cfc827a8a0f731" "reference": "ceac681e74e824bbf90468eb231d40988d6d18a5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/16b0d46d8e11f480345c15b229cfc827a8a0f731", "url": "https://api.github.com/repos/symfony/http-kernel/zipball/ceac681e74e824bbf90468eb231d40988d6d18a5",
"reference": "16b0d46d8e11f480345c15b229cfc827a8a0f731", "reference": "ceac681e74e824bbf90468eb231d40988d6d18a5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2901,7 +2901,7 @@
"description": "Provides a structured process for converting a Request into a Response", "description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/http-kernel/tree/v6.4.31" "source": "https://github.com/symfony/http-kernel/tree/v6.4.30"
}, },
"funding": [ "funding": [
{ {
@@ -2921,7 +2921,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-12-31T08:27:27+00:00" "time": "2025-12-07T15:49:34+00:00"
}, },
{ {
"name": "symfony/intl", "name": "symfony/intl",
@@ -4018,16 +4018,16 @@
}, },
{ {
"name": "symfony/twig-bridge", "name": "symfony/twig-bridge",
"version": "v6.4.31", "version": "v6.4.30",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/twig-bridge.git", "url": "https://github.com/symfony/twig-bridge.git",
"reference": "24a498d80fd2a28087fbac0a96e0721ce2756b65" "reference": "d77a78c7fffaf7cb0158d28db824ba78d89a9f34"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/twig-bridge/zipball/24a498d80fd2a28087fbac0a96e0721ce2756b65", "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/d77a78c7fffaf7cb0158d28db824ba78d89a9f34",
"reference": "24a498d80fd2a28087fbac0a96e0721ce2756b65", "reference": "d77a78c7fffaf7cb0158d28db824ba78d89a9f34",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4107,7 +4107,7 @@
"description": "Provides integration for Twig with various Symfony components", "description": "Provides integration for Twig with various Symfony components",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/twig-bridge/tree/v6.4.31" "source": "https://github.com/symfony/twig-bridge/tree/v6.4.30"
}, },
"funding": [ "funding": [
{ {
@@ -4127,20 +4127,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-12-11T18:16:47+00:00" "time": "2025-12-05T13:01:31+00:00"
}, },
{ {
"name": "symfony/var-dumper", "name": "symfony/var-dumper",
"version": "v7.4.3", "version": "v7.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/var-dumper.git", "url": "https://github.com/symfony/var-dumper.git",
"reference": "7e99bebcb3f90d8721890f2963463280848cba92" "reference": "41fd6c4ae28c38b294b42af6db61446594a0dece"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/7e99bebcb3f90d8721890f2963463280848cba92", "url": "https://api.github.com/repos/symfony/var-dumper/zipball/41fd6c4ae28c38b294b42af6db61446594a0dece",
"reference": "7e99bebcb3f90d8721890f2963463280848cba92", "reference": "41fd6c4ae28c38b294b42af6db61446594a0dece",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4194,7 +4194,7 @@
"dump" "dump"
], ],
"support": { "support": {
"source": "https://github.com/symfony/var-dumper/tree/v7.4.3" "source": "https://github.com/symfony/var-dumper/tree/v7.4.0"
}, },
"funding": [ "funding": [
{ {
@@ -4214,7 +4214,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-12-18T07:04:31+00:00" "time": "2025-10-27T20:36:44+00:00"
}, },
{ {
"name": "symfony/var-exporter", "name": "symfony/var-exporter",
@@ -4583,5 +4583,5 @@
"prefer-lowest": false, "prefer-lowest": false,
"platform": {}, "platform": {},
"platform-dev": {}, "platform-dev": {},
"plugin-api-version": "2.9.0" "plugin-api-version": "2.6.0"
} }

View File

@@ -8,22 +8,52 @@ CREATE TABLE events (
`description` TEXT `description` TEXT
); );
CREATE TABLE projects ( CREATE TABLE project_group (
`id` INTEGER PRIMARY KEY AUTO_INCREMENT, `id` INTEGER PRIMARY KEY AUTO_INCREMENT,
`name` TEXT NOT NULL, `title` TEXT NOT NULL,
`description` TEXT, `description_en` TEXT NOT NULL,
`active` BOOLEAN DEFAULT TRUE `description_no` TEXT NOT NULL,
`gitea_link` TEXT NOT NULL,
`wiki_link` TEXT
); );
CREATE TABLE projectmembers ( INSERT INTO
project_group (title, description_en, description_no, gitea_link, wiki_link)
VALUES
(
'Projects',
'Projects developed by members of PVV.',
'Prosjekter utviklet av medlemmer i PVV.',
'https://git.pvv.ntnu.no/Projects',
'https://wiki.pvv.ntnu.no/wiki/Programvareutvikling'
);
CREATE TABLE project (
`id` INTEGER PRIMARY KEY AUTO_INCREMENT, `id` INTEGER PRIMARY KEY AUTO_INCREMENT,
`projectid` INTEGER FOREIGN KEY REFERENCES projects(`id`), `group_id` INTEGER NOT NULL REFERENCES project_group (id) DEFAULT 1,
`title` TEXT NOT NULL,
`description_en` TEXT NOT NULL,
`description_no` TEXT NOT NULL,
`gitea_link` TEXT,
`issue_board_link` TEXT,
`wiki_link` TEXT,
`programming_languages` TEXT,
`technologies` TEXT,
`keywords` TEXT,
`license` TEXT,
`logo_url` TEXT,
`is_hidden` BOOLEAN DEFAULT FALSE,
FOREIGN KEY (group_id) REFERENCES project_group (id) ON DELETE SET DEFAULT
);
CREATE TABLE project_maintainer (
`uname` TEXT NOT NULL,
`project_id` INTEGER NOT NULL,
`name` TEXT NOT NULL, `name` TEXT NOT NULL,
`uname` TEXT NOT NULL REFERENCES users(`uname`), `email` TEXT,
`mail` TEXT, `is_organizer` BOOLEAN DEFAULT FALSE,
`role` TEXT, PRIMARY KEY (uname, project_id),
`lead` BOOLEAN NOT NULL DEFAULT FALSE, FOREIGN KEY (project_id) REFERENCES project (id) ON DELETE CASCADE
`owner` BOOLEAN NOT NULL DEFAULT FALSE
); );
CREATE TABLE users ( CREATE TABLE users (

View File

@@ -8,24 +8,58 @@ CREATE TABLE "events" (
"description" TEXT "description" TEXT
); );
CREATE TABLE "projects" ( -- PROJECTS
CREATE TABLE "project_group" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT, "id" INTEGER PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL, "title" TEXT NOT NULL,
"description" TEXT, "description_en" TEXT NOT NULL,
"active" BOOLEAN DEFAULT TRUE "description_no" TEXT NOT NULL,
"gitea_link" TEXT NOT NULL,
"wiki_link" TEXT
); );
CREATE TABLE "projectmembers" ( INSERT INTO
"id" INTEGER PRIMARY KEY AUTOINCREMENT, project_group (title, description_en, description_no, gitea_link, wiki_link)
"projectid" INTEGER REFERENCES projects(id), VALUES
"name" TEXT NOT NULL, (
"uname" TEXT NOT NULL REFERENCES users(uname), 'Projects',
"mail" TEXT, 'Projects developed by members of PVV.',
"role" TEXT, 'Prosjekter utviklet av medlemmer i PVV.',
"lead" BOOLEAN NOT NULL DEFAULT FALSE, 'https://git.pvv.ntnu.no/Projects',
"owner" BOOLEAN NOT NULL DEFAULT FALSE 'https://wiki.pvv.ntnu.no/wiki/Programvareutvikling'
); );
CREATE TABLE "project" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"group_id" INTEGER NOT NULL DEFAULT 1,
"title" TEXT NOT NULL,
"description_en" TEXT NOT NULL,
"description_no" TEXT NOT NULL,
"gitea_link" TEXT,
"issue_board_link" TEXT,
"wiki_link" TEXT,
"programming_languages" TEXT,
"technologies" TEXT,
"keywords" TEXT,
"license" TEXT,
"logo_url" TEXT,
"is_hidden" BOOLEAN DEFAULT FALSE,
FOREIGN KEY (group_id) REFERENCES project_group (id) ON DELETE SET DEFAULT
);
CREATE TABLE "project_maintainer" (
"uname" TEXT NOT NULL,
"project_id" INTEGER NOT NULL,
"name" TEXT NOT NULL,
"email" TEXT,
"is_organizer" BOOLEAN DEFAULT FALSE,
PRIMARY KEY (uname, project_id),
FOREIGN KEY (project_id) REFERENCES project (id) ON DELETE CASCADE
);
--
CREATE TABLE "users" ( CREATE TABLE "users" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT, "id" INTEGER PRIMARY KEY AUTOINCREMENT,
"uname" TEXT NOT NULL UNIQUE, "uname" TEXT NOT NULL UNIQUE,

View File

@@ -22,7 +22,7 @@ php.buildComposerProject rec {
}; };
pname = "pvv-nettsiden"; pname = "pvv-nettsiden";
version = "0.0.1"; version = "0.0.1";
vendorHash = "sha256-3+hX9tzC7IvU2bDKpPsfk/TH1ZxffTp+5k5ky5tP7yg="; vendorHash = "sha256-7I7Fdp5DvCwCdYY66Mv0hZ+a8xRzQt+WMUKG544k7Fc=";
passthru.simplesamlphpPath = "share/php/pvv-nettsiden/vendor/simplesamlphp/simplesamlphp"; passthru.simplesamlphpPath = "share/php/pvv-nettsiden/vendor/simplesamlphp/simplesamlphp";

View File

@@ -6,35 +6,159 @@ namespace pvv\side;
class Project { class Project {
private int $id; private int $id;
private string $name; private string $title;
private array $descr; private array $description_en;
private bool $active; private array $description_no;
private ?string $gitea_link;
private ?string $issue_board_link;
private ?string $wiki_link;
private array $programming_languages;
private array $technologies;
private array $keywords;
// NOTE: spdx identifier
private ?string $license;
private ?string $logo_url;
private bool $is_hidden;
public function __construct( public function __construct(
int $id, int $id,
string $name, string $title,
string $descr, ?string $description_en,
bool $active, ?string $description_no,
?string $gitea_link,
?string $issue_board_link,
?string $wiki_link,
?string $programming_languages,
?string $technologies,
?string $keywords,
?string $license,
?string $logo_url,
bool $is_hidden = false,
) { ) {
$this->id = $id; $this->id = $id;
$this->name = $name; $this->title = $title;
$this->descr = explode("\n", $descr); $this->description_en
$this->active = $active; = $description_en === null || $description_en === ''
? []
: explode("\n", $description_en);
$this->description_no
= $description_no === null || $description_no === ''
? []
: explode("\n", $description_no);
$this->gitea_link = $gitea_link;
$this->issue_board_link = $issue_board_link;
$this->wiki_link = $wiki_link;
$this->programming_languages
= $programming_languages === null || $programming_languages === ''
? []
: explode(',', $programming_languages);
$this->technologies
= $technologies === null || $technologies === ''
? []
: explode(',', $technologies);
$this->keywords
= $keywords === null || $keywords === '' ? [] : explode(',', $keywords);
$this->license = $license;
$this->logo_url = $logo_url;
$this->is_hidden = $is_hidden;
} }
public function getID(): int { public function getID(): int {
return $this->id; return $this->id;
} }
public function getTitle(): string {
return $this->title;
}
/**
* @return string[]
*/
public function getDescriptionEn(): array {
return $this->description_en;
}
/**
* @return string[]
*/
public function getDescriptionNo(): array {
return $this->description_no;
}
public function getGiteaLink(): ?string {
return $this->gitea_link;
}
public function getIssueBoardLink(): ?string {
return $this->issue_board_link;
}
public function getWikiLink(): ?string {
return $this->wiki_link;
}
/**
* @return string[]
*/
public function getProgrammingLanguages(): array {
return $this->programming_languages;
}
/**
* @return string[]
*/
public function getTechnologies(): array {
return $this->technologies;
}
/**
* @return string[]
*/
public function getKeywords(): array {
return $this->keywords;
}
public function getLicense(): ?string {
return $this->license;
}
public function getLogoURL(): ?string {
return $this->logo_url;
}
public function isHidden(): bool {
return $this->is_hidden;
}
}
class ProjectMaintainer {
private string $uname;
private string $name;
private string $email;
private bool $is_organizer;
public function __construct(
string $uname,
string $name,
string $email,
bool $is_organizer,
) {
$this->uname = $uname;
$this->name = $name;
$this->email = $email;
$this->is_organizer = $is_organizer;
}
public function getUname(): string {
return $this->uname;
}
public function getName(): string { public function getName(): string {
return $this->name; return $this->name;
} }
public function getEmail(): string {
public function getDescription(): array { return $this->email;
return $this->descr;
} }
public function isOrganizer(): bool {
public function getActive(): bool { return $this->is_organizer;
return $this->active;
} }
} }

View File

@@ -11,11 +11,30 @@ class ProjectManager {
$this->pdo = $pdo; $this->pdo = $pdo;
} }
// TODO: groupid
/** /**
* @return Project[] * @return Project[]
*/ */
public function getAll(): array { public function getAll(): array {
$query = 'SELECT * FROM projects ORDER BY id ASC'; $query = '
SELECT
id,
title,
description_en,
description_no,
gitea_link,
issue_board_link,
wiki_link,
programming_languages,
technologies,
keywords,
license,
logo_url,
is_hidden
FROM project
ORDER BY title ASC
';
$statement = $this->pdo->prepare($query); $statement = $this->pdo->prepare($query);
$statement->execute(); $statement->execute();
@@ -23,9 +42,18 @@ class ProjectManager {
foreach ($statement->fetchAll() as $dbProj) { foreach ($statement->fetchAll() as $dbProj) {
$project = new Project( $project = new Project(
$dbProj['id'], $dbProj['id'],
$dbProj['name'], $dbProj['title'],
$dbProj['description'], $dbProj['description_en'],
(bool) $dbProj['active'], $dbProj['description_no'],
$dbProj['gitea_link'],
$dbProj['issue_board_link'],
$dbProj['wiki_link'],
$dbProj['programming_languages'],
$dbProj['technologies'],
$dbProj['keywords'],
$dbProj['license'],
$dbProj['logo_url'],
(bool) $dbProj['is_hidden']
); );
$projects[] = $project; $projects[] = $project;
} }
@@ -33,8 +61,26 @@ class ProjectManager {
return $projects; return $projects;
} }
// TODO: groupid
public function getByID(int $id): ?Project { public function getByID(int $id): ?Project {
$query = 'SELECT * FROM projects WHERE id=:id LIMIT 1'; $query = '
SELECT
id,
title,
description_en,
description_no,
gitea_link,
issue_board_link,
wiki_link,
programming_languages,
technologies,
keywords,
license,
logo_url,
is_hidden
FROM project
WHERE id = :id
';
$statement = $this->pdo->prepare($query); $statement = $this->pdo->prepare($query);
$statement->bindParam(':id', $id, \PDO::PARAM_INT); $statement->bindParam(':id', $id, \PDO::PARAM_INT);
$statement->execute(); $statement->execute();
@@ -46,87 +92,139 @@ class ProjectManager {
return new Project( return new Project(
$dbProj['id'], $dbProj['id'],
$dbProj['name'], $dbProj['title'],
$dbProj['description'], $dbProj['description_en'],
(bool) $dbProj['active'], $dbProj['description_no'],
$dbProj['gitea_link'],
$dbProj['issue_board_link'],
$dbProj['wiki_link'],
$dbProj['programming_languages'],
$dbProj['technologies'],
$dbProj['keywords'],
$dbProj['license'],
$dbProj['logo_url'],
(bool) $dbProj['is_hidden']
); );
} }
// TODO: groupid
/** /**
* @return Project[] * @return Project[]
*/ */
public function getByOwner(string $uname): array { public function getByMaintainer(string $uname): array {
$query = 'SELECT projectid FROM projectmembers WHERE uname=:uname'; $query = '
SELECT
project.id,
project.title
project.description_en,
project.description_no,
project.gitea_link,
project.issue_board_link,
project.wiki_link,
project.programming_languages,
project.technologies,
project.keywords,
project.license,
project.logo_url,
project.is_hidden
FROM project_maintainer
JOIN project ON project.id = project_maintainer.project_id
WHERE project_maintainer.uname = :uname
';
$statement = $this->pdo->prepare($query); $statement = $this->pdo->prepare($query);
$statement->bindParam(':uname', $uname, \PDO::PARAM_STR); $statement->bindParam(':uname', $uname, \PDO::PARAM_STR);
$statement->execute(); $statement->execute();
$projectIDs = $statement->fetchAll(); $result = array_map(
$projects = []; function ($dbProj) {
foreach ($projectIDs as $id) { return new Project(
$id = $id['projectid'];
$query = 'SELECT * FROM projects WHERE id=:id';
$statement = $this->pdo->prepare($query);
$statement->bindParam(':id', $id, \PDO::PARAM_INT);
$statement->execute();
foreach ($statement->fetchAll() as $dbProj) {
$project = new Project(
$dbProj['id'], $dbProj['id'],
$dbProj['name'], $dbProj['title'],
$dbProj['description'], $dbProj['description_en'],
(bool) $dbProj['active'], $dbProj['description_no'],
$dbProj['gitea_link'],
$dbProj['issue_board_link'],
$dbProj['wiki_link'],
$dbProj['programming_languages'],
$dbProj['technologies'],
$dbProj['keywords'],
$dbProj['license'],
$dbProj['logo_url'],
(bool) $dbProj['is_hidden']
);
},
$statement->fetchAll()
); );
$projects[] = $project;
}
}
return $projects; return $result;
} }
/** /**
* @return array<int,array> * @return ProjectMaintainer[]
*/ */
public function getProjectMembers(int $id): array { public function getProjectMaintainers(int $project_id): array {
$query = 'SELECT * FROM projectmembers WHERE projectid=:id'; $query = '
SELECT
project_maintainer.uname,
project_maintainer.name,
project_maintainer.email,
project_maintainer.is_organizer
FROM project_maintainer
WHERE project_maintainer.project_id = :id
';
$statement = $this->pdo->prepare($query); $statement = $this->pdo->prepare($query);
$statement->bindParam(':id', $id, \PDO::PARAM_STR); $statement->bindParam(':id', $project_id, \PDO::PARAM_STR);
$statement->execute(); $statement->execute();
$members = []; $result = array_map(
foreach ($statement->fetchAll() as $dbUsr) { function ($dbUsr) {
$members[] = [ return new ProjectMaintainer(
'name' => $dbUsr['name'], $dbUsr['uname'],
'uname' => $dbUsr['uname'], $dbUsr['name'],
'mail' => $dbUsr['mail'], $dbUsr['email'],
'role' => $dbUsr['role'], (bool)$dbUsr['is_organizer']
'lead' => (bool) $dbUsr['lead'], );
'owner' => (bool) $dbUsr['owner'], },
]; $statement->fetchAll()
} );
return $members; return $result;
} }
/** /**
* @return array<string,mixed> * @return ProjectMaintainer[]
*/ */
public function getProjectOwner(int $id): array { public function getProjectOrganizers(int $project_id): array {
$query = 'SELECT * FROM projectmembers WHERE (projectid=:id AND owner=1)'; $query = '
SELECT
project_maintainer.uname,
project_maintainer.name,
project_maintainer.email,
project_maintainer.is_organizer
FROM project_maintainer
WHERE
project_maintainer.project_id = :id
AND project_maintainer.is_organizer = True
';
$statement = $this->pdo->prepare($query); $statement = $this->pdo->prepare($query);
$statement->bindParam(':id', $id, \PDO::PARAM_STR); $statement->bindParam(':id', $project_id, \PDO::PARAM_STR);
$statement->execute(); $statement->execute();
$dbOwner = $statement->fetch(); $result = array_map(
function ($dbUsr) {
return new ProjectMaintainer(
$dbUsr['uname'],
$dbUsr['name'],
$dbUsr['email'],
(bool)$dbUsr['is_organizer']
);
},
$statement->fetchAll()
);
return [ return $result;
'name' => $dbOwner['name'],
'uname' => $dbOwner['uname'],
'mail' => $dbOwner['mail'],
'role' => $dbOwner['role'],
'lead' => (bool) $dbOwner['lead'],
'owner' => (bool) $dbOwner['owner'],
];
} }
} }

View File

@@ -39,22 +39,22 @@ class BrettspillEvent extends Event {
'', '',
'## Vår samling', '## Vår samling',
'', '',
'* Dominion\\*', '* Dominion\*',
'* Three cheers for master', '* Three cheers for master',
'* Avalon', '* Avalon',
'* Hanabi', '* Hanabi',
'* Cards aginst humanity\\*', '* Cards aginst humanity\*',
'* Citadels', '* Citadels',
'* Munchkin\\*\\*', '* Munchkin\*\*',
'* Exploding kittens\\*\\*', '* Exploding kittens\*\*',
'* Aye dark overlord', '* Aye dark overlord',
'* Settlers of catan\\*', '* Settlers of catan\*',
'* Risk\\*\\*', '* Risk\*\*',
'* og mange flere...', '* og mange flere...',
'', '',
'\\* Vi har flere ekspansjoner til spillet', '\* Vi har flere ekspansjoner til spillet',
'', '',
'\\*\\* Vi har flere varianter av spillet', '\*\* Vi har flere varianter av spillet',
]; ];
} }

View File

@@ -18,8 +18,9 @@ if (!$userManager->hasGroup($uname, 'prosjekt')) {
$projectID = $_GET['id']; $projectID = $_GET['id'];
$query = 'DELETE FROM projects WHERE id=\'' . $projectID . '\''; $query = 'DELETE FROM project WHERE id=:projectID';
$statement = $pdo->prepare($query); $statement = $pdo->prepare($query);
$statement->bindParam(':projectID', $projectID, PDO::PARAM_INT);
$statement->execute(); $statement->execute();
header('Location: ' . $_SERVER['HTTP_REFERER']); header('Location: ' . $_SERVER['HTTP_REFERER']);

View File

@@ -37,13 +37,18 @@ if (isset($_GET['id'])) {
} }
$project = new pvv\side\Project( $project = new pvv\side\Project(
0, id: 0,
'Kult Prosjekt', title: 'Kult Prosjekt',
'', description_en: '',
'kåre knoll', description_no: '',
'pvvadmin', gitea_link: 'https://git.pvv.ntnu.no/Projects/kultprosjekt',
'drift@pvv.ntnu.no', issue_board_link: 'https://git.pvv.ntnu.no/Projects/kultprosjekt/issues',
0 wiki_link: 'https://wiki.pvv.ntnu.no/wiki/Kult_Prosjekt',
programming_languages: 'PHP, HTML, CSS, JavaScript',
technologies: 'MySQL, REST, AJAX',
keywords: 'web, very-cool',
license: 'GPL-3.0',
logo_url: '',
); );
if ($new == 0) { if ($new == 0) {
$project = $projectManager->getByID($projectID); $project = $projectManager->getByID($projectID);
@@ -56,7 +61,7 @@ $owner = [
'mail' => '', 'mail' => '',
]; ];
foreach ($members as $i => $data) { foreach ($members as $i => $data) {
if ($data['owner']) { if ($data['is_owner']) {
$owner = $data; $owner = $data;
} }
} }

View File

@@ -43,7 +43,7 @@ if(isset($_POST['organiser'])){
// filter // filter
$projects = array_values(array_filter( $projects = array_values(array_filter(
$projects, $projects,
static fn($project) => preg_match('/.*' . $filterTitle . '.*/i', $project->getName()) static fn($project) => preg_match('/.*' . $filterTitle . '.*/i', $project->getTitle())
)); ));
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
@@ -87,17 +87,17 @@ $projects = array_values(array_filter(
$project = $projects[$i]; $project = $projects[$i];
$projectID = $project->getID(); $projectID = $project->getID();
$owner = $projectManager->getProjectOwner($projectID); $organizers = $projectManager->getProjectOrganizers($projectID);
?> ?>
<li> <li>
<div class="event admin"> <div class="event admin">
<div class="event-info"> <div class="event-info">
<h3 class="no-chin"><?php echo $project->getName() . ' (ID: ' . $projectID . ')'; ?></h3> <h3 class="no-chin"><?php echo $project->getTitle() . ' (ID: ' . $projectID . ')'; ?></h3>
<p class="subnote"><?php echo 'Organisert av: ' . $owner['name']; ?></p> <p class="subnote"><?php echo 'Organisert av: ' . implode(',', array_map(function($org) { return $org->getName(); }, $organizers)); ?></p>
<?php <?php
$Parsedown = new Parsedown(); $Parsedown = new Parsedown();
echo $Parsedown->text(implode("\n", $project->getDescription())); echo $Parsedown->text(implode("\n", $project->getDescriptionNo()));
?> ?>
</div> </div>

View File

@@ -1,173 +1,120 @@
a.nostyle {
text-decoration: none;
color:inherit;
cursor: pointer;
}
.project-card { .project-card {
position: relative; position: relative;
display: flex;
flex-direction: column;
box-sizing: border-box; box-sizing: border-box;
border-radius: .15em; border-radius: .2em;
border: 0 solid #048; border-left: .3em solid #048;
border-left-width: .3em;
box-shadow: 0 .1em .3em -.1em rgba(0,0,0,0.5); box-shadow: 0 .1em .3em -.1em rgba(0,0,0,0.5);
overflow: hidden; background: #fff;
top: 0; min-height: 8em;
min-height: 6em; transition: box-shadow .15s ease, transform .15s ease;
margin: 0;
height: 100%;
} }
.project-card:hover { .project-card:hover {
box-shadow: 0.1em 0.2em 0.5em 0em rgba(0,0,0,0.5); box-shadow: 0.2em 0.3em 0.6em rgba(0,0,0,0.45);
transform: translateY(-2px);
}
/* Header */
.project-header {
display: flex;
align-items: center;
gap: .6em;
padding: .6em;
}
.project-logo {
width: 2.4em;
height: 2.4em;
object-fit: contain;
border-radius: .2em;
flex-shrink: 0;
} }
.project-title { .project-title {
padding-bottom: .1em;
margin: 0; margin: 0;
font-size: 1.05em;
text-overflow: ellipsis; text-overflow: ellipsis;
}
.card-content {
display: block;
margin: .6em;
margin-bottom: 0;
}
.card-content p {
line-height: 1.25em;
}
.card-content * {
margin-top: 0;
}
.project-organizer {
position: absolute;
bottom: 0;
right: 0;
margin: 0;
font-size: .8em;
text-align: right;
font-style: italic;
opacity: 0.5;
padding: 0.1em 0.4em;
}
.projects-container {
margin-top: 2em;
margin-bottom: 3em;
display: grid;
grid-template-columns: 1fr;
grid-column-gap: 0.5em;
grid-row-gap: 1.3em;
}
@media screen and (min-width: 60em) {
.projects-container {
grid-template-columns: 1fr 1fr;
}
}
@media screen and (min-width: 50rem) {
.contentsplit {
display: grid;
grid-template-columns: 17em 2.7fr;
grid-template-areas: "left right";
grid-column-gap: 0.9em;
}
}
@media screen and (max-width: 50rem) {
.contentsplit {
display: grid;
grid-template-rows: auto auto;
grid-template-areas: "right"
"left";
}
}
@media screen and (min-width: 33rem) and (max-width: 50rem) {
.projectmember-container {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: auto auto;
grid-template-areas: "organizers members"
"join join";
}
}
.gridl {
grid-area: left;
}
.projectmember-container {
padding: 0.1em 1em;
box-shadow: 0 2px 10px 0 rgba(0,0,0,0.2);
}
.projectmember-container h2 {
text-align: center;
}
.projectmember-container >form {
text-align: center;
grid-area: join;
}
.gridr {
border-left: 0;
grid-area: right;
padding:0;
margin:0;
}
.projectmember {
margin-bottom: 1em;
padding: 0 .5em 0 .5em;
overflow: hidden; overflow: hidden;
border-left: 4px solid #35a; white-space: nowrap;
} }
.projectmember p { /* Content */
.card-content {
padding: 0 .6em .4em;
flex-grow: 1;
}
.project-description {
line-height: 1.3em;
margin: 0; margin: 0;
color: #333;
} }
.projectmember p { /* Tags */
font-size: .8em; .project-tags {
margin-top: .4em;
display: flex;
flex-wrap: wrap;
gap: .3em;
} }
.projectmember p:first-child { .tag {
font-size: 1em; font-size: .7em;
margin-bottom: .2em; padding: .15em .45em;
border-radius: .3em;
background: #eef3f7;
color: #345;
white-space: nowrap;
} }
.memberuname, .memberemail { /* Footer */
display: inline-block; .project-footer {
color: #888; display: flex;
justify-content: space-between;
align-items: center;
padding: .2em .5em;
font-size: .75em;
opacity: .7;
} }
.memberuname { .project-links a {
float: left; margin-left: .4em;
text-decoration: none;
opacity: .7;
} }
.memberemail { .project-links a:hover {
float: right; opacity: 1;
}
@media screen and (max-width: 50rem) {
.projects {
display: inline-block;
}
} }
/* edit */ /* edit */
form .wide { form .wide {
min-width: 66%; min-width: 100%;
} }
form .tall { form .tall {
min-height: calc(100vh - 28em); min-height: calc(100vh - 28em);
} }
@media screen and (max-width: 50rem) { @media screen and (max-width: 50rem) {
form .wide { form .wide {
width: calc(100% - 2em); width: calc(100% - 2em);
margin: 0 1em; margin: 0 1em;
} }
} }
form .input-group {
display: flex;
}
form .input-group-item {
flex: 1;
margin: 0 0.5em;
}
form .input-group-item input.boxinput,textarea {
width: 100%;
box-sizing: border-box;
}

View File

@@ -10,7 +10,7 @@ main {
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem; gap: 1.5rem;
padding: 2rem; padding: 2rem;
margin: 50px 2%; margin: 6% 2%;
} }
/* Base styles for all cards */ /* Base styles for all cards */

View File

@@ -37,7 +37,7 @@ require_once dirname(__DIR__, 2) . implode(\DIRECTORY_SEPARATOR, ['', 'inc', 'in
<body> <body>
<nav id="navbar" class=""> <nav id="navbar" class="">
<?php echo navbar(1, ''); ?> <?php echo navbar(1, 'Hjem'); ?>
<?php echo loginbar(null, $pdo); ?> <?php echo loginbar(null, $pdo); ?>
</nav> </nav>

View File

@@ -14,31 +14,37 @@ $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$projectManager = new pvv\side\ProjectManager($pdo); $projectManager = new pvv\side\ProjectManager($pdo);
$new = 0; $project_is_new = false;
if (isset($_GET['new'])) { if (isset($_GET['new'])) {
$new = $_GET['new']; $project_is_new = $_GET['new'];
} }
$projectID = 0; $projectID = 0;
if (isset($_GET['id'])) { if (isset($_GET['id'])) {
$projectID = $_GET['id']; $projectID = $_GET['id'];
} elseif ($new == 0) { } elseif (!$project_is_new) {
echo "\nID not set"; echo "\nID not set";
exit; exit;
} }
$project = new pvv\side\Project( $project = new pvv\side\Project(
0, id: 0,
'Nytt Prosjekt', title: 'Nytt Prosjekt',
'', description_en: null,
$attrs['cn'][0], description_no: null,
$attrs['uid'][0], gitea_link: null,
$attrs['mail'][0], issue_board_link: null,
1 wiki_link: null,
programming_languages: null,
technologies: null,
keywords: null,
license: null,
logo_url: null
); );
if ($new == 0) {
if (!$project_is_new) {
$project = $projectManager->getByID($projectID); $project = $projectManager->getByID($projectID);
$owner = $projectManager->getProjectOwner($projectID); $maintainers = $projectManager->getProjectMaintainers($projectID);
if ($owner['uname'] != $attrs['uid'][0]) { if ($owner['uname'] != $attrs['uid'][0]) {
header('HTTP/1.0 403 Forbidden'); header('HTTP/1.0 403 Forbidden');
@@ -46,6 +52,7 @@ if ($new == 0) {
exit; exit;
} }
} }
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="no"> <html lang="no">
@@ -74,20 +81,144 @@ if ($new == 0) {
<form action="update.php", method="post"> <form action="update.php", method="post">
<p class="subtitle no-chin">Prosjektnavn</p> <p class="subtitle no-chin">Prosjektnavn</p>
<p class="subnote">Gi prosjektet ditt et passende navn</p> <p class="subnote">Gi prosjektet ditt et passende navn</p>
<input class="wide" type="text" name="title" value="<?php echo $project->getName(); ?>" class="boxinput"><br> <input class="wide" type="text" name="title" value="<?php echo $project->getTitle(); ?>" class="boxinput" required><br>
<div class="input-group">
<div class="input-group-item">
<p class="subtitle no-chin">Beskrivelse (<i style="opacity:0.5;">markdown</i>)</p> <p class="subtitle no-chin">Beskrivelse (<i style="opacity:0.5;">markdown</i>)</p>
<p class="subnote no-chin">Hva går prosjektet ditt ut på?</p> <p class="subnote no-chin">Hva går prosjektet ditt ut på?</p>
<p class="subnote">De første to linjene blir vist på prosjektkortet, prøv å gjøre de til et fint sammendrag eller intro!</p> <p class="subnote">De første to linjene blir vist på prosjektkortet, prøv å gjøre de til et fint sammendrag eller intro!</p>
<textarea class="tall" name="desc" style="width:100%" rows="8" class="boxinput"><?php echo implode("\n", $project->getDescription()); ?></textarea> <textarea name="desc_no" rows="3" class="boxinput" required><?php echo implode("\n", $project->getDescriptionNo()); ?></textarea>
</div>
<div class="input-group-item">
<p class="subtitle no-chin">Beskrivelse på engelsk (<i style="opacity:0.5;">markdown</i>)</p>
<p class="subnote no-chin">Gjenta på engelsk</p>
<br>
<textarea name="desc_en" rows="3" class="boxinput" required><?php echo implode("\n", $project->getDescriptionEn()); ?></textarea>
</div>
</div>
<div class="input-group">
<div class="input-group-item">
<p class="subtitle no-chin">Gitea-link</p>
<p class="subnote">Link til prosjektet på Gitea</p>
<input
type="text"
name="gitea"
placeholder="https://git.pvv.ntnu.no/Projects/mittprosjekt"
value="<?php echo $project->getGiteaLink(); ?>"
class="boxinput"
>
</div>
<div class="input-group-item">
<p class="subtitle no-chin">Issue board-link</p>
<p class="subnote">Link til issue board på Gitea</p>
<input
type="text"
name="issue"
placeholder="https://git.pvv.ntnu.no/Projects/mittprosjekt/issues"
value="<?php echo $project->getIssueBoardLink(); ?>"
class="boxinput"
>
</div>
</div>
<div class="input-group">
<div class="input-group-item">
<p class="subtitle no-chin">Logo-URL</p>
<p class="subnote">Link til logo for prosjektet</p>
<input
type="text"
name="logo"
placeholder="https://www.pvv.ntnu.no/~user/pictures/logos/prosjektlogo.png"
value="<?php echo $project->getLogoURL(); ?>"
class="boxinput"
>
</div>
<div class="input-group-item">
<p class="subtitle no-chin">Wiki-link</p>
<p class="subnote">Link til wiki-side</p>
<input
type="text"
name="wiki"
placeholder="https://wiki.pvv.ntnu.no/wiki/Prosjekter/Mitt_Prosjekt"
value="<?php echo $project->getWikiLink(); ?>"
class="boxinput"
>
</div>
</div>
<div class="input-group">
<div class="input-group-item">
<p class="subtitle no-chin">Programmeringsspråk</p>
<p class="subnote">Hvilke programmeringsspråk brukes i prosjektet?</p>
<input
type="text"
name="programming-languages"
placeholder="php,javascript,html,css"
value="<?php echo implode("\n", $project->getProgrammingLanguages()); ?>"
class="boxinput"
>
</div>
<div class="input-group-item">
<p class="subtitle no-chin">Teknologier</p>
<p class="subnote">Hvilke teknologier brukes i prosjektet?</p>
<input
type="text"
name="technologies"
placeholder="mysql,rest,ajax"
value="<?php echo implode("\n", $project->getTechnologies()); ?>"
class="boxinput"
>
</div>
<div class="input-group-item">
<p class="subtitle no-chin">Nøkkelord</p>
<p class="subnote">Nøkkelord som beskriver prosjektet</p>
<input
type="text"
name="keywords"
placeholder="web,very-cool"
value="<?php echo implode("\n", $project->getKeywords()); ?>"
class="boxinput"
>
</div>
</div>
<div class="input-group">
<div class="input-group-item">
<p class="subtitle no-chin">Lisens</p>
<p class="subnote">Hvilken lisens bruker prosjektet?</p>
<input
type="text"
name="license"
placeholder="GPL-3.0"
value="<?php echo $project->getLicense(); ?>"
class="boxinput"
>
</div>
<div class="input-group-item">
<p class="subtitle no-chin">Skult</p>
<p class="subnote">Skal prosjektet være skjult fra prosjektindeksen?</p>
<input
type="checkbox"
name="is_hidden"
value="<?php echo $project->isHidden(); ?>"
>
</div>
</div>
<?php echo '<input type="hidden" name="id" value="' . $project->getID() . '" />'; ?> <?php echo '<input type="hidden" name="id" value="' . $project->getID() . '" />'; ?>
<input type="hidden" name="active" value="1"/> <input type="hidden" name="active" value="1"/>
<div style="margin-top: 0.2em;"> <div style="margin-top: 0.2em;">
<hr class="ruler"> <hr class="ruler">
<input type="submit" class="btn" value="<?php echo $new ? 'Opprett prosjekt' : 'Lagre endringer'; ?>"></input> <input type="submit" class="btn" value="<?php echo $project_is_new ? 'Opprett prosjekt' : 'Lagre endringer'; ?>"></input>
<?php if (!$new) {?><input type="submit" class="btn" name="delete" value="Slett"></input><?php } ?> <?php if (!$project_is_new) {?><input type="submit" class="btn" name="delete" value="Slett"></input><?php } ?>
</div> </div>
</form> </form>
</main> </main>

View File

@@ -71,7 +71,6 @@ $projects = $projectManager->getAll();
<br> <br>
<center> <center>
<a class="btn" href="edit.php?new=1">Lag prosjekt</a> <a class="btn" href="edit.php?new=1">Lag prosjekt</a>
<a class="btn" href="mine.php">Mine prosjekter</a>
</center> </center>
<br> <br>
<?php <?php
@@ -84,25 +83,71 @@ $projects = $projectManager->getAll();
<div class="projects-container"> <div class="projects-container">
<?php <?php
$randProjects = array_rand($projects, min(6, count($projects))); $randProjects = array_rand($projects, min(8, count($projects)));
if (!is_array($randProjects)) { if (!is_array($randProjects)) {
$randProjects = [$randProjects]; $randProjects = [$randProjects];
} }
foreach ($randProjects as $i) { foreach ($randProjects as $i) {
$project = $projects[$i]; $project = $projects[$i];
$owner = $projectManager->getProjectOwner($project->getID()); $organizers = $projectManager->getProjectOrganizers($project->getID());
?> ?>
<a class="nostyle" href="info.php?id=<?php echo $project->getID(); ?>"><div class="project-card"> <a class="nostyle" href="info.php?id=<?php echo $project->getID(); ?>">
<article class="project-card">
<header class="project-header">
<?php if (!empty($project->getLogoURL())): ?>
<img src="<?php echo htmlspecialchars($project->getLogoURL()); ?>"
alt=""
class="project-logo">
<?php endif; ?>
<h4 class="project-title">
<?php echo htmlspecialchars($project->getTitle()); ?>
</h4>
</header>
<div class="card-content"> <div class="card-content">
<h4 class="project-title"><?php echo $project->getName(); ?></h4> <p class="project-description">
<?php <?php
$Parsedown = new Parsedown(); $Parsedown = new Parsedown();
echo $Parsedown->text(implode("\n", array_slice($project->getDescription(), 0, 2))); echo $Parsedown->text(
implode("\n", $project->getDescriptionEn())
);
?> ?>
</p>
<?php if (!empty($project->getTechnologies())): ?>
<div class="project-tags">
<?php foreach ($project->getTechnologies() as $tech): ?>
<span class="tag"><?php echo trim($tech); ?></span>
<?php endforeach; ?>
</div> </div>
<p class="project-organizer">Organisert av <?php echo $owner['name']; ?></p> <?php endif; ?>
</div></a> </div>
<footer class="project-footer">
<span class="project-organizer">
Organisert av <?php echo htmlspecialchars(implode(', ', array_map(function ($org) {
return $org->getName();
}, $organizers))); ?>
</span>
<div class="project-links">
<?php if ($project->getGiteaLink()): ?>
<a href="<?php echo $project->getGiteaLink(); ?>" title="Repository"></a>
<?php endif; ?>
<?php if ($project->getIssueBoardLink()): ?>
<a href="<?php echo $project->getIssueBoardLink(); ?>" title="Issues">🐞</a>
<?php endif; ?>
<?php if ($project->getWikiLink()): ?>
<a href="<?php echo $project->getWikiLink(); ?>" title="Wiki">📖</a>
<?php endif; ?>
</div>
</footer>
</article>
</a>
<?php } ?> <?php } ?>
</div> </div>
<center> <center>

View File

@@ -20,7 +20,7 @@ if (!$project) {
exit; exit;
} }
$members = $projectManager->getProjectMembers($projectID); $members = $projectManager->getProjectMaintainers($projectID);
$normal_members = $members; $normal_members = $members;
foreach ($normal_members as $i => $data) { foreach ($normal_members as $i => $data) {
if ($data['lead']) { if ($data['lead']) {
@@ -65,10 +65,10 @@ if ($attrs) {
<main class="contentsplit"> <main class="contentsplit">
<div class="gridr"> <div class="gridr">
<h2><?php echo $project->getName(); ?></h2> <h2><?php echo $project->getTitle(); ?></h2>
<?php <?php
$Parsedown = new Parsedown(); $Parsedown = new Parsedown();
echo $Parsedown->text(implode("\n", $project->getDescription())); echo $Parsedown->text(implode("\n", $project->getDescriptionEn()));
?> ?>
</div> </div>

View File

@@ -1,120 +0,0 @@
<?php
date_default_timezone_set('Europe/Oslo');
setlocale(\LC_ALL, 'nb_NO');
require __DIR__ . '/../../inc/navbar.php';
require __DIR__ . '/../../src/_autoload.php';
require __DIR__ . '/../../config.php';
require_once __DIR__ . '/../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth();
$attrs = $as->getAttributes();
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$projectManager = new pvv\side\ProjectManager($pdo);
$projects = $projectManager->getByOwner($attrs['uid'][0]);
$page = 1;
if (isset($_GET['page'])) {
$page = $_GET['page'];
}
$filter = '';
if (isset($_GET['filter'])) {
$filter = $_GET['filter'];
}
// filter
$projects = array_values(array_filter(
$projects,
static fn($project) => (preg_match('/.*' . $filter . '.*/i', $project->getName()) || preg_match('/.*' . $filter . '.*/i', implode(' ', $project->getDescription())))
));
?>
<!DOCTYPE html>
<html lang="no">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<link rel="shortcut icon" href="favicon.ico">
<link rel="stylesheet" href="../css/normalize.css">
<link rel="stylesheet" href="../css/style.css">
<link rel="stylesheet" href="../css/events.css">
<link rel="stylesheet" href="../css/admin.css">
<meta name="theme-color" content="#024" />
<title>Prosjektverkstedet</title>
<header>Prosjekt&shy;verk&shy;stedet</header>
<body>
<nav>
<?php echo navbar(1, 'prosjekt'); ?>
<?php echo loginbar(); ?>
</nav>
<main class="gridsplit">
<div class="gridl">
<h2 class="no-chin">Mine Prosjekter</h2>
<ul class="event-list">
<?php
$counter = 0;
$pageLimit = 8;
for ($i = ($pageLimit * ($page - 1)); $i < count($projects); ++$i) {
if ($counter == $pageLimit) {
break;
}
$project = $projects[$i];
$projectID = $project->getID();
$owner = $projectManager->getProjectOwner($projectID);
if ($owner['uname'] != $attrs['uid'][0]) {
continue;
}
?>
<li>
<div class="event">
<div class="event-info">
<a href="edit.php?id=<?php echo $project->getID(); ?>">
<h3 class="no-chin"><?php echo $project->getName(); ?></h3>
</a>
<p style="text-decoration: none;"><?php echo implode('<br>', array_slice($project->getDescription(), 0, 4)); ?></p>
</div>
</div>
</li>
<?php
++$counter;
}
?>
</ul>
<?php
if ($page != 1) {
echo '<a class="btn float-left" href="?page=' . ($page - 1) . '&filter=' . urlencode($filter) . '">Forrige side</a>';
}
if (($counter == $pageLimit) && (($pageLimit * $page) < count($projects))) {
echo '<a class="btn float-right" href="?page=' . ($page + 1) . '&filter=' . urlencode($filter) . '">Neste side</a>';
}
?>
</div>
<div class="gridr">
<h2>Verktøy</h2>
<a class="btn" href="edit.php?new=1">Lag prosjekt</a>
<h2>Filter</h2>
<form action="mine.php" method="get">
<p class="no-chin">Navn</p>
<?php echo '<input type="text" name="filter" class="boxinput" value="' . $filter . '">'; ?><br>
<div style="margin-top: 2em;">
<input type="submit" class="btn" value="Filtrer"></input>
</div>
</form>
</div>
</main>
</body>

View File

@@ -6,51 +6,140 @@ require __DIR__ . '/../../config.php';
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS); $pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if (!isset($_POST['title']) || !isset($_POST['desc']) || !isset($_POST['active'])) { $required_fields = [
'title',
'desc_no',
'desc_en',
'gitea',
'issue',
'wiki',
'programming-languages',
'technologies',
'keywords',
'license',
'logo'
];
foreach ($required_fields as $field) {
if (!isset($_POST[$field])) {
header('Location: ' . $_SERVER['HTTP_REFERER']); header('Location: ' . $_SERVER['HTTP_REFERER']);
exit; exit;
} }
}
require_once __DIR__ . '/../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php'; require_once __DIR__ . '/../../vendor/simplesamlphp/simplesamlphp/lib/_autoload.php';
$as = new SimpleSAML\Auth\Simple('default-sp'); $as = new SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth(); $as->requireAuth();
$attrs = $as->getAttributes(); $attrs = $as->getAttributes();
$id = $_POST['id']; $id = $_POST['id'] ?? 0;
$do_delete = isset($_POST['delete']); $do_delete = isset($_POST['delete']);
$do_join_or_leave = isset($_POST['join_or_leave']); $do_join_or_leave = isset($_POST['join_or_leave']);
$active = $_POST['active']; function clean_tags(string $raw): string {
$tags = array_map('trim', explode(',', $raw));
$tags = array_filter($tags, fn($tag) => !empty($tag));
return implode(',', $tags);
}
$title = $_POST['title']; $title = $_POST['title'];
$desc = $_POST['desc']; $desc_no = $_POST['desc_no'];
$desc_en = $_POST['desc_en'];
$gitea = $_POST['gitea'];
$issue = $_POST['issue'];
$wiki = $_POST['wiki'];
$langs = clean_tags($_POST['programming-languages']);
$techs = clean_tags($_POST['technologies']);
$keywords = clean_tags($_POST['keywords']);
$license = $_POST['license'];
$logo = $_POST['logo'];
$is_hidden = isset($_POST['is_hidden']) ? 1 : 0;
$name = $attrs['cn'][0]; $name = $attrs['cn'][0];
$uname = $attrs['uid'][0]; $uname = $attrs['uid'][0];
$mail = $attrs['mail'][0]; $mail = $attrs['mail'][0];
if ($id == 0) { // Create new project
if ($id == 0) { $query = <<<END
$query = 'INSERT INTO projects (name, description, active) VALUES (:title, :desc, TRUE)'; INSERT INTO
project(
title,
description_no,
description_en,
gitea_link,
issue_board_link,
wiki_link,
programming_languages,
technologies,
keywords,
license,
logo_url,
is_hidden
)
VALUES
(
:title,
:desc_no,
:desc_en,
:gitea,
:issue,
:wiki,
:programming_languages,
:technologies,
:keywords,
:license,
:logo,
:is_hidden
)
END;
$statement = $pdo->prepare($query); $statement = $pdo->prepare($query);
$statement->bindParam(':title', $title, PDO::PARAM_STR); $statement->bindParam(':title', $title, PDO::PARAM_STR);
$statement->bindParam(':desc', $desc, PDO::PARAM_STR); $statement->bindParam(':desc_no', $desc_no, PDO::PARAM_STR);
$statement->bindParam(':desc_en', $desc_en, PDO::PARAM_STR);
$statement->bindParam(':gitea', $gitea, PDO::PARAM_STR);
$statement->bindParam(':issue', $issue, PDO::PARAM_STR);
$statement->bindParam(':wiki', $wiki, PDO::PARAM_STR);
$statement->bindParam(':programming_languages', $langs, PDO::PARAM_STR);
$statement->bindParam(':technologies', $techs, PDO::PARAM_STR);
$statement->bindParam(':keywords', $keywords, PDO::PARAM_STR);
$statement->bindParam(':license', $license, PDO::PARAM_STR);
$statement->bindParam(':logo', $logo, PDO::PARAM_STR);
$statement->bindParam(':is_hidden', $is_hidden, PDO::PARAM_BOOL);
$statement->execute(); $statement->execute();
$new_id = $pdo->lastInsertId(); $new_project_id = $pdo->lastInsertId();
$ownerQuery = "INSERT INTO projectmembers (projectid, name, uname, mail, role, lead, owner) VALUES (:id, :owner, :owneruname, :owneremail, 'Prosjektleder', TRUE, TRUE)"; $insertOrganizerQuery = <<<END
$statement = $pdo->prepare($ownerQuery); INSERT INTO
$statement->bindParam(':id', $new_id, PDO::PARAM_STR); project_maintainer (
$statement->bindParam(':owner', $name, PDO::PARAM_STR); uname,
$statement->bindParam(':owneruname', $uname, PDO::PARAM_STR); project_id,
$statement->bindParam(':owneremail', $mail, PDO::PARAM_STR); name,
email,
is_organizer
)
VALUES
(
:username,
:project_id,
:user_real_name,
:user_email,
TRUE
)
END;
$statement = $pdo->prepare($insertOrganizerQuery);
$statement->bindParam(':username', $uname, PDO::PARAM_STR);
$statement->bindParam(':project_id', $new_project_id, PDO::PARAM_INT);
$statement->bindParam(':user_real_name', $name, PDO::PARAM_STR);
$statement->bindParam(':user_email', $mail, PDO::PARAM_STR);
$statement->execute(); $statement->execute();
} else { } else { // Update existing project
$projectManager = new pvv\side\ProjectManager($pdo); $projectManager = new pvv\side\ProjectManager($pdo);
$owner = $projectManager->getProjectOwner($id); // $owner = $projectManager->getProjectOwner($id);
$members = $projectManager->getProjectMembers($id); $members = $projectManager->getProjectMaintainers($id);
// if ($do_join_or_leave and $owner['uname'] != $uname) { // if ($do_join_or_leave and $owner['uname'] != $uname) {
if ($do_join_or_leave) { if ($do_join_or_leave) {
@@ -62,7 +151,12 @@ if ($id == 0) {
} }
} }
if ($is_member) {// leave 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
';
$statement = $pdo->prepare($query); $statement = $pdo->prepare($query);
$statement->bindParam(':id', $id, PDO::PARAM_STR); $statement->bindParam(':id', $id, PDO::PARAM_STR);
$statement->bindParam(':uname', $uname, PDO::PARAM_STR); $statement->bindParam(':uname', $uname, PDO::PARAM_STR);
@@ -70,7 +164,12 @@ if ($id == 0) {
$statement->execute(); $statement->execute();
echo 'leave'; echo 'leave';
} else {// join } 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)
VALUES
(:id, :name, :uname, :mail, \'Medlem\')
';
$statement = $pdo->prepare($query); $statement = $pdo->prepare($query);
$statement->bindParam(':id', $id, PDO::PARAM_STR); $statement->bindParam(':id', $id, PDO::PARAM_STR);
$statement->bindParam(':name', $name, PDO::PARAM_STR); $statement->bindParam(':name', $name, PDO::PARAM_STR);
@@ -94,19 +193,23 @@ if ($id == 0) {
// this should be done as a transaction... // this should be done as a transaction...
$pdo->beginTransaction(); $pdo->beginTransaction();
// NOTE: project members are deleted via ON DELETE CASCADE
$query = 'DELETE FROM projects WHERE id=:id'; $query = 'DELETE FROM projects WHERE id=:id';
$statement = $pdo->prepare($query); $statement = $pdo->prepare($query);
$statement->bindParam(':id', $id, PDO::PARAM_INT); $statement->bindParam(':id', $id, PDO::PARAM_INT);
$statement->execute(); $statement->execute();
$query = 'DELETE FROM projectmembers WHERE projectid=:id';
$statement = $pdo->prepare($query);
$statement->bindParam(':id', $id, PDO::PARAM_INT);
$statement->execute();
$pdo->commit(); $pdo->commit();
} else { } else {
$query = 'UPDATE projects SET name=:title, description=:desc WHERE id=:id'; $query = '
UPDATE
projects
SET
name = :title,
description = :desc
WHERE
id = :id
';
$statement = $pdo->prepare($query); $statement = $pdo->prepare($query);
$statement->bindParam(':title', $title, PDO::PARAM_STR); $statement->bindParam(':title', $title, PDO::PARAM_STR);

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 KiB

View File

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

View File

@@ -240,13 +240,6 @@ $services = [
"link_text" => "Se dokumentasjon for gophertjening", "link_text" => "Se dokumentasjon for gophertjening",
"image" => "img/gopher.png", "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", "name" => "Wiki",
"description" => "PVVs wiki er åpen for alle medlemmer, og kan brukes til dokumentasjon, notater, prosjektsider og mye mer.", "description" => "PVVs wiki er åpen for alle medlemmer, og kan brukes til dokumentasjon, notater, prosjektsider og mye mer.",
@@ -263,6 +256,32 @@ $services = [
], ],
], ],
], ],
"recreational" => [
"title" => "Underholdning og fritid",
"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" => "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",
],
],
],
"physical" => [ "physical" => [
"title" => "Fysiske tjenester", "title" => "Fysiske tjenester",
"services" => [ "services" => [
@@ -302,53 +321,7 @@ $services = [
"image" => "img/terminal.png", "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); $servicesArrayKeys = array_keys($services);