]> git.mxchange.org Git - friendica.git/blob - src/Module/Settings/Profile/Index.php
Merge pull request #12131 from MrPetovan/task/4090-move-mod-salmon
[friendica.git] / src / Module / Settings / Profile / Index.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2022, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Module\Settings\Profile;
23
24 use Friendica\Core\ACL;
25 use Friendica\Core\Hook;
26 use Friendica\Core\Protocol;
27 use Friendica\Core\Renderer;
28 use Friendica\Core\Theme;
29 use Friendica\Database\DBA;
30 use Friendica\DI;
31 use Friendica\Model\Contact;
32 use Friendica\Model\Profile;
33 use Friendica\Profile\ProfileField\Collection\ProfileFields;
34 use Friendica\Profile\ProfileField\Entity\ProfileField;
35 use Friendica\Model\User;
36 use Friendica\Module\BaseSettings;
37 use Friendica\Module\Security\Login;
38 use Friendica\Network\HTTPException;
39 use Friendica\Util\DateTimeFormat;
40 use Friendica\Util\Temporal;
41 use Friendica\Core\Worker;
42
43 class Index extends BaseSettings
44 {
45         protected function post(array $request = [])
46         {
47                 if (!DI::userSession()->getLocalUserId()) {
48                         return;
49                 }
50
51                 $profile = Profile::getByUID(DI::userSession()->getLocalUserId());
52                 if (!DBA::isResult($profile)) {
53                         return;
54                 }
55
56                 self::checkFormSecurityTokenRedirectOnError('/settings/profile', 'settings_profile');
57
58                 Hook::callAll('profile_post', $_POST);
59
60                 $dob = trim($_POST['dob'] ?? '');
61
62                 if ($dob && !in_array($dob, ['0000-00-00', DBA::NULL_DATE])) {
63                         $y = substr($dob, 0, 4);
64                         if ((!ctype_digit($y)) || ($y < 1900)) {
65                                 $ignore_year = true;
66                         } else {
67                                 $ignore_year = false;
68                         }
69
70                         if (strpos($dob, '0000-') === 0 || strpos($dob, '0001-') === 0) {
71                                 $ignore_year = true;
72                                 $dob = substr($dob, 5);
73                         }
74
75                         if ($ignore_year) {
76                                 $dob = '0000-' . DateTimeFormat::utc('1900-' . $dob, 'm-d');
77                         } else {
78                                 $dob = DateTimeFormat::utc($dob, 'Y-m-d');
79                         }
80                 }
81
82                 $name = trim($_POST['name'] ?? '');
83                 if (!strlen($name)) {
84                         DI::sysmsg()->addNotice(DI::l10n()->t('Profile Name is required.'));
85                         return;
86                 }
87
88                 $about = trim($_POST['about']);
89                 $address = trim($_POST['address']);
90                 $locality = trim($_POST['locality']);
91                 $region = trim($_POST['region']);
92                 $postal_code = trim($_POST['postal_code']);
93                 $country_name = trim($_POST['country_name']);
94                 $pub_keywords = self::cleanKeywords(trim($_POST['pub_keywords']));
95                 $prv_keywords = self::cleanKeywords(trim($_POST['prv_keywords']));
96                 $xmpp = trim($_POST['xmpp']);
97                 $matrix = trim($_POST['matrix']);
98                 $homepage = trim($_POST['homepage']);
99                 if ((strpos($homepage, 'http') !== 0) && (strlen($homepage))) {
100                         // neither http nor https in URL, add them
101                         $homepage = 'http://' . $homepage;
102                 }
103
104                 $profileFieldsNew = self::getProfileFieldsFromInput(
105                         DI::userSession()->getLocalUserId(),
106                         $_REQUEST['profile_field'],
107                         $_REQUEST['profile_field_order']
108                 );
109
110                 DI::profileField()->saveCollectionForUser(DI::userSession()->getLocalUserId(), $profileFieldsNew);
111
112                 $result = Profile::update(
113                         [
114                                 'name'         => $name,
115                                 'about'        => $about,
116                                 'dob'          => $dob,
117                                 'address'      => $address,
118                                 'locality'     => $locality,
119                                 'region'       => $region,
120                                 'postal-code'  => $postal_code,
121                                 'country-name' => $country_name,
122                                 'xmpp'         => $xmpp,
123                                 'matrix'       => $matrix,
124                                 'homepage'     => $homepage,
125                                 'pub_keywords' => $pub_keywords,
126                                 'prv_keywords' => $prv_keywords,
127                         ],
128                         DI::userSession()->getLocalUserId()
129                 );
130
131                 Worker::add(Worker::PRIORITY_MEDIUM, 'CheckRelMeProfileLink', DI::userSession()->getLocalUserId());
132
133                 if (!$result) {
134                         DI::sysmsg()->addNotice(DI::l10n()->t('Profile couldn\'t be updated.'));
135                         return;
136                 }
137
138                 DI::baseUrl()->redirect('settings/profile');
139         }
140
141         protected function content(array $request = []): string
142         {
143                 if (!DI::userSession()->getLocalUserId()) {
144                         DI::sysmsg()->addNotice(DI::l10n()->t('You must be logged in to use this module'));
145                         return Login::form();
146                 }
147
148                 parent::content();
149
150                 $o = '';
151
152                 $profile = User::getOwnerDataById(DI::userSession()->getLocalUserId());
153                 if (!DBA::isResult($profile)) {
154                         throw new HTTPException\NotFoundException();
155                 }
156
157                 $a = DI::app();
158
159                 DI::page()->registerFooterScript('view/asset/es-jquery-sortable/source/js/jquery-sortable-min.js');
160                 DI::page()->registerFooterScript(Theme::getPathForFile('js/module/settings/profile/index.js'));
161
162                 $custom_fields = [];
163
164                 $profileFields = DI::profileField()->selectByUserId(DI::userSession()->getLocalUserId());
165                 foreach ($profileFields as $profileField) {
166                         /** @var ProfileField $profileField */
167                         $defaultPermissions = $profileField->permissionSet->withAllowedContacts(
168                                 Contact::pruneUnavailable($profileField->permissionSet->allow_cid)
169                         );
170
171                         $custom_fields[] = [
172                                 'id' => $profileField->id,
173                                 'legend' => $profileField->label,
174                                 'fields' => [
175                                         'label' => ['profile_field[' . $profileField->id . '][label]', DI::l10n()->t('Label:'), $profileField->label],
176                                         'value' => ['profile_field[' . $profileField->id . '][value]', DI::l10n()->t('Value:'), $profileField->value],
177                                         'acl' => ACL::getFullSelectorHTML(
178                                                 DI::page(),
179                                                 $a->getLoggedInUserId(),
180                                                 false,
181                                                 $defaultPermissions->toArray(),
182                                                 ['network' => Protocol::DFRN],
183                                                 'profile_field[' . $profileField->id . ']'
184                                         ),
185                                 ],
186                                 'permissions' => DI::l10n()->t('Field Permissions'),
187                                 'permdesc' => DI::l10n()->t("(click to open/close)"),
188                         ];
189                 };
190
191                 $custom_fields[] = [
192                         'id' => 'new',
193                         'legend' => DI::l10n()->t('Add a new profile field'),
194                         'fields' => [
195                                 'label' => ['profile_field[new][label]', DI::l10n()->t('Label:')],
196                                 'value' => ['profile_field[new][value]', DI::l10n()->t('Value:')],
197                                 'acl' => ACL::getFullSelectorHTML(
198                                         DI::page(),
199                                         $a->getLoggedInUserId(),
200                                         false,
201                                         ['allow_cid' => []],
202                                         ['network' => Protocol::DFRN],
203                                         'profile_field[new]'
204                                 ),
205                         ],
206                         'permissions' => DI::l10n()->t('Field Permissions'),
207                         'permdesc' => DI::l10n()->t("(click to open/close)"),
208                 ];
209
210                 DI::page()['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('settings/profile/index_head.tpl'), [
211                         '$baseurl' => DI::baseUrl()->get(true),
212                 ]);
213
214                 $personal_account = ($profile['account-type'] != User::ACCOUNT_TYPE_COMMUNITY);
215
216                 if ($profile['homepage_verified']) {
217                         $homepage_help_text = DI::l10n()->t('The homepage is verified. A rel="me" link back to your Friendica profile page was found on the homepage.');
218                 } else {
219                         $homepage_help_text = DI::l10n()->t('To verify your homepage, add a rel="me" link to it, pointing to your profile URL (%s).', $profile['url']);
220                 }
221
222                 $tpl = Renderer::getMarkupTemplate('settings/profile/index.tpl');
223                 $o .= Renderer::replaceMacros($tpl, [
224                         '$personal_account' => $personal_account,
225
226                         '$form_security_token' => self::getFormSecurityToken('settings_profile'),
227                         '$form_security_token_photo' => self::getFormSecurityToken('settings_profile_photo'),
228
229                         '$profile_action' => DI::l10n()->t('Profile Actions'),
230                         '$banner' => DI::l10n()->t('Edit Profile Details'),
231                         '$submit' => DI::l10n()->t('Submit'),
232                         '$profpic' => DI::l10n()->t('Change Profile Photo'),
233                         '$profpiclink' => '/photos/' . $profile['nickname'],
234                         '$viewprof' => DI::l10n()->t('View Profile'),
235
236                         '$lbl_personal_section' => DI::l10n()->t('Personal'),
237                         '$lbl_picture_section' => DI::l10n()->t('Profile picture'),
238                         '$lbl_location_section' => DI::l10n()->t('Location'),
239                         '$lbl_miscellaneous_section' => DI::l10n()->t('Miscellaneous'),
240                         '$lbl_custom_fields_section' => DI::l10n()->t('Custom Profile Fields'),
241
242                         '$lbl_profile_photo' => DI::l10n()->t('Upload Profile Photo'),
243
244                         '$baseurl' => DI::baseUrl()->get(true),
245                         '$nickname' => $profile['nickname'],
246                         '$name' => ['name', DI::l10n()->t('Display name:'), $profile['name']],
247                         '$about' => ['about', DI::l10n()->t('Description:'), $profile['about']],
248                         '$dob' => Temporal::getDateofBirthField($profile['dob'], $profile['timezone']),
249                         '$address' => ['address', DI::l10n()->t('Street Address:'), $profile['address']],
250                         '$locality' => ['locality', DI::l10n()->t('Locality/City:'), $profile['locality']],
251                         '$region' => ['region', DI::l10n()->t('Region/State:'), $profile['region']],
252                         '$postal_code' => ['postal_code', DI::l10n()->t('Postal/Zip Code:'), $profile['postal-code']],
253                         '$country_name' => ['country_name', DI::l10n()->t('Country:'), $profile['country-name']],
254                         '$age' => ((intval($profile['dob'])) ? '(' . DI::l10n()->t('Age: ') . DI::l10n()->tt('%d year old', '%d years old', Temporal::getAgeByTimezone($profile['dob'], $profile['timezone'])) . ')' : ''),
255                         '$xmpp' => ['xmpp', DI::l10n()->t('XMPP (Jabber) address:'), $profile['xmpp'], DI::l10n()->t('The XMPP address will be published so that people can follow you there.')],
256                         '$matrix' => ['matrix', DI::l10n()->t('Matrix (Element) address:'), $profile['matrix'], DI::l10n()->t('The Matrix address will be published so that people can follow you there.')],
257                         '$homepage' => ['homepage', DI::l10n()->t('Homepage URL:'), $profile['homepage'], $homepage_help_text],
258                         '$pub_keywords' => ['pub_keywords', DI::l10n()->t('Public Keywords:'), $profile['pub_keywords'], DI::l10n()->t('(Used for suggesting potential friends, can be seen by others)')],
259                         '$prv_keywords' => ['prv_keywords', DI::l10n()->t('Private Keywords:'), $profile['prv_keywords'], DI::l10n()->t('(Used for searching profiles, never shown to others)')],
260                         '$custom_fields_description' => DI::l10n()->t("<p>Custom fields appear on <a href=\"%s\">your profile page</a>.</p>
261                                 <p>You can use BBCodes in the field values.</p>
262                                 <p>Reorder by dragging the field title.</p>
263                                 <p>Empty the label field to remove a custom field.</p>
264                                 <p>Non-public fields can only be seen by the selected Friendica contacts or the Friendica contacts in the selected groups.</p>",
265                                 'profile/' . $profile['nickname']
266                         ),
267                         '$custom_fields' => $custom_fields,
268                 ]);
269
270                 $arr = ['profile' => $profile, 'entry' => $o];
271                 Hook::callAll('profile_edit', $arr);
272
273                 return $o;
274         }
275
276         private static function getProfileFieldsFromInput(int $uid, array $profileFieldInputs, array $profileFieldOrder): ProfileFields
277         {
278                 $profileFields = new ProfileFields();
279
280                 // Returns an associative array of id => order values
281                 $profileFieldOrder = array_flip($profileFieldOrder);
282
283                 // Creation of the new field
284                 if (!empty($profileFieldInputs['new']['label'])) {
285                         $permissionSet = DI::permissionSet()->selectOrCreate(DI::permissionSetFactory()->createFromString(
286                                 $uid,
287                                 DI::aclFormatter()->toString($profileFieldInputs['new']['contact_allow'] ?? ''),
288                                 DI::aclFormatter()->toString($profileFieldInputs['new']['group_allow'] ?? ''),
289                                 DI::aclFormatter()->toString($profileFieldInputs['new']['contact_deny'] ?? ''),
290                                 DI::aclFormatter()->toString($profileFieldInputs['new']['group_deny'] ?? '')
291                         ));
292
293                         $profileFields->append(DI::profileFieldFactory()->createFromValues(
294                                 $uid,
295                                 $profileFieldOrder['new'],
296                                 $profileFieldInputs['new']['label'],
297                                 $profileFieldInputs['new']['value'],
298                                 $permissionSet
299                         ));
300                 }
301
302                 unset($profileFieldInputs['new']);
303                 unset($profileFieldOrder['new']);
304
305                 foreach ($profileFieldInputs as $id => $profileFieldInput) {
306                         $permissionSet = DI::permissionSet()->selectOrCreate(DI::permissionSetFactory()->createFromString(
307                                 $uid,
308                                 DI::aclFormatter()->toString($profileFieldInput['contact_allow'] ?? ''),
309                                 DI::aclFormatter()->toString($profileFieldInput['group_allow'] ?? ''),
310                                 DI::aclFormatter()->toString($profileFieldInput['contact_deny'] ?? ''),
311                                 DI::aclFormatter()->toString($profileFieldInput['group_deny'] ?? '')
312                         ));
313
314                         $profileFields->append(DI::profileFieldFactory()->createFromValues(
315                                 $uid,
316                                 $profileFieldOrder[$id],
317                                 $profileFieldInput['label'],
318                                 $profileFieldInput['value'],
319                                 $permissionSet
320                         ));
321                 }
322
323                 return $profileFields;
324         }
325
326         private static function cleanKeywords($keywords)
327         {
328                 $keywords = str_replace(',', ' ', $keywords);
329                 $keywords = explode(' ', $keywords);
330
331                 $cleaned = [];
332                 foreach ($keywords as $keyword) {
333                         $keyword = trim(strtolower($keyword));
334                         $keyword = trim($keyword, '#');
335                         if ($keyword != '') {
336                                 $cleaned[] = $keyword;
337                         }
338                 }
339
340                 $keywords = implode(', ', $cleaned);
341
342                 return $keywords;
343         }
344 }