11 Commits
v1.1 ... master

10 changed files with 184 additions and 156 deletions

View File

@@ -13,7 +13,9 @@ A light PHP web interface for managing [mlmmj](http://mlmmj.org/) mailing lists.
### For users
- Authentication via LDAP
- List all available mailinglists on the server
- Display owners and listdescription of the respective mailing lists on the index page
- Only show the edit function for mailing lists where the user is set as owner
- Edit functions per mailing list: subscribers, moderators, prefix and listdescription
### For admins
- Error handling regarding invalid user input
@@ -21,6 +23,13 @@ A light PHP web interface for managing [mlmmj](http://mlmmj.org/) mailing lists.
- Audit log of changes
- Notify admins about errors via Rocket:Chat bot implementation
---
## IMPORTANT
In case of login issues: Please be aware that the password input field gets sanitized using the filter [FILTER_SANITIZE_FULL_SPECIAL_CHARS](https://www.php.net/manual/en/filter.filters.sanitize.php)
---
## Installation
Clone the git repository to your webserver:
@@ -69,7 +78,9 @@ Check if the values from `init.php` are still valid or need to be adapted.
## Changelog
v1.0 - Initial release (08/13/2021)
[v1.2](https://git.ecogood.org/services/mlmmj-light-web-ecg/releases/tag/v1.2) - Version 1.2 (2022-02-01)
[v1.1](https://git.ecogood.org/services/mlmmj-light-web-ecg/releases/tag/v1.1) - Version 1.1 (2021-11-25)
[v1.0](https://git.ecogood.org/services/mlmmj-light-web-ecg/releases/tag/v1.0) - Initial release (2021-08-13)
## Roadmap

View File

@@ -28,7 +28,7 @@ if ( strlen($list_name) > 30 )
}
// Test list existence
if( !is_dir("$lists_path/$domain/$list_name") )
if( !is_dir("$lists_path/$domain/$list_name") || $list_name == "" )
{
header("Location: error.php");
exit();

View File

@@ -1,5 +1,8 @@
<?php
# Scan loading time
$time_start = microtime(true);
require("init.php");
if (!isset($_SESSION["auth"]) || $_SESSION["auth"] != 1)
@@ -27,16 +30,40 @@ if (isset($lists))
}
$lists_new = [];
# Iterate through all lists
foreach($lists as $list)
{
# If list is in array of owned lists
if (!in_array($list, $_SESSION["array_lists_owned"]))
{
$lists_new[$list] = 0;
$lists_new[$list]["iamowner"] = 0;
}
else
{
$lists_new[$list] = 1;
$lists_new[$list]["iamowner"] = 1;
}
# Get the owners of the list and put them into the array
$owners = explode("\n", trim(shell_exec("/usr/bin/mlmmj-list -o -L $lists_path/$domain/$list")));
$lists_new[$list]["owners"] = $owners;
# Check whether there is a listdescription file
if (file_exists("$lists_path/$domain/$list/control/listdescription") && @file_get_contents("$lists_path/$domain/$list/control/listdescription") != "")
{
// Get list description
$listdescription = file_get_contents("$lists_path/$domain/$list/control/listdescription");
// Remove trailing empty symbols
$listdescription = trim($listdescription);
}
else
{
# Set listdescription to none
$listdescription = "none";
}
# Add the listdescription to the array
$lists_new[$list]["description"] = $listdescription;
}
}
else
@@ -44,11 +71,18 @@ else
$lists = NULL;
}
# Scan loading time
$time_end = microtime(true);
# Calculate loading time
$loadingtime = round(($time_end - $time_start), 2);
$smarty->assign("headline", $headline);
$smarty->assign("web_url", $web_url);
$smarty->assign("lists", $lists_new);
$smarty->assign("domain", $domain);
$smarty->assign("username", $_SESSION["username"]);
$smarty->assign("loadingtime", $loadingtime);
$smarty->display("index.tpl");
?>

1
info.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" enable-background="new 0 0 64 64"><path d="m32 2c-16.568 0-30 13.432-30 30s13.432 30 30 30 30-13.432 30-30-13.432-30-30-30m5 49.75h-10v-24h10v24m-5-29.5c-2.761 0-5-2.238-5-5s2.239-5 5-5c2.762 0 5 2.238 5 5s-2.238 5-5 5" fill="#dddddd"/></svg>

After

Width:  |  Height:  |  Size: 303 B

View File

@@ -22,7 +22,7 @@ $domain_global = "mlmmj";
$rc_webhook = "";
# No need to change this values
$current_version = "v1.1";
$current_version = "v1.2";
$headline = "Manage your ECG mailing lists " . $current_version;
$debug = false;

View File

@@ -81,7 +81,7 @@
<div id="column_middle">
<div id="column_middle_inner">
<div id="table_div">
<table id="table_middle">
<table id="table_middle" class="table_middle">
<tr>
<td>
<div id="prefix_header">
@@ -94,14 +94,16 @@
&nbsp;Prefix:
</div>
</td>
</tr>
<tr>
<td>
<input type="text" name="prefix" value="{$prefix|escape:'htmlall'}" id="prefix">
</td>
</tr>
</table>
<table style="width: 100%; text-align: center; margin-top: 50px; padding: 0 25px 0 25px;">
<table class="table_middle">
<tr>
<td colspan="2">
<td >
<div id="listdescription_header">
<div class="tooltip">
<img src="help.svg" width=15 height=15>
@@ -111,6 +113,10 @@
</div>
&nbsp;List description:
</div>
</td>
</tr>
<tr>
<td>
<textarea name="listdescription" id="listdescription" style="height: 100%; width: 100%;">{$listdescription|escape:'htmlall'}</textarea>
</td>
</tr>

View File

@@ -58,13 +58,19 @@
</tr>
{foreach $lists as $list}
{if $list == 1}
{if $list.iamowner == 1}
<tr>
<td>
&check;
</td>
<td>
<a href="edit_list.php?list_name={$list@key}">{$list@key}</a>
<div class="tooltip">
<img src="info.svg" width=15 height=15>
<span class="help_add_list">
<strong>Description</strong><br />{$list.description}<br /><br /><strong>List owner(s)</strong><br />{foreach $list.owners as $owner}{$owner}<br />{/foreach}
</span>
</div>
</td>
</tr>
{/if}
@@ -94,18 +100,26 @@
</tr>
{foreach $lists as $list}
{if $list == 0}
{if $list.iamowner == 0}
<tr>
<td>
&cross;
</td>
<td>
{$list@key}
<div class="tooltip">
<img src="info.svg" width=15 height=15>
<span class="help_add_list">
<strong>Description</strong><br />{$list.description}<br /><br /><strong>List owner(s)</strong><br />{foreach $list.owners as $owner}{$owner}<br />{/foreach}
</span>
</div>
</td>
</tr>
{/if}
{/foreach}
</table>
<br />
<span>Loading time: {$loadingtime} seconds</span>
</div>
</body>
</html>

View File

@@ -35,7 +35,8 @@
</div>
<div id="login">
<div id="login_form">
<p>Please enter the credentials of your ECG account<br />(<strong>without</strong> @ecogood.org)</p>
<p>Please enter the credentials of your ECG account<br />(<strong>without</strong> <i>@ecogood.org</I>)</p>
<br />
<form method="post" action="login.php" onsubmit="return validate_form()">
<div id="username">
<div id="username_left">
@@ -53,10 +54,12 @@
<input type="password" name="login_pass" id="password_input">
</div>
</div>
<a href="https://wiki.ecogood.org/display/PUBLIC/IT-Support" target="_blank"><p>Forgot your password?</p></a>
<div id="enter">
<input type="submit" name="submit" value="Login">
</div>
<br />
<br />
<a href=" https://wiki.ecogood.org/x/DYQjB " target="_blank"><p>Forgot your password?</p></a>
</form>
</div>
</div>

View File

@@ -19,6 +19,7 @@ function trim_array($arr)
$list_name = isset( $_POST["list_name"] ) ? $_POST["list_name"] : NULL;
$prefix = isset ( $_POST["prefix"] ) ? $_POST["prefix"] : NULL;
$listdescription = isset ( $_POST["listdescription"] ) ? $_POST["listdescription"] : NULL;
$new_subscribers = isset ( $_POST["subscribers"] ) ? $_POST["subscribers"] : NULL;
$moderators = isset ( $_POST["moderators"] ) ? $_POST["moderators"] : NULL;
@@ -46,7 +47,7 @@ if ( strlen($list_name) > 30 )
}
// Test list existence
if( !is_dir("$lists_path/$domain/$list_name") )
if( !is_dir("$lists_path/$domain/$list_name") || $list_name == "" )
{
header("Location: error.php");
exit();
@@ -158,11 +159,18 @@ if ($moderators !== NULL)
}
}
# Add prefix to the respective file
if ($prefix !== NULL)
{
file_put_contents("$lists_path/$domain/$list_name/control/prefix", "$prefix");
}
# Add listdescription to the respective file
if ($listdescription !== NULL)
{
file_put_contents("$lists_path/$domain/$list_name/control/listdescription", "$listdescription");
}
# The following code section is for audit log only
# -------------------------------------------------------------

237
style.css
View File

@@ -1,5 +1,4 @@
body
{
body {
margin: 0;
padding: 0;
font-family: sans-serif;
@@ -7,14 +6,12 @@ body
height: 100%;
}
form
{
form {
margin: 0;
padding: 0;
}
a
{
a {
margin-top: 0;
margin-bottom: 0;
cursor: pointer;
@@ -22,18 +19,15 @@ a
text-decoration: none;
}
a:hover
{
a:hover {
color: #66ccff;
}
td
{
td {
padding-right: 8px;
}
#header
{
#header {
font-size: 30px;
background-color: #222222;
color: #9d9d9d;
@@ -48,48 +42,40 @@ td
justify-content: space-between;
}
#error
{
#error {
padding-top: 15px;
padding-left: 30px;
}
#header_left
{
#header_left {
float: left;
}
#header_left a
{
#header_left a {
color: #9d9d9d;
}
#header_left a:hover
{
#header_left a:hover {
color: #66ccff;
}
#header_right
{
#header_right {
display: flex;
align-items: center;
font-size: 20px;
}
#header_right a
{
#header_right a {
color: #9d9d9d;
}
#header_right a:hover
{
#header_right a:hover {
color: #66ccff;
}
#login
{
#login {
width: 100%;
position: absolute;
top: 60px;
@@ -97,45 +83,45 @@ td
display: flex;
}
#login_form
{
width: 250px;
#login_form {
width: 400px;
padding: 10px;
margin: auto;
align-self: center;
}
#login_form > form {
width: 300px;
}
#username, #password
{
#username, #password {
width: 100%;
padding-bottom: 5px;
display: flex;
}
#username_left, #password_left
{
#username_left, #password_left {
align-self: center;
}
#username_right, #password_right
{
#username_right, #password_right {
margin-left: auto;
}
#username_input, #password_input
{
#username_input, #password_input {
width: 170px;
}
#enter
{
padding-top: 5px;
#enter {
width: 100%;
padding-top: 5px;
display: inline-block;
margin-left: 80px;
# margin-left: 80px;
}
#enter > input {
width: 100%;
}
#breadcrumbs
{
#breadcrumbs {
height: 40px;
background-color: #f5f5f5;
margin-top: 20px;
@@ -147,43 +133,36 @@ td
align-items: center;
}
#index
{
#index {
margin-left: 30px;
}
#lists_header
{
#lists_header {
margin-bottom: 10px;
display: flex;
align-items: center;
}
#lists
{
#lists {
padding-left: 17px;
margin-bottom: 5px;
}
#add_list
{
#add_list {
display: flex;
padding-left: 20px;
}
#add_list_input
{
#add_list_input {
width: 170px;
}
.tooltip
{
.tooltip {
position: relative;
display: inline-block;
}
.tooltip .help_add_list
{
.tooltip .help_add_list {
visibility: hidden;
width: 450px;
background-color: #111;
@@ -197,8 +176,7 @@ td
left: 170%;
}
.tooltip .help_add_list::after
{
.tooltip .help_add_list::after {
content: "";
position: absolute;
top: 5px;
@@ -209,142 +187,131 @@ td
border-color: transparent #111 transparent transparent;
}
.tooltip:hover .help_add_list
{
.tooltip:hover .help_add_list {
visibility: visible;
}
#edit_page
{
#edit_page {
display: table;
width: 100%;
height: 100%;
}
.success
{
.success {
font-weight: bold;
color: #00aa00;
text-align: center;
}
#save_list
{
#save_list {
background-color: #f5f5f5;
margin-top: 20px;
margin-bottom: 20px;
margin-left: 30px;
margin-right: 30px;
height: calc(100% - 170px);
height: calc(100% - 280px);
min-height: 400px;
width: calc(100% - 60px);
}
#column_left
{
#column_left {
height: 100%;
display: table-cell;
min-width: 300px;
}
#subscribers_header
{
#subscribers_header {
height: 30px;
width: 300px;
width: 350px;
display: flex;
align-items: center;
justify-content: center;
margin-left: auto;
}
#subscribers_body
{
height: calc(100% - 100px);
width: 300px;
#subscribers_body {
height: calc(100% - 50px);
width: 350px;
margin-left: auto;
}
#subscribers
{
#subscribers {
height: 100%;
width: 100%;
}
#column_right
{
#column_right {
height: 100%;
display: table-cell;
min-width: 320px;
}
#moderators_header
{
#moderators_header {
height: 30px;
width: 300px;
width: 350px;
display: flex;
align-items: center;
justify-content: center;
}
#moderators_body
{
height: calc(100% - 100px);
width: 300px;
#moderators_body {
height: calc(100% - 50px);
width: 350px;
}
#moderators
{
#moderators {
height: 100%;
width: 100%;
}
#column_middle
{
#column_middle {
padding-top: 30px;
width: 500px;
height: 100%;
display: table-cell;
min-width: 440px;
vertical-align: top;
padding-bottom: 20px;
}
#column_middle_inner
{
#column_middle_inner {
height: 100%;
display: flex;
justify-content: space-between;
flex-direction: column;
}
#table_middle
{
text-align: right;
margin: auto;
.table_middle {
width: 100%;
# text-align: center;
margin-bottom: 30px;
padding: 0 25px 0 25px;
}
#table_middle td
{
#table_middle td {
padding-bottom: 10px;
}
#prefix, #list_type
{
#prefix, #list_type {
width: 100%;
}
#footer
{
#footer {
width: 100%;
height: 100px;
}
#save_btn
{
#save_btn {
text-align: center;
width: 100%;
height: 30px;
}
#save_btn > input {
text-align: center;
height: 30px;
width: 50%;
}
.tooltip .help_sub, .tooltip .help_mod
{
.tooltip .help_sub, .tooltip .help_mod {
visibility: hidden;
width: 250px;
background-color: #111;
@@ -359,8 +326,7 @@ td
margin-left: -133px;
}
.tooltip .help_sub::after, .tooltip .help_mod::after
{
.tooltip .help_sub::after, .tooltip .help_mod::after {
content: "";
position: absolute;
bottom: 100%;
@@ -371,13 +337,11 @@ td
border-color: transparent transparent #111 transparent;
}
.tooltip:hover .help_sub, .tooltip:hover .help_mod
{
.tooltip:hover .help_sub, .tooltip:hover .help_mod {
visibility: visible;
}
.tooltip .help_list_type
{
.tooltip .help_list_type {
visibility: hidden;
width: 300px;
background-color: #111;
@@ -391,8 +355,7 @@ td
right: 170%;
}
.tooltip .help_list_type::after
{
.tooltip .help_list_type::after {
content: "";
position: absolute;
top: 5px;
@@ -403,19 +366,16 @@ td
border-color: transparent transparent transparent #111;
}
.tooltip:hover .help_list_type
{
.tooltip:hover .help_list_type {
visibility: visible;
}
#list_type_header, #prefix_header, #footer_header, #notmetoo_header
{
#list_type_header, #prefix_header, #footer_header, #notmetoo_header, #listdescription_header {
display: flex;
align-items: center;
}
.tooltip .help_prefix
{
.tooltip .help_prefix {
visibility: hidden;
width: 200px;
background-color: #111;
@@ -429,8 +389,7 @@ td
right: 160%;
}
.tooltip .help_prefix::after
{
.tooltip .help_prefix::after {
content: "";
position: absolute;
top: 50%;
@@ -441,13 +400,11 @@ td
border-color: transparent transparent transparent #111;
}
.tooltip:hover .help_prefix
{
.tooltip:hover .help_prefix {
visibility: visible;
}
.tooltip .help_footer
{
.tooltip .help_footer {
visibility: hidden;
width: 200px;
background-color: #111;
@@ -461,8 +418,7 @@ td
right: 160%;
}
.tooltip .help_footer::after
{
.tooltip .help_footer::after {
content: "";
position: absolute;
top: 50%;
@@ -473,19 +429,16 @@ td
border-color: transparent transparent transparent #111;
}
.tooltip:hover .help_footer
{
.tooltip:hover .help_footer {
visibility: visible;
}
#notmetoo_checkbox
{
#notmetoo_checkbox {
margin-left: 5px;
margin-right: 5px;
}
.tooltip .help_notmetoo
{
.tooltip .help_notmetoo {
visibility: hidden;
width: 300px;
background-color: #111;
@@ -499,8 +452,7 @@ td
right: 160%;
}
.tooltip .help_notmetoo::after
{
.tooltip .help_notmetoo::after {
content: "";
position: absolute;
top: 50%;
@@ -511,7 +463,6 @@ td
border-color: transparent transparent transparent #111;
}
.tooltip:hover .help_notmetoo
{
.tooltip:hover .help_notmetoo {
visibility: visible;
}