]> git.mxchange.org Git - friendica.git/blob - src/Core/ACL.php
Merge pull request #8222 from annando/ap-gnusocial
[friendica.git] / src / Core / ACL.php
1 <?php
2
3 /**
4  * @file src/Core/Acl.php
5  */
6
7 namespace Friendica\Core;
8
9 use Friendica\App\Page;
10 use Friendica\Database\DBA;
11 use Friendica\DI;
12 use Friendica\Model\Contact;
13 use Friendica\Model\Group;
14
15 /**
16  * Handle ACL management and display
17  *
18  * @author Hypolite Petovan <hypolite@mrpetovan.com>
19  */
20 class ACL
21 {
22         /**
23          * Returns a select input tag with all the contact of the local user
24          *
25          * @param string $selname     Name attribute of the select input tag
26          * @param string $selclass    Class attribute of the select input tag
27          * @param array  $preselected Contact IDs that should be already selected
28          * @param int    $size        Length of the select box
29          * @param int    $tabindex    Select input tag tabindex attribute
30          * @return string
31          * @throws \Exception
32          */
33         public static function getMessageContactSelectHTML($selname, $selclass, array $preselected = [], $size = 4, $tabindex = null)
34         {
35                 $a = DI::app();
36
37                 $o = '';
38
39                 // When used for private messages, we limit correspondence to mutual DFRN/Friendica friends and the selector
40                 // to one recipient. By default our selector allows multiple selects amongst all contacts.
41                 $sql_extra = sprintf(" AND `rel` = %d ", intval(Contact::FRIEND));
42                 $sql_extra .= sprintf(" AND `network` IN ('%s' , '%s') ", Protocol::DFRN, Protocol::DIASPORA);
43
44                 $tabindex_attr = !empty($tabindex) ? ' tabindex="' . intval($tabindex) . '"' : '';
45
46                 $hidepreselected = '';
47                 if ($preselected) {
48                         $sql_extra .= " AND `id` IN (" . implode(",", $preselected) . ")";
49                         $hidepreselected = ' style="display: none;"';
50                 }
51
52                 $o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"$size\"$tabindex_attr$hidepreselected>\r\n";
53
54                 $stmt = DBA::p("SELECT `id`, `name`, `url`, `network` FROM `contact`
55                         WHERE `uid` = ? AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND NOT `deleted` AND `notify` != ''
56                         $sql_extra
57                         ORDER BY `name` ASC ", intval(local_user())
58                 );
59
60                 $contacts = DBA::toArray($stmt);
61
62                 $arr = ['contact' => $contacts, 'entry' => $o];
63
64                 // e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow'
65                 Hook::callAll(DI::module()->getName() . '_pre_' . $selname, $arr);
66
67                 $receiverlist = [];
68
69                 if (DBA::isResult($contacts)) {
70                         foreach ($contacts as $contact) {
71                                 if (in_array($contact['id'], $preselected)) {
72                                         $selected = ' selected="selected"';
73                                 } else {
74                                         $selected = '';
75                                 }
76
77                                 $trimmed = Protocol::formatMention($contact['url'], $contact['name']);
78
79                                 $receiverlist[] = $trimmed;
80
81                                 $o .= "<option value=\"{$contact['id']}\"$selected title=\"{$contact['name']}|{$contact['url']}\" >$trimmed</option>\r\n";
82                         }
83                 }
84
85                 $o .= '</select>' . PHP_EOL;
86
87                 if ($preselected) {
88                         $o .= implode(', ', $receiverlist);
89                 }
90
91                 Hook::callAll(DI::module()->getName() . '_post_' . $selname, $o);
92
93                 return $o;
94         }
95
96         /**
97          * Return the default permission of the provided user array
98          *
99          * @param array $user
100          * @return array Hash of contact id lists
101          * @throws \Exception
102          */
103         public static function getDefaultUserPermissions(array $user = null)
104         {
105                 $aclFormatter = DI::aclFormatter();
106
107                 return [
108                         'allow_cid' => Contact::pruneUnavailable($aclFormatter->expand($user['allow_cid'] ?? '')),
109                         'allow_gid' => $aclFormatter->expand($user['allow_gid'] ?? ''),
110                         'deny_cid'  => $aclFormatter->expand($user['deny_cid']  ?? ''),
111                         'deny_gid'  => $aclFormatter->expand($user['deny_gid']  ?? ''),
112                 ];
113         }
114
115         /**
116          * Returns the ACL list of contacts for a given user id
117          *
118          * @param int   $user_id
119          * @param array $condition Additional contact lookup table conditions
120          * @return array
121          * @throws \Exception
122          */
123         public static function getContactListByUserId(int $user_id, array $condition = [])
124         {
125                 $fields = ['id', 'name', 'addr', 'micro'];
126                 $params = ['order' => ['name']];
127                 $acl_contacts = Contact::selectToArray(
128                         $fields,
129                         array_merge([
130                                 'uid' => $user_id,
131                                 'self' => false,
132                                 'blocked' => false,
133                                 'archive' => false,
134                                 'deleted' => false,
135                                 'pending' => false,
136                                 'rel' => [Contact::FOLLOWER, Contact::FRIEND]
137                         ], $condition),
138                         $params
139                 );
140
141                 $acl_yourself = Contact::selectFirst($fields, ['uid' => $user_id, 'self' => true]);
142                 $acl_yourself['name'] = DI::l10n()->t('Yourself');
143
144                 $acl_contacts[] = $acl_yourself;
145
146                 $acl_forums = Contact::selectToArray($fields,
147                         ['uid' => $user_id, 'self' => false, 'blocked' => false, 'archive' => false, 'deleted' => false,
148                         'pending' => false, 'contact-type' => Contact::TYPE_COMMUNITY], $params
149                 );
150
151                 $acl_contacts = array_merge($acl_forums, $acl_contacts);
152
153                 array_walk($acl_contacts, function (&$value) {
154                         $value['type'] = 'contact';
155                 });
156
157                 return $acl_contacts;
158         }
159
160         /**
161          * Returns the ACL list of groups (including meta-groups) for a given user id
162          *
163          * @param int $user_id
164          * @return array
165          */
166         public static function getGroupListByUserId(int $user_id)
167         {
168                 $acl_groups = [
169                         [
170                                 'id' => Group::FOLLOWERS,
171                                 'name' => DI::l10n()->t('Followers'),
172                                 'addr' => '',
173                                 'micro' => 'images/twopeople.png',
174                                 'type' => 'group',
175                         ],
176                         [
177                                 'id' => Group::MUTUALS,
178                                 'name' => DI::l10n()->t('Mutuals'),
179                                 'addr' => '',
180                                 'micro' => 'images/twopeople.png',
181                                 'type' => 'group',
182                         ]
183                 ];
184                 foreach (Group::getByUserId($user_id) as $group) {
185                         $acl_groups[] = [
186                                 'id' => $group['id'],
187                                 'name' => $group['name'],
188                                 'addr' => '',
189                                 'micro' => 'images/twopeople.png',
190                                 'type' => 'group',
191                         ];
192                 }
193
194                 return $acl_groups;
195         }
196
197         /**
198          * Return the full jot ACL selector HTML
199          *
200          * @param Page   $page
201          * @param array  $user                  User array
202          * @param bool   $for_federation
203          * @param array  $default_permissions   Static defaults permission array:
204          *                                      [
205          *                                      'allow_cid' => [],
206          *                                      'allow_gid' => [],
207          *                                      'deny_cid' => [],
208          *                                      'deny_gid' => [],
209          *                                      'hidewall' => true/false
210          *                                      ]
211          * @param array  $condition
212          * @param string $form_prefix
213          * @return string
214          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
215          */
216         public static function getFullSelectorHTML(
217                 Page $page,
218                 array $user = null,
219                 bool $for_federation = false,
220                 array $default_permissions = [],
221                 array $condition = [],
222                 $form_prefix = ''
223         ) {
224                 if (empty($user['uid'])) {
225                         return '';
226                 }
227
228                 static $input_group_id = 0;
229
230                 $input_group_id++;
231
232                 $page->registerFooterScript(Theme::getPathForFile('asset/typeahead.js/dist/typeahead.bundle.js'));
233                 $page->registerFooterScript(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.js'));
234                 $page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css'));
235                 $page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput-typeahead.css'));
236
237                 // Defaults user permissions
238                 if (empty($default_permissions)) {
239                         $default_permissions = self::getDefaultUserPermissions($user);
240                 }
241
242                 $default_permissions = [
243                         'allow_cid' => $default_permissions['allow_cid'] ?? [],
244                         'allow_gid' => $default_permissions['allow_gid'] ?? [],
245                         'deny_cid'  => $default_permissions['deny_cid']  ?? [],
246                         'deny_gid'  => $default_permissions['deny_gid']  ?? [],
247                         'hidewall'  => $default_permissions['hidewall']  ?? false,
248                 ];
249
250                 if (count($default_permissions['allow_cid'])
251                         + count($default_permissions['allow_gid'])
252                         + count($default_permissions['deny_cid'])
253                         + count($default_permissions['deny_gid'])) {
254                         $visibility = 'custom';
255                 } else {
256                         $visibility = 'public';
257                         // Default permission display for custom panel
258                         $default_permissions['allow_gid'] = [Group::FOLLOWERS];
259                 }
260
261                 $jotnets_fields = [];
262                 if ($for_federation) {
263                         $mail_enabled = false;
264                         $pubmail_enabled = false;
265
266                         if (function_exists('imap_open') && !DI::config()->get('system', 'imap_disabled')) {
267                                 $mailacct = DBA::selectFirst('mailacct', ['pubmail'], ['`uid` = ? AND `server` != ""', $user['uid']]);
268                                 if (DBA::isResult($mailacct)) {
269                                         $mail_enabled = true;
270                                         $pubmail_enabled = !empty($mailacct['pubmail']);
271                                 }
272                         }
273
274                         if (!$default_permissions['hidewall']) {
275                                 if ($mail_enabled) {
276                                         $jotnets_fields[] = [
277                                                 'type' => 'checkbox',
278                                                 'field' => [
279                                                         'pubmail_enable',
280                                                         DI::l10n()->t('Post to Email'),
281                                                         $pubmail_enabled
282                                                 ]
283                                         ];
284                                 }
285
286                                 Hook::callAll('jot_networks', $jotnets_fields);
287                         }
288                 }
289
290                 $acl_contacts = self::getContactListByUserId($user['uid'], $condition);
291
292                 $acl_groups = self::getGroupListByUserId($user['uid']);
293
294                 $acl_list = array_merge($acl_groups, $acl_contacts);
295
296                 $input_names = [
297                         'visibility'    => $form_prefix ? $form_prefix . '[visibility]'    : 'visibility',
298                         'group_allow'   => $form_prefix ? $form_prefix . '[group_allow]'   : 'group_allow',
299                         'contact_allow' => $form_prefix ? $form_prefix . '[contact_allow]' : 'contact_allow',
300                         'group_deny'    => $form_prefix ? $form_prefix . '[group_deny]'    : 'group_deny',
301                         'contact_deny'  => $form_prefix ? $form_prefix . '[contact_deny]'  : 'contact_deny',
302                         'emailcc'       => $form_prefix ? $form_prefix . '[emailcc]'       : 'emailcc',
303                 ];
304
305                 $tpl = Renderer::getMarkupTemplate('acl_selector.tpl');
306                 $o = Renderer::replaceMacros($tpl, [
307                         '$public_title'   => DI::l10n()->t('Public'),
308                         '$public_desc'    => DI::l10n()->t('This content will be shown to all your followers and can be seen in the community pages and by anyone with its link.'),
309                         '$custom_title'   => DI::l10n()->t('Limited/Private'),
310                         '$custom_desc'    => DI::l10n()->t('This content will be shown only to the people in the first box, to the exception of the people mentioned in the second box. It won\'t appear anywhere public.'),
311                         '$allow_label'    => DI::l10n()->t('Show to:'),
312                         '$deny_label'     => DI::l10n()->t('Except to:'),
313                         '$emailcc'        => DI::l10n()->t('CC: email addresses'),
314                         '$emtitle'        => DI::l10n()->t('Example: bob@example.com, mary@example.com'),
315                         '$jotnets_summary' => DI::l10n()->t('Connectors'),
316                         '$jotnets_disabled_label' => DI::l10n()->t('Connectors disabled, since "%s" is enabled.', DI::l10n()->t('Hide your profile details from unknown viewers?')),
317                         '$visibility'     => $visibility,
318                         '$acl_contacts'   => $acl_contacts,
319                         '$acl_groups'     => $acl_groups,
320                         '$acl_list'       => $acl_list,
321                         '$contact_allow'  => implode(',', $default_permissions['allow_cid']),
322                         '$group_allow'    => implode(',', $default_permissions['allow_gid']),
323                         '$contact_deny'   => implode(',', $default_permissions['deny_cid']),
324                         '$group_deny'     => implode(',', $default_permissions['deny_gid']),
325                         '$for_federation' => $for_federation,
326                         '$jotnets_fields' => $jotnets_fields,
327                         '$user_hidewall'  => $default_permissions['hidewall'],
328                         '$input_names'    => $input_names,
329                         '$input_group_id' => $input_group_id,
330                 ]);
331
332                 return $o;
333         }
334 }