diff --git a/.gitignore b/.gitignore
index 1e69fc0..e06445a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,4 @@ bin/
include/
lib/python3.9/
pyvenv.cfg
+lib/python*
diff --git a/lib/pgfw b/lib/pgfw
index 72866bd..ee9bdd7 160000
--- a/lib/pgfw
+++ b/lib/pgfw
@@ -1 +1 @@
-Subproject commit 72866bd11c07ae50ef4fbaae683200e6bb9007b5
+Subproject commit ee9bdd7678402811f817fcaa7d35c1fdecd75cca
diff --git a/resource/scores b/resource/scores
index 4df76c1..e69de29 100644
--- a/resource/scores
+++ b/resource/scores
@@ -1,51 +0,0 @@
-44857 0
-49055 0
-50925 0
-52244 0
-52476 0
-52697 0
-53843 0
-54228 0
-55784 0
-56431 0
-56841 0
-57276 0
-59877 0
-59924 0
-60226 0
-60533 0
-60592 0
-60840 0
-61002 0
-61161 0
-61886 0
-62177 0
-64400 0
-66059 0
-67432 0
-68558 0
-70106 0
-70215 0
-72014 0
-73576 0
-73582 0
-73707 0
-74811 0
-76033 0
-76297 0
-77707 0
-79626 0
-73625 1
-92223 1
-100944 1
-104210 1
-107313 1
-108885 1
-112707 1
-114058 1
-118589 1
-124901 1
-78910 2
-82296 2
-82801 2
-97958 2
diff --git a/www/index.php b/www/index.php
index 4217e07..bde937e 100644
--- a/www/index.php
+++ b/www/index.php
@@ -368,9 +368,38 @@
- Check out Scrapeboard at an upcoming event!
+ Play Scrapeboard at an upcoming event!
+
+
+
+ Thu - Sun
+
+
+ Jan. 5 - 8
+
+
+ 2023
+
+
+
+
+ Sat
+
+
+ Nov. 5
+
+
+ 2022
+
+
+
+
Sun
@@ -464,29 +493,45 @@
+
+
Join the announcements list
-
+
-
-
-
+
diff --git a/www/subscribe.php b/www/subscribe.php
index 9eccb41..9d2fa62 100644
--- a/www/subscribe.php
+++ b/www/subscribe.php
@@ -1,20 +1,152 @@
API_HOST. "/" . API_VERSION . "/" . $request,
+ CURLOPT_HTTPAUTH => CURLAUTH_ANY,
+ CURLOPT_USERPWD => API_USER . ":" . API_TOKEN,
+
+ /* Return the response from curl_exec as a string instead or outputting it directly */
+ CURLOPT_RETURNTRANSFER => true
+ ));
+
+ /* Use HTTP POST method if requested, application/x-www-form-urlencoded */
+ if ($method == "POST")
+ {
+ curl_setopt($ch, CURLOPT_POST, true);
+
+ /* Include any post data in the request, using http_build_query to post as application/x-www-form-urlencoded */
+ if ($post_data)
+ {
+ curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
+ }
+ }
+
+ /* Define a response array that contains the success state and a message that will be filled in the case of an error */
+ $response = array("success" => false, "message" => "");
+ $result = curl_exec($ch);
+ if ($result !== false)
+ {
+ /* Make sure the appropriate response for GET or POST was received */
+ $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ if ($method == "POST" && $http_status != 201 || $method == "GET" && $http_status != 200)
+ {
+ $response["message"] = "[" . curl_getinfo($ch, CURLINFO_HTTP_CODE) . "]";
+ if ($result != "")
+ {
+ $result = json_decode($result, true);
+ if (array_key_exists("title", $result))
+ {
+ $response["message"] .= " " . $result["title"];
+ }
+ if (array_key_exists("description", $result))
+ {
+ $response["message"] .= " " . $result["description"];
+ }
+ }
+ }
+ else
+ {
+ /* Merge the response from Mailman3 into the existing response array */
+ $response["success"] = true;
+ if ($result != "")
+ {
+ $response = array_merge($response, json_decode($result, true));
+ }
+ }
+ }
+ else
+ {
+ $response["message"] = "cURL error: " . curl_error($ch);
+ }
+
+ curl_close($ch);
+ return $response;
+}
+
+/* Start a response array that will be output as JSON and get the log directory */
+$response = submit_request_to_mailman("system/configuration/paths.debian");
+
+if ($response["success"])
+{
+ /* Use the mailman-web log since www-data has write permission and record the input */
+ $log_directory = $response["log_dir"];
+ $log_path = $log_directory . "/web/mailman-web.log";
+ file_put_contents(
+ $log_path, "[" . date(DATE_RFC2822) . "] Processing subscription request with input " . json_encode($_POST) . "\n", FILE_APPEND);
+
+ if (array_key_exists("email", $_POST))
+ {
+ /* Use Data Filtering to validate that a valid email address was submitted
+ * [https://www.php.net/manual/en/filter.examples.sanitization.php]
+ *
+ * If an invalid email was submitted, print an error message and exit
+ */
+ $sanitized_email = filter_var($_POST["email"], FILTER_SANITIZE_EMAIL);
+ $response["email"] = $sanitized_email;
+ if (!filter_var($sanitized_email, FILTER_VALIDATE_EMAIL))
+ {
+ $response["success"] = false;
+ $response["message"] = $_POST["email"] . " (sanitized to $sanitized_email) is not a valid email address";
+ }
+ else
+ {
+ /* Skip the verification, confirmation, and approval emails, and subscribe the submitted address */
+ $subscription_response = submit_request_to_mailman(
+ "members", "POST", array(
+ 'list_id' => MAILING_LIST_ID,
+ 'subscriber' => $sanitized_email,
+ 'pre_verified' => true,
+ 'pre_confirmed' => true,
+ 'pre_approved' => true));
+
+ if ($subscription_response["success"])
+ {
+ $response["success"] = true;
+ $response["message"] = "Added $sanitized_email to " . MAILING_LIST_ID;
+ }
+ else
+ {
+ /* Merge in the API request response, which will contain the error information */
+ $response = array_merge($response, $subscription_response);
+ }
+ }
+ }
+ else
+ {
+ $response["success"] = false;
+ $response["message"] = "No email address to subscribe was provided";
+ }
+}
+
+/* Log the response internally, set the JSON output header, and output JSON for the client */
+file_put_contents($log_path, "[" . date(DATE_RFC2822) . "] Final response is " . json_encode($response) . "\n", FILE_APPEND);
+header("Content-Type: application/json");
+echo json_encode($response);
?>