├── interface
└── lib
│ ├── plugins
│ ├── nextcloud_plugin
│ │ ├── VERSION
│ │ ├── screenshots
│ │ │ ├── ispconfig-01.png
│ │ │ ├── ispconfig-02.png
│ │ │ └── ispconfig-03.png
│ │ ├── sql
│ │ │ ├── mail_domain.sql
│ │ │ └── mail_user.sql
│ │ ├── templates
│ │ │ ├── mail_domain_edit.htm
│ │ │ ├── mail_user_edit.htm
│ │ │ └── server_config_edit.htm
│ │ └── lib
│ │ │ └── lang
│ │ │ └── en.lng
│ └── nextcloud_plugin.inc.php
│ └── classes
│ └── validate_nextcloud.inc.php
├── CHANGELOG.md
├── LICENSE
├── README.md
└── server
└── plugins-available
└── nextcloud_plugin.inc.php
/interface/lib/plugins/nextcloud_plugin/VERSION:
--------------------------------------------------------------------------------
1 | 29.0.1
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [Unreleased]
2 |
3 | ## 29.0.1
4 |
5 | - Implement enable/disable login by server
6 |
7 | ## 29.0.0
8 |
9 | - Initial release
10 |
--------------------------------------------------------------------------------
/interface/lib/plugins/nextcloud_plugin/screenshots/ispconfig-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mediabox-cl/ispconfig-nextcloud-plugin/HEAD/interface/lib/plugins/nextcloud_plugin/screenshots/ispconfig-01.png
--------------------------------------------------------------------------------
/interface/lib/plugins/nextcloud_plugin/screenshots/ispconfig-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mediabox-cl/ispconfig-nextcloud-plugin/HEAD/interface/lib/plugins/nextcloud_plugin/screenshots/ispconfig-02.png
--------------------------------------------------------------------------------
/interface/lib/plugins/nextcloud_plugin/screenshots/ispconfig-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mediabox-cl/ispconfig-nextcloud-plugin/HEAD/interface/lib/plugins/nextcloud_plugin/screenshots/ispconfig-03.png
--------------------------------------------------------------------------------
/interface/lib/plugins/nextcloud_plugin/sql/mail_domain.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE mail_domain
2 | ADD COLUMN IF NOT EXISTS nc_enabled enum ('n','y') NOT NULL DEFAULT 'n',
3 | ADD COLUMN IF NOT EXISTS nc_quota varchar(255) NOT NULL DEFAULT '0',
4 | ADD COLUMN IF NOT EXISTS nc_group varchar(255) NOT NULL DEFAULT '';
--------------------------------------------------------------------------------
/interface/lib/plugins/nextcloud_plugin/sql/mail_user.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE mail_user
2 | ADD COLUMN IF NOT EXISTS nc_enabled enum ('n','y') NOT NULL DEFAULT 'y',
3 | ADD COLUMN IF NOT EXISTS nc_quota varchar(255) NOT NULL DEFAULT '',
4 | ADD COLUMN IF NOT EXISTS nc_group varchar(255) NOT NULL DEFAULT '',
5 | ADD COLUMN IF NOT EXISTS nc_adm_user enum ('n','y') NOT NULL DEFAULT 'n',
6 | ADD COLUMN IF NOT EXISTS nc_server enum ('n','y') NOT NULL DEFAULT 'y',
7 | ADD COLUMN IF NOT EXISTS nc_adm_server enum ('n','y') NOT NULL DEFAULT 'n',
8 | ADD COLUMN IF NOT EXISTS nc_domain enum ('n','y') NOT NULL DEFAULT 'y',
9 | ADD COLUMN IF NOT EXISTS nc_adm_domain enum ('n','y') NOT NULL DEFAULT 'n';
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 2-Clause License
2 |
3 | Copyright (c) 2024, Michael Epstein, Mediabox EIRL
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | 2. Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 |
--------------------------------------------------------------------------------
/interface/lib/classes/validate_nextcloud.inc.php:
--------------------------------------------------------------------------------
1 | tform->lng($errmsg) . $text . ' ';
42 | }
43 |
44 | /**
45 | * Check url
46 | *
47 | * @param $field_name
48 | * @param $field_value
49 | * @param $validator
50 | *
51 | * @return false|string
52 | */
53 | function check_url($field_name, $field_value, $validator)
54 | {
55 | if ($field_value !== '') {
56 | if (filter_var($field_value, FILTER_VALIDATE_URL) === false) {
57 | return $this->get_error($validator['errmsg'], $field_value);
58 | }
59 | }
60 |
61 | return false;
62 | }
63 | }
--------------------------------------------------------------------------------
/interface/lib/plugins/nextcloud_plugin/templates/mail_domain_edit.htm:
--------------------------------------------------------------------------------
1 |
9 |
10 |
25 |
26 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
69 |
70 |
71 |
72 |
73 |
74 |
76 | {tmpl_var name='btn_save_txt'}
77 |
78 |
80 | {tmpl_var name='btn_cancel_txt'}
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/interface/lib/plugins/nextcloud_plugin/lib/lang/en.lng:
--------------------------------------------------------------------------------
1 | 1';
55 | $wb['nc_group_domain_txt'] = 'Domain Group';
56 | $wb['nc_group_domain_desc_txt'] = 'Domain group for users with mailboxes in this domain. If leave empty, no group will be created.';
57 | $wb['nc_quota_user_txt'] = 'User Quota';
58 | $wb['nc_quota_user_desc_txt'] = 'Leave empty to use the default domain quota.';
59 | $wb['nc_quota_user_error_regex'] = 'Invalid quota value. Allowed values are: Empty to use the domain quota, 0 for none or numbers > 1';
60 | $wb['nc_group_user_txt'] = 'User Group';
61 | $wb['nc_group_user_desc_txt'] = 'Specific user group. If leave empty, no group will be created.';
62 | $wb['nc_group_adm_user_txt'] = 'User Group Admin';
63 | $wb['nc_group_adm_user_desc_txt'] = 'Makes the user an admin of their own user group.';
64 | $wb['nc_group_adm_server_txt'] = 'Server Group Admin';
65 | $wb['nc_group_adm_server_desc_txt'] = 'Makes the user an admin of their own server group';
66 | $wb['nc_group_adm_domain_txt'] = 'Domain Group Admin';
67 | $wb['nc_group_adm_domain_desc_txt'] = 'Makes the user an admin of their own domain group';
68 | $wb['nc_group_user_server_desc_txt'] = 'Add this user to the Server group.';
69 | $wb['nc_group_user_domain_desc_txt'] = 'Add this user to the Domain group.';
70 |
--------------------------------------------------------------------------------
/interface/lib/plugins/nextcloud_plugin/templates/mail_user_edit.htm:
--------------------------------------------------------------------------------
1 |
9 |
10 |
25 |
26 |
38 |
39 |
50 |
51 |
62 |
63 |
74 |
75 |
86 |
87 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
106 |
107 |
108 |
109 |
110 |
111 |
113 | {tmpl_var name='btn_save_txt'}
114 |
115 |
117 | {tmpl_var name='btn_cancel_txt'}
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/interface/lib/plugins/nextcloud_plugin/templates/server_config_edit.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 | {tmpl_var name='server_name'}
4 |
5 |
6 |
7 |
15 |
16 |
27 |
28 |
38 |
39 |
49 |
50 |
62 |
63 |
75 |
76 |
87 |
88 |
102 |
103 |
117 |
118 |
119 |
120 |
121 |
122 |
124 | {tmpl_var name='btn_save_txt'}
125 |
126 |
128 | {tmpl_var name='btn_cancel_txt'}
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ISPConfig - Nextcloud Plugin
2 |
3 | Allows users to log in to **Nextcloud** with their email or custom login name created in the **ISPConfig 3** Control Panel.
4 |
5 | **IMPORTANT:** This plugin requires the installation of an APP in **Nextcloud**. [Nextcloud - User ISPConfig API](https://github.com/mediabox-cl/nextcloud-user-ispconfig-api.git)
6 |
7 | ## Features
8 |
9 | This plugin has three places where you can configure different functionalities or integrations with **Nextcloud**.
10 |
11 | - `System > Server Config > Your Server Name > Nextcloud (TAB)`
12 | - `Email > Domain > Your Domain Name > Nextcloud (TAB)`
13 | - `Email > Email Mailbox > Your Mailbox Name > Nextcloud (TAB)`
14 |
15 | ### Users
16 |
17 | - Users can change their **ISPConfig** password and display name in the **Nextcloud** interface.
18 | - Delete the **Nextcloud** user account and data when the **ISPConfig** Mailbox User or Domain is deleted.
19 | - Enable/Disable login by user or domain.
20 | - You can define the user quota per domain or per user.
21 | - ...
22 |
23 | ### Groups
24 |
25 | Groups have 3 places where you can set them; Server, Domain and User.
26 | - The Server Group is like a Global Group for all the mail users in this server.
27 | - The Domain Group is a Group for all the Users ho belong to each domain.
28 | - The User Group are specific for each user.
29 | - Add or remove users to the group defined in Server, Domain and User.
30 | - Add or remove users as admin of the groups they belong to.
31 | - Delete empty group.
32 | - ...
33 |
34 | ## Installation
35 |
36 | ### Manual installation
37 |
38 | Installation in **ISPConfig** is a bit tricky because this control panel, despite being very good, is not very user-friendly when it comes to creating/installing plugins.
39 |
40 | **IMPORTANT!:** The DATABASE user "ispconfig", have the `SELECT`, `INSERT`, `UPDATE` and `DELETE` privileges only, but this plugin requires the `ALTER` privilege.
41 |
42 | **Before** you install this plugin, you must log in to your **phpMyAdmin** (easier) and give the `ALTER` privilege to the "ispconfig" user in the "dbispconfig" database.
43 |
44 | _Notes:_
45 |
46 | - _After finishing the installation of the plugin you can disable the `ALTER` privilege._
47 | - _"dbispconfig" and "ispconfig" are the default database and database user for **ISPConfig**. You may have another one if you changed it during installation._
48 |
49 | Login to your server and clone this repository:
50 |
51 | ```bash
52 | cd /tmp
53 | git clone https://github.com/mediabox-cl/ispconfig-nextcloud-plugin.git
54 | cd ispconfig-nextcloud-plugin
55 | cp -R interface /usr/local/ispconfig
56 | cp -R server /usr/local/ispconfig
57 | chown -R ispconfig:ispconfig /usr/local/ispconfig/interface/lib
58 | cd /usr/local/ispconfig/server/plugins-enabled
59 | ln -s /usr/local/ispconfig/server/plugins-available/nextcloud_plugin.inc.php nextcloud_plugin.inc.php
60 | rm -rf /tmp/ispconfig-nextcloud-plugin
61 | ```
62 |
63 | Logout from your **ISPConfig 3** Control Panel and login again. **You must do this!**
64 | Now you can navigate to the **Nextcloud** tabs in the Server, Domain and Mailbox and make your configurations.
65 |
66 | ## Update
67 |
68 | ### Manual Update
69 |
70 | **Before** update, you must log in to your **phpMyAdmin** (easier) and give the `ALTER` privilege to the "ispconfig" user in the "dbispconfig" database.
71 |
72 | _Notes:_
73 |
74 | - _After finishing the update you can disable the `ALTER` privilege._
75 | - _"dbispconfig" and "ispconfig" are the default database and database user for **ISPConfig**. You may have another one if you changed it during installation._
76 |
77 | Login to your server and clone this repository:
78 |
79 | ```bash
80 | cd /tmp
81 | git clone https://github.com/mediabox-cl/ispconfig-nextcloud-plugin.git
82 | cd ispconfig-nextcloud-plugin
83 | cp -R interface /usr/local/ispconfig
84 | cp -R server /usr/local/ispconfig
85 | chown -R ispconfig:ispconfig /usr/local/ispconfig/interface/lib
86 | rm -rf /tmp/ispconfig-nextcloud-plugin
87 | ```
88 |
89 | Logout from your ISPConfig 3 Control Panel and login again. You must do this!
90 |
91 | ## Configuration
92 |
93 | ### Nextcloud API
94 |
95 | This plugin uses the **Nextcloud API** to delete users on **Nextcloud** who were deleted in **ISPConfig**.
96 |
97 | - Login to your **Nextcloud** installation with your admin account.
98 | - Navigate to `Personal settings > Security (Devices & sessions)` and create a new `APP Password`.
99 | - Input the APP name, for example: `ispconfig` and hit the `Create new app password` button.
100 | - Copy and paste the supplied credentials in `ISPConfig > Server > Nextcloud (TAB)`.
101 |
102 | Now, whenever you delete a user or domain in **ISPConfig**, this user or domain users will be deleted in **Nextcloud** (if enabled).
103 |
104 | ### What's next?
105 |
106 | Please, follow the instruction here to install the [Nextcloud - User ISPConfig API](https://github.com/mediabox-cl/nextcloud-user-ispconfig-api.git) APP.
107 |
108 | ## Thanks to:
109 |
110 | - Till Brehm from Projektfarm GmbH.
111 | - Falko Timme from Timme Hosting.
112 | - The ISPConfig community and developers.
113 | - The Nextcloud community and developers.
114 |
--------------------------------------------------------------------------------
/server/plugins-available/nextcloud_plugin.inc.php:
--------------------------------------------------------------------------------
1 | [
43 | 'method' => 'GET',
44 | 'path' => 'ocs/v1.php/cloud/users/{uid}',
45 | 'header' => ['OCS-APIRequest: true'],
46 | 'success' => 100,
47 | ],
48 | 'delete' => [
49 | 'method' => 'DELETE',
50 | 'path' => 'ocs/v1.php/cloud/users/{uid}',
51 | 'header' => ['OCS-APIRequest: true'],
52 | 'success' => 100,
53 | ]
54 | ];
55 |
56 | // Plugin
57 | public string $plugin_name = 'nextcloud_plugin';
58 | public string $class_name = 'nextcloud_plugin';
59 |
60 | // Private variables
61 | public string $action = '';
62 |
63 | // Nextcloud
64 | private ?bool $nc_enabled = null;
65 | private string $nc_url;
66 | private string $nc_path;
67 | private string $nc_user;
68 | private string $nc_password;
69 |
70 | /**
71 | * This function is called during ISPConfig installation to determine
72 | * if a symlink shall be created for this plugin.
73 | */
74 | function onInstall(): bool
75 | {
76 | global $conf;
77 |
78 | return (bool) $conf['services']['mail'];
79 | }
80 |
81 | /**
82 | * This function is called when the plugin is loaded
83 | */
84 | public function onLoad(): void
85 | {
86 | global $app;
87 |
88 | // Register for the events
89 |
90 | // Mailboxes
91 | $app->plugins->registerEvent('mail_user_delete', $this->plugin_name, 'mail_user_delete');
92 |
93 | // Mail Domains
94 | $app->plugins->registerEvent('mail_domain_delete', $this->plugin_name, 'mail_domain_delete');
95 | }
96 |
97 | /**
98 | * Mail user delete event
99 | *
100 | * @param $event_name
101 | * @param $data
102 | *
103 | * @return void
104 | */
105 | public function mail_user_delete($event_name, $data): void
106 | {
107 | $this->loadConf();
108 |
109 | if ($this->nc_enabled) {
110 | $this->user_delete($data['old']['email']);
111 | }
112 | }
113 |
114 | /**
115 | * Mail domain delete event
116 | *
117 | * @param $event_name
118 | * @param $data
119 | *
120 | * @return void
121 | */
122 | public function mail_domain_delete($event_name, $data): void
123 | {
124 | global $app;
125 |
126 | $this->loadConf();
127 |
128 | if ($this->nc_enabled) {
129 | $mail_users = $app->db->queryAllRecords("SELECT email FROM mail_user WHERE email like ?", '%@' . $data['old']['domain']);
130 |
131 | if (is_array($mail_users)) {
132 | foreach ($mail_users as $user) {
133 | $this->user_delete($user['email']);
134 | }
135 | }
136 | }
137 | }
138 |
139 | /**
140 | * Delete user
141 | *
142 | * @param string $email
143 | *
144 | * @return void
145 | */
146 | private function user_delete(string $email): void
147 | {
148 | global $app;
149 |
150 | $uid = $this->getUid($email);
151 |
152 | $this->nc_path = str_replace('{uid}', $uid, self::PATHS['delete']['path']);
153 | $data = $this->call(self::PATHS['delete']['method'], self::PATHS['delete']['header']);
154 |
155 | if (!$data['error'] && $data['response']) {
156 | $status = $this->getStatus($data['response']);
157 |
158 | if ($status === self::PATHS['delete']['success']) {
159 | $app->log("Deleted the Nextcloud account for User: $uid", LOGLEVEL_WARN);
160 | } else {
161 | $app->log("Can't deleted the Nextcloud account for User: $uid - Status code: $status", LOGLEVEL_ERROR);
162 | }
163 | } else {
164 | $app->log("Can't deleted the Nextcloud account for User: $uid - Error: " . $data['description'], LOGLEVEL_ERROR);
165 | }
166 | }
167 |
168 | /**
169 | * Get status code from xml response
170 | *
171 | * @param string $xml
172 | *
173 | * @return int
174 | */
175 | private function getStatus(string $xml): int
176 | {
177 | if (preg_match('/(\d+)<\/statuscode>/', $xml, $matches)) {
178 | return (int) $matches[1];
179 | }
180 |
181 | return 0;
182 | }
183 |
184 | /**
185 | * Compute UID from email
186 | *
187 | * @param string $email
188 | *
189 | * @return string
190 | */
191 | private function getUid(string $email): string
192 | {
193 | $parts = explode('@', mb_strtolower(trim($email)));
194 | $mailDomain = array_pop($parts);
195 | $mailUser = implode('@', $parts);
196 |
197 | $uid = "$mailUser.$mailDomain";
198 |
199 | if (mb_strlen($uid) > self::MAX_UID_LENGTH) {
200 | $uid = hash('sha256', $uid);
201 | }
202 |
203 | return $uid;
204 | }
205 |
206 | /**
207 | * Curl call
208 | *
209 | * @param string $method
210 | * @param array $headers
211 | *
212 | * @return array
213 | */
214 | private function call(string $method, array $headers): array
215 | {
216 | $url = rtrim($this->nc_url, '/') . '/' . $this->nc_path;
217 | $ch = curl_init($url);
218 |
219 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
220 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
221 | curl_setopt($ch, CURLINFO_HEADER_OUT, true);
222 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
223 | curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
224 | curl_setopt($ch, CURLOPT_TIMEOUT, 30);
225 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
226 | curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
227 | curl_setopt($ch, CURLOPT_USERPWD, $this->nc_user . ':' . $this->nc_password);
228 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
229 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
230 |
231 | $response = curl_exec($ch);
232 | $error = curl_errno($ch);
233 | $http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
234 |
235 | curl_close($ch);
236 |
237 | return [
238 | 'http' => $http,
239 | 'error' => $error,
240 | 'description' => ($error ? curl_strerror($error) : ''),
241 | 'response' => $response
242 | ];
243 | }
244 |
245 | /**
246 | * Load config
247 | *
248 | * @return void
249 | */
250 | private function loadConf(): void
251 | {
252 | global $app, $conf;
253 |
254 | if ($this->nc_enabled === null) {
255 | // load the server specific configuration options for nextcloud
256 | $app->uses('getconf');
257 | $nc_config = $app->getconf->get_server_config($conf['server_id'], 'nextcloud');
258 | $this->nc_enabled = is_array($nc_config) && isset($nc_config['nc_enabled']) && $nc_config['nc_enabled'] == 'y';
259 |
260 | if (
261 | $this->nc_enabled &&
262 | isset($nc_config['nc_account']) &&
263 | $nc_config['nc_account'] == 'y' &&
264 | isset($nc_config['nc_url']) &&
265 | $nc_config['nc_url'] &&
266 | isset($nc_config['nc_user']) &&
267 | $nc_config['nc_user'] &&
268 | isset($nc_config['nc_password']) &&
269 | $nc_config['nc_password']
270 | ) {
271 | $this->nc_url = $nc_config['nc_url'];
272 | $this->nc_user = $nc_config['nc_user'];
273 | $this->nc_password = $nc_config['nc_password'];
274 | } else {
275 | $this->nc_enabled = false;
276 | }
277 | }
278 | }
279 | }
--------------------------------------------------------------------------------
/interface/lib/plugins/nextcloud_plugin.inc.php:
--------------------------------------------------------------------------------
1 | [
40 | 'nc_enabled',
41 | 'nc_quota',
42 | 'nc_group'
43 | ],
44 | 'mail_user' => [
45 | 'nc_enabled',
46 | 'nc_quota',
47 | 'nc_group',
48 | 'nc_adm_user',
49 | 'nc_server',
50 | 'nc_adm_server',
51 | 'nc_domain',
52 | 'nc_adm_domain'
53 | ]
54 | ];
55 |
56 | public function __construct()
57 | {
58 | $this->plugin_dir = ISPC_ROOT_PATH . '/lib/plugins/' . $this->plugin_name;
59 | }
60 |
61 | /**
62 | * This function is called when the plugin is loaded
63 | *
64 | * @return void
65 | */
66 | public function onLoad(): void
67 | {
68 | global $app;
69 |
70 | // Check if needed tables/columns exist
71 | $this->checkTables();
72 |
73 | // Register for the events
74 |
75 | // We need this in the Domain tab to restore missing vars needed by ISPConfig,
76 | // also we set the "active" var to an empty string in order to bypass the dkim
77 | // check part.
78 | $app->plugin->registerEvent('mail:mail_domain:on_before_insert', $this->plugin_name, 'mail_domain_edit');
79 | $app->plugin->registerEvent('mail:mail_domain:on_before_update', $this->plugin_name, 'mail_domain_edit');
80 |
81 | // Server - Insert tabs || fields (Remote)
82 | $app->plugin->registerEvent('admin:server_config:on_after_formdef', $this->plugin_name, 'server_config_form');
83 | $app->plugin->registerEvent('admin:server_config:on_remote_after_formdef', $this->plugin_name, 'server_config_form');
84 |
85 | // Domain - Insert tabs || fields (Remote)
86 | $app->plugin->registerEvent('mail:mail_domain:on_after_formdef', $this->plugin_name, 'mail_domain_form');
87 | $app->plugin->registerEvent('mail:mail_domain:on_remote_after_formdef', $this->plugin_name, 'mail_domain_form');
88 |
89 | // Mailbox - Insert tabs || fields (Remote)
90 | $app->plugin->registerEvent('mail:mail_user:on_after_formdef', $this->plugin_name, 'mail_user_form');
91 | $app->plugin->registerEvent('mail:mail_user:on_remote_after_formdef', $this->plugin_name, 'mail_user_form');
92 | }
93 |
94 | private function checkTables(): void
95 | {
96 | global $app;
97 |
98 | foreach ($this->nc_tables as $table => $columns) {
99 | // Check if table exist
100 | $list = "'" . implode("','", $columns) . "'";
101 | $sql = "SHOW COLUMNS FROM $table WHERE Field IN($list)";
102 | $result = $app->db->queryAllArray($sql);
103 |
104 | if (!empty($result)) {
105 | $diff = array_diff($columns, $result);
106 | if ($diff) {
107 | $this->createColumns($table);
108 | }
109 | } else {
110 | $this->createColumns($table);
111 | }
112 | }
113 | }
114 |
115 | private function createColumns($table): void
116 | {
117 | global $app;
118 |
119 | $file = $this->plugin_dir . "/sql/$table.sql";
120 |
121 | if (is_file($file)) {
122 | $sql = preg_replace('/\s+/', ' ', file_get_contents($file));
123 | if ($sql) {
124 | $app->db->query($sql);
125 | }
126 | }
127 | }
128 |
129 | public function mail_domain_edit($event_name, $page_form): void
130 | {
131 | global $app;
132 |
133 | // INFO: This is a HACK because the mail domain part in ISPConfig
134 | // isn't prepared to use TABS :(
135 |
136 | // We need to set this because from our tab to the domain tab it
137 | // need the domain ID from $_GET and this is a POST.
138 | if (isset($page_form->dataRecord['id'])) {
139 | if (!isset($_GET['id'])) {
140 | $_GET['id'] = $page_form->dataRecord['id'];
141 | }
142 | }
143 |
144 | // Restore this vars in the form
145 | if (isset($page_form->dataRecord)) {
146 | $app->tpl->setVar(
147 | 'server_value',
148 | ($page_form->dataRecord['server_id'] ?? ''),
149 | true
150 | );
151 | $app->tpl->setVar(
152 | 'domain_value',
153 | ($page_form->dataRecord['domain'] ?? ''),
154 | true
155 | );
156 | $app->tpl->setVar(
157 | 'policy_value',
158 | ($page_form->dataRecord['policy'] ?? ''),
159 | true
160 | );
161 | $app->tpl->setVar(
162 | 'dkim_private_value',
163 | ($page_form->dataRecord['dkim_private'] ?? ''),
164 | true
165 | );
166 | $app->tpl->setVar(
167 | 'dkim_public_value',
168 | ($page_form->dataRecord['dkim_public'] ?? ''),
169 | true
170 | );
171 | $app->tpl->setVar(
172 | 'dkim_selector_value',
173 | ($page_form->dataRecord['dkim_selector'] ?? ''),
174 | true
175 | );
176 | $app->tpl->setVar(
177 | 'dns_record_value',
178 | ($page_form->dataRecord['dns_record'] ?? ''),
179 | true
180 | );
181 | }
182 | }
183 |
184 | public function server_config_form($event_name, $page_form): void
185 | {
186 | $this->loadLang($page_form);
187 |
188 | $tabs = array(
189 | 'nextcloud' => array(
190 | 'title' => 'Nextcloud',
191 | 'width' => 100,
192 | 'template' => $this->plugin_dir . '/templates/server_config_edit.htm',
193 | 'fields' => array(
194 | 'nc_enabled' => array(
195 | 'datatype' => 'VARCHAR',
196 | 'formtype' => 'CHECKBOX',
197 | 'default' => 'n',
198 | 'value' => array(
199 | 1 => 'y',
200 | 0 => 'n'
201 | )
202 | ),
203 | 'nc_account' => array(
204 | 'datatype' => 'VARCHAR',
205 | 'formtype' => 'CHECKBOX',
206 | 'default' => 'n',
207 | 'value' => array(
208 | 1 => 'y',
209 | 0 => 'n'
210 | )
211 | ),
212 | 'nc_url' => array(
213 | 'datatype' => 'VARCHAR',
214 | 'formtype' => 'TEXT',
215 | 'filters' => array(
216 | 0 => array(
217 | 'event' => 'SAVE',
218 | 'type' => 'TRIM'
219 | )
220 | ),
221 | 'validators' => array(
222 | 0 => array(
223 | 'type' => 'CUSTOM',
224 | 'class' => 'validate_nextcloud',
225 | 'function' => 'check_url',
226 | 'errmsg' => 'nc_url_error_function'
227 | )
228 | ),
229 | 'default' => '',
230 | 'value' => '',
231 | 'maxlength' => '255'
232 | ),
233 | 'nc_user' => array(
234 | 'datatype' => 'VARCHAR',
235 | 'formtype' => 'TEXT',
236 | 'filters' => array(
237 | 0 => array(
238 | 'event' => 'SAVE',
239 | 'type' => 'TRIM'
240 | )
241 | ),
242 | 'default' => '',
243 | 'value' => '',
244 | 'maxlength' => '255'
245 | ),
246 | 'nc_password' => array(
247 | 'datatype' => 'VARCHAR',
248 | 'formtype' => 'TEXT',
249 | 'default' => '',
250 | 'value' => '',
251 | 'maxlength' => '255'
252 | ),
253 | 'nc_group' => array(
254 | 'datatype' => 'VARCHAR',
255 | 'formtype' => 'TEXT',
256 | 'filters' => array(
257 | 0 => array(
258 | 'event' => 'SAVE',
259 | 'type' => 'TRIM'
260 | )
261 | ),
262 | 'default' => '',
263 | 'value' => '',
264 | 'maxlength' => '255'
265 | ),
266 | 'nc_add' => array(
267 | 'datatype' => 'VARCHAR',
268 | 'formtype' => 'CHECKBOX',
269 | 'default' => 'y',
270 | 'value' => array(
271 | 1 => 'y',
272 | 0 => 'n'
273 | )
274 | ),
275 | 'nc_remove' => array(
276 | 'datatype' => 'VARCHAR',
277 | 'formtype' => 'CHECKBOX',
278 | 'default' => 'n',
279 | 'value' => array(
280 | 1 => 'y',
281 | 0 => 'n'
282 | )
283 | ),
284 | 'nc_delete' => array(
285 | 'datatype' => 'VARCHAR',
286 | 'formtype' => 'CHECKBOX',
287 | 'default' => 'n',
288 | 'value' => array(
289 | 1 => 'y',
290 | 0 => 'n'
291 | )
292 | ),
293 | )
294 | )
295 | );
296 |
297 | $this->insert($tabs, $page_form);
298 | }
299 |
300 | public function mail_domain_form($event_name, $page_form): void
301 | {
302 | $this->loadLang($page_form);
303 |
304 | $tabs = array(
305 | 'nextcloud' => array(
306 | 'title' => 'Nextcloud',
307 | 'width' => 100,
308 | 'template' => $this->plugin_dir . '/templates/mail_domain_edit.htm',
309 | 'fields' => array(
310 | 'nc_enabled' => array(
311 | 'datatype' => 'VARCHAR',
312 | 'formtype' => 'CHECKBOX',
313 | 'default' => 'n',
314 | 'value' => array(
315 | 1 => 'y',
316 | 0 => 'n'
317 | )
318 | ),
319 | 'nc_quota' => array(
320 | 'datatype' => 'VARCHAR',
321 | 'formtype' => 'TEXT',
322 | 'validators' => array(
323 | 0 => array(
324 | 'type' => 'REGEX',
325 | 'regex' => '/^([0-9]+)$/',
326 | 'errmsg' => 'nc_quota_error_regex'
327 | ),
328 | ),
329 | 'default' => '0',
330 | 'value' => '',
331 | 'maxlength' => '255'
332 | ),
333 | 'nc_group' => array(
334 | 'datatype' => 'VARCHAR',
335 | 'formtype' => 'TEXT',
336 | 'filters' => array(
337 | 0 => array(
338 | 'event' => 'SAVE',
339 | 'type' => 'TRIM'
340 | )
341 | ),
342 | 'default' => '',
343 | 'value' => '',
344 | 'maxlength' => '255'
345 | ),
346 | )
347 | )
348 | );
349 |
350 | $this->insert($tabs, $page_form);
351 | }
352 |
353 | public function mail_user_form($event_name, $page_form): void
354 | {
355 | $this->loadLang($page_form);
356 |
357 | $tabs = array(
358 | 'nextcloud' => array(
359 | 'title' => 'Nextcloud',
360 | 'width' => 100,
361 | 'template' => $this->plugin_dir . '/templates/mail_user_edit.htm',
362 | 'fields' => array(
363 | 'nc_enabled' => array(
364 | 'datatype' => 'VARCHAR',
365 | 'formtype' => 'CHECKBOX',
366 | 'default' => 'y',
367 | 'value' => array(
368 | 1 => 'y',
369 | 0 => 'n'
370 | )
371 | ),
372 | 'nc_quota' => array(
373 | 'datatype' => 'VARCHAR',
374 | 'formtype' => 'TEXT',
375 | 'validators' => array(
376 | 0 => array(
377 | 'type' => 'REGEX',
378 | 'regex' => '/^([0-9]*)$/',
379 | 'errmsg' => 'nc_quota_user_error_regex'
380 | ),
381 | ),
382 | 'default' => '',
383 | 'value' => '',
384 | 'maxlength' => '255'
385 | ),
386 | 'nc_group' => array(
387 | 'datatype' => 'VARCHAR',
388 | 'formtype' => 'TEXT',
389 | 'filters' => array(
390 | 0 => array(
391 | 'event' => 'SAVE',
392 | 'type' => 'TRIM'
393 | )
394 | ),
395 | 'default' => '',
396 | 'value' => '',
397 | 'maxlength' => '255'
398 | ),
399 | 'nc_adm_user' => array(
400 | 'datatype' => 'VARCHAR',
401 | 'formtype' => 'CHECKBOX',
402 | 'default' => 'n',
403 | 'value' => array(
404 | 1 => 'y',
405 | 0 => 'n'
406 | )
407 | ),
408 | 'nc_server' => array(
409 | 'datatype' => 'VARCHAR',
410 | 'formtype' => 'CHECKBOX',
411 | 'default' => 'y',
412 | 'value' => array(
413 | 1 => 'y',
414 | 0 => 'n'
415 | )
416 | ),
417 | 'nc_adm_server' => array(
418 | 'datatype' => 'VARCHAR',
419 | 'formtype' => 'CHECKBOX',
420 | 'default' => 'n',
421 | 'value' => array(
422 | 1 => 'y',
423 | 0 => 'n'
424 | )
425 | ),
426 | 'nc_domain' => array(
427 | 'datatype' => 'VARCHAR',
428 | 'formtype' => 'CHECKBOX',
429 | 'default' => 'y',
430 | 'value' => array(
431 | 1 => 'y',
432 | 0 => 'n'
433 | )
434 | ),
435 | 'nc_adm_domain' => array(
436 | 'datatype' => 'VARCHAR',
437 | 'formtype' => 'CHECKBOX',
438 | 'default' => 'n',
439 | 'value' => array(
440 | 1 => 'y',
441 | 0 => 'n'
442 | )
443 | ),
444 | )
445 | )
446 | );
447 |
448 | $this->insert($tabs, $page_form);
449 | }
450 |
451 | private function loadLang($page_form): void
452 | {
453 | global $app, $conf;
454 |
455 | $language = $app->functions->check_language(
456 | $_SESSION['s']['user']['language'] ?? $conf['language']
457 | );
458 |
459 | $file = $this->plugin_dir . "/lib/lang/$language.lng";
460 |
461 | if (!is_file($file)) {
462 | $file = $this->plugin_dir . "/lib/lang/en.lng";
463 | }
464 |
465 | @include $file;
466 |
467 | if (isset($page_form->wordbook) && isset($wb) && is_array($wb)) {
468 |
469 | if (is_array($page_form->wordbook)) {
470 | $page_form->wordbook = array_merge($page_form->wordbook, $wb);
471 | } else {
472 | $page_form->wordbook = $wb;
473 | }
474 | }
475 | }
476 |
477 | private function insert($tabs, $page_form): void
478 | {
479 | if (isset($page_form->formDef['tabs'])) {
480 | $page_form->formDef['tabs'] += $tabs;
481 | } elseif (isset($page_form->formDef['fields'])) {
482 | foreach ($tabs as $tab) {
483 | foreach ($tab['fields'] as $key => $value) {
484 | $page_form->formDef['fields'][$key] = $value;
485 | }
486 | }
487 | }
488 | }
489 | }
--------------------------------------------------------------------------------