From d1be68b75462df77100c9262134b70717635ddfe Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 27 Oct 2019 10:08:14 -0400 Subject: [PATCH 01/19] Move Module\Profile to Module\Profile\Index - Move /profiles to Module\Settings\Profile\Index --- mod/network.php | 2 +- mod/profiles.php | 675 ------------------ mod/settings.php | 6 +- mod/update_profile.php | 49 -- src/Model/Profile.php | 85 +-- src/Module/BaseSettingsModule.php | 6 +- src/Module/Profile.php | 361 ---------- src/Module/Profile/Index.php | 121 ++++ src/Module/Profile/Status.php | 217 ++++++ src/Module/Settings/Profile/Index.php | 388 ++++++++++ src/Module/Update/Profile.php | 127 ++++ static/routes.config.php | 11 +- tests/src/App/RouterTest.php | 6 +- view/templates/profile-hide-wall.tpl | 17 - view/templates/profile-in-directory.tpl | 17 - view/templates/profile-in-netdir.tpl | 17 - view/templates/profile_edlink.tpl | 3 - .../profile/hide-friends.tpl} | 0 .../profile/index.tpl} | 30 +- .../profile/index_head.tpl} | 0 view/templates/settings/profile/link.tpl | 2 + view/templates/welcome.tpl | 4 +- .../profile/index.tpl} | 102 +-- .../profile/index.tpl} | 120 ++-- .../profile/link.tpl} | 0 25 files changed, 1007 insertions(+), 1359 deletions(-) delete mode 100644 mod/profiles.php delete mode 100644 mod/update_profile.php delete mode 100644 src/Module/Profile.php create mode 100644 src/Module/Profile/Index.php create mode 100644 src/Module/Profile/Status.php create mode 100644 src/Module/Settings/Profile/Index.php create mode 100644 src/Module/Update/Profile.php delete mode 100644 view/templates/profile-hide-wall.tpl delete mode 100644 view/templates/profile-in-directory.tpl delete mode 100644 view/templates/profile-in-netdir.tpl delete mode 100644 view/templates/profile_edlink.tpl rename view/templates/{profile-hide-friends.tpl => settings/profile/hide-friends.tpl} (100%) rename view/templates/{profile_edit.tpl => settings/profile/index.tpl} (91%) rename view/templates/{profed_head.tpl => settings/profile/index_head.tpl} (100%) create mode 100644 view/templates/settings/profile/link.tpl rename view/theme/frio/templates/{profile_edit.tpl => settings/profile/index.tpl} (76%) rename view/theme/vier/templates/{profile_edit.tpl => settings/profile/index.tpl} (93%) rename view/theme/vier/templates/{profile_edlink.tpl => settings/profile/link.tpl} (100%) diff --git a/mod/network.php b/mod/network.php index db6d8eaf45..1bbddf2196 100644 --- a/mod/network.php +++ b/mod/network.php @@ -879,7 +879,7 @@ function network_tabs(App $a) { // item filter tabs /// @TODO fix this logic, reduce duplication - /// $a->page['content'] .= '
'; + /// DI::page()['content'] .= '
'; list($no_active, $all_active, $post_active, $conv_active, $new_active, $starred_active, $bookmarked_active) = network_query_get_sel_tab($a); // if no tabs are selected, defaults to activitys diff --git a/mod/profiles.php b/mod/profiles.php deleted file mode 100644 index 53da8510c4..0000000000 --- a/mod/profiles.php +++ /dev/null @@ -1,675 +0,0 @@ -argc > 2) && ($a->argv[1] === "drop") && intval($a->argv[2])) { - $r = q("SELECT * FROM `profile` WHERE `id` = %d AND `uid` = %d AND `is-default` = 0 LIMIT 1", - intval($a->argv[2]), - intval(local_user()) - ); - if (! DBA::isResult($r)) { - notice(DI::l10n()->t('Profile not found.') . EOL); - DI::baseUrl()->redirect('profiles'); - return; // NOTREACHED - } - - BaseModule::checkFormSecurityTokenRedirectOnError('/profiles', 'profile_drop', 't'); - - // move every contact using this profile as their default to the user default - - q("UPDATE `contact` SET `profile-id` = (SELECT `profile`.`id` AS `profile-id` FROM `profile` WHERE `profile`.`is-default` = 1 AND `profile`.`uid` = %d LIMIT 1) WHERE `profile-id` = %d AND `uid` = %d ", - intval(local_user()), - intval($a->argv[2]), - intval(local_user()) - ); - q("DELETE FROM `profile` WHERE `id` = %d AND `uid` = %d", - intval($a->argv[2]), - intval(local_user()) - ); - if (DBA::isResult($r)) { - info(DI::l10n()->t('Profile deleted.').EOL); - } - - DI::baseUrl()->redirect('profiles'); - return; // NOTREACHED - } - - if (($a->argc > 1) && ($a->argv[1] === 'new')) { - - BaseModule::checkFormSecurityTokenRedirectOnError('/profiles', 'profile_new', 't'); - - $r0 = q("SELECT `id` FROM `profile` WHERE `uid` = %d", - intval(local_user())); - - $num_profiles = (DBA::isResult($r0) ? count($r0) : 0); - - $name = DI::l10n()->t('Profile-') . ($num_profiles + 1); - - $r1 = q("SELECT `name`, `photo`, `thumb` FROM `profile` WHERE `uid` = %d AND `is-default` = 1 LIMIT 1", - intval(local_user())); - - q("INSERT INTO `profile` (`uid` , `profile-name` , `name`, `photo`, `thumb`) - VALUES ( %d, '%s', '%s', '%s', '%s' )", - intval(local_user()), - DBA::escape($name), - DBA::escape($r1[0]['name']), - DBA::escape($r1[0]['photo']), - DBA::escape($r1[0]['thumb']) - ); - - $r3 = q("SELECT `id` FROM `profile` WHERE `uid` = %d AND `profile-name` = '%s' LIMIT 1", - intval(local_user()), - DBA::escape($name) - ); - - info(DI::l10n()->t('New profile created.') . EOL); - if (DBA::isResult($r3) && count($r3) == 1) { - DI::baseUrl()->redirect('profiles/' . $r3[0]['id']); - } - - DI::baseUrl()->redirect('profiles'); - } - - if (($a->argc > 2) && ($a->argv[1] === 'clone')) { - - BaseModule::checkFormSecurityTokenRedirectOnError('/profiles', 'profile_clone', 't'); - - $r0 = q("SELECT `id` FROM `profile` WHERE `uid` = %d", - intval(local_user())); - - $num_profiles = (DBA::isResult($r0) ? count($r0) : 0); - - $name = DI::l10n()->t('Profile-') . ($num_profiles + 1); - $r1 = q("SELECT * FROM `profile` WHERE `uid` = %d AND `id` = %d LIMIT 1", - intval(local_user()), - intval($a->argv[2]) - ); - if(! DBA::isResult($r1)) { - notice(DI::l10n()->t('Profile unavailable to clone.') . EOL); - exit(); - } - unset($r1[0]['id']); - $r1[0]['is-default'] = 0; - $r1[0]['publish'] = 0; - $r1[0]['net-publish'] = 0; - $r1[0]['profile-name'] = DBA::escape($name); - - DBA::insert('profile', $r1[0]); - - $r3 = q("SELECT `id` FROM `profile` WHERE `uid` = %d AND `profile-name` = '%s' LIMIT 1", - intval(local_user()), - DBA::escape($name) - ); - info(DI::l10n()->t('New profile created.') . EOL); - if ((DBA::isResult($r3)) && (count($r3) == 1)) { - DI::baseUrl()->redirect('profiles/'.$r3[0]['id']); - } - - DI::baseUrl()->redirect('profiles'); - - return; // NOTREACHED - } - - - if (($a->argc > 1) && (intval($a->argv[1]))) { - $r = q("SELECT id FROM `profile` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($a->argv[1]), - intval(local_user()) - ); - if (! DBA::isResult($r)) { - notice(DI::l10n()->t('Profile not found.') . EOL); - exit(); - } - - Profile::load($a, $a->user['nickname'], $r[0]['id']); - } -} - -function profile_clean_keywords($keywords) -{ - $keywords = str_replace(",", " ", $keywords); - $keywords = explode(" ", $keywords); - - $cleaned = []; - foreach ($keywords as $keyword) { - $keyword = trim(strtolower($keyword)); - $keyword = trim($keyword, "#"); - if ($keyword != "") { - $cleaned[] = $keyword; - } - } - - $keywords = implode(", ", $cleaned); - - return $keywords; -} - -function profiles_post(App $a) { - - if (! local_user()) { - notice(DI::l10n()->t('Permission denied.') . EOL); - return; - } - - $namechanged = false; - - Hook::callAll('profile_post', $_POST); - - if (($a->argc > 1) && ($a->argv[1] !== "new") && intval($a->argv[1])) { - $orig = q("SELECT * FROM `profile` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($a->argv[1]), - intval(local_user()) - ); - if (! DBA::isResult($orig)) { - notice(DI::l10n()->t('Profile not found.') . EOL); - return; - } - - BaseModule::checkFormSecurityTokenRedirectOnError('/profiles', 'profile_edit'); - - $is_default = (($orig[0]['is-default']) ? 1 : 0); - - $profile_name = Strings::escapeTags(trim($_POST['profile_name'])); - if (! strlen($profile_name)) { - notice(DI::l10n()->t('Profile Name is required.') . EOL); - return; - } - - $dob = !empty($_POST['dob']) ? Strings::escapeHtml(trim($_POST['dob'])) : '0000-00-00'; - - $y = substr($dob, 0, 4); - if ((! ctype_digit($y)) || ($y < 1900)) { - $ignore_year = true; - } else { - $ignore_year = false; - } - if (!in_array($dob, ['0000-00-00', DBA::NULL_DATE])) { - if (strpos($dob, '0000-') === 0 || strpos($dob, '0001-') === 0) { - $ignore_year = true; - $dob = substr($dob, 5); - } - - if ($ignore_year) { - $dob = '0000-' . DateTimeFormat::utc('1900-' . $dob, 'm-d'); - } else { - $dob = DateTimeFormat::utc($dob, 'Y-m-d'); - } - } - - $name = Strings::escapeTags(trim($_POST['name'])); - - if (! strlen($name)) { - $name = '[No Name]'; - } - - if ($orig[0]['name'] != $name) { - $namechanged = true; - } - - $pdesc = Strings::escapeTags(trim($_POST['pdesc'] ?? '')); - $gender = Strings::escapeTags(trim($_POST['gender'] ?? '')); - $address = Strings::escapeTags(trim($_POST['address'] ?? '')); - $locality = Strings::escapeTags(trim($_POST['locality'] ?? '')); - $region = Strings::escapeTags(trim($_POST['region'] ?? '')); - $postal_code = Strings::escapeTags(trim($_POST['postal_code'] ?? '')); - $country_name = Strings::escapeTags(trim($_POST['country_name'] ?? '')); - $pub_keywords = profile_clean_keywords(Strings::escapeTags(trim($_POST['pub_keywords'] ?? ''))); - $prv_keywords = profile_clean_keywords(Strings::escapeTags(trim($_POST['prv_keywords'] ?? ''))); - $marital = Strings::escapeTags(trim($_POST['marital'] ?? '')); - $howlong = Strings::escapeTags(trim($_POST['howlong'] ?? '')); - - $with = (!empty($_POST['with']) ? Strings::escapeTags(trim($_POST['with'])) : ''); - - if (! strlen($howlong)) { - $howlong = DBA::NULL_DATETIME; - } else { - $howlong = DateTimeFormat::convert($howlong, 'UTC', date_default_timezone_get()); - } - // linkify the relationship target if applicable - - $withchanged = false; - - if (strlen($with)) { - if ($with != strip_tags($orig[0]['with'])) { - $withchanged = true; - $prf = ''; - $lookup = $with; - if (strpos($lookup, '@') === 0) { - $lookup = substr($lookup, 1); - } - $lookup = str_replace('_',' ', $lookup); - if (strpos($lookup, '@') || (strpos($lookup, 'http://'))) { - $newname = $lookup; - $links = @Probe::lrdd($lookup); - if (count($links)) { - foreach ($links as $link) { - if ($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') { - $prf = $link['@attributes']['href']; - } - } - } - } else { - $newname = $lookup; - - $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `uid` = %d LIMIT 1", - DBA::escape($newname), - intval(local_user()) - ); - if (! DBA::isResult($r)) { - $r = q("SELECT * FROM `contact` WHERE `nick` = '%s' AND `uid` = %d LIMIT 1", - DBA::escape($lookup), - intval(local_user()) - ); - } - if (DBA::isResult($r)) { - $prf = $r[0]['url']; - $newname = $r[0]['name']; - } - } - - if ($prf) { - $with = str_replace($lookup, '' . $newname . '', $with); - if (strpos($with, '@') === 0) { - $with = substr($with, 1); - } - } - } else { - $with = $orig[0]['with']; - } - } - - /// @TODO Not flexible enough for later expansion, let's have more OOP here - $sexual = Strings::escapeTags(trim($_POST['sexual'])); - $xmpp = Strings::escapeTags(trim($_POST['xmpp'])); - $homepage = Strings::escapeTags(trim($_POST['homepage'])); - if ((strpos($homepage, 'http') !== 0) && (strlen($homepage))) { - // neither http nor https in URL, add them - $homepage = 'http://'.$homepage; - } - $hometown = Strings::escapeTags(trim($_POST['hometown'])); - $politic = Strings::escapeTags(trim($_POST['politic'])); - $religion = Strings::escapeTags(trim($_POST['religion'])); - - $likes = Strings::escapeHtml(trim($_POST['likes'])); - $dislikes = Strings::escapeHtml(trim($_POST['dislikes'])); - - $about = Strings::escapeHtml(trim($_POST['about'])); - $interest = Strings::escapeHtml(trim($_POST['interest'])); - $contact = Strings::escapeHtml(trim($_POST['contact'])); - $music = Strings::escapeHtml(trim($_POST['music'])); - $book = Strings::escapeHtml(trim($_POST['book'])); - $tv = Strings::escapeHtml(trim($_POST['tv'])); - $film = Strings::escapeHtml(trim($_POST['film'])); - $romance = Strings::escapeHtml(trim($_POST['romance'])); - $work = Strings::escapeHtml(trim($_POST['work'])); - $education = Strings::escapeHtml(trim($_POST['education'])); - - $hide_friends = (($_POST['hide-friends'] == 1) ? 1: 0); - - DI::pConfig()->set(local_user(), 'system', 'detailled_profile', !empty($_POST['detailed_profile']) ? 1: 0); - - $changes = []; - if ($is_default) { - if ($marital != $orig[0]['marital']) { - $changes[] = '[color=#ff0000]♥[/color] ' . DI::l10n()->t('Marital Status'); - } - if ($withchanged) { - $changes[] = '[color=#ff0000]♥[/color] ' . DI::l10n()->t('Romantic Partner'); - } - if ($likes != $orig[0]['likes']) { - $changes[] = DI::l10n()->t('Likes'); - } - if ($dislikes != $orig[0]['dislikes']) { - $changes[] = DI::l10n()->t('Dislikes'); - } - if ($work != $orig[0]['work']) { - $changes[] = DI::l10n()->t('Work/Employment'); - } - if ($religion != $orig[0]['religion']) { - $changes[] = DI::l10n()->t('Religion'); - } - if ($politic != $orig[0]['politic']) { - $changes[] = DI::l10n()->t('Political Views'); - } - if ($gender != $orig[0]['gender']) { - $changes[] = DI::l10n()->t('Gender'); - } - if ($sexual != $orig[0]['sexual']) { - $changes[] = DI::l10n()->t('Sexual Preference'); - } - if ($xmpp != $orig[0]['xmpp']) { - $changes[] = DI::l10n()->t('XMPP'); - } - if ($homepage != $orig[0]['homepage']) { - $changes[] = DI::l10n()->t('Homepage'); - } - if ($interest != $orig[0]['interest']) { - $changes[] = DI::l10n()->t('Interests'); - } - if ($address != $orig[0]['address']) { - $changes[] = DI::l10n()->t('Address'); - // New address not sent in notifications, potential privacy issues - // in case this leaks to unintended recipients. Yes, it's in the public - // profile but that doesn't mean we have to broadcast it to everybody. - } - if ($locality != $orig[0]['locality'] || $region != $orig[0]['region'] - || $country_name != $orig[0]['country-name']) { - $changes[] = DI::l10n()->t('Location'); - } - } - - $r = q("UPDATE `profile` - SET `profile-name` = '%s', - `name` = '%s', - `pdesc` = '%s', - `gender` = '%s', - `dob` = '%s', - `address` = '%s', - `locality` = '%s', - `region` = '%s', - `postal-code` = '%s', - `country-name` = '%s', - `marital` = '%s', - `with` = '%s', - `howlong` = '%s', - `sexual` = '%s', - `xmpp` = '%s', - `homepage` = '%s', - `hometown` = '%s', - `politic` = '%s', - `religion` = '%s', - `pub_keywords` = '%s', - `prv_keywords` = '%s', - `likes` = '%s', - `dislikes` = '%s', - `about` = '%s', - `interest` = '%s', - `contact` = '%s', - `music` = '%s', - `book` = '%s', - `tv` = '%s', - `film` = '%s', - `romance` = '%s', - `work` = '%s', - `education` = '%s', - `hide-friends` = %d - WHERE `id` = %d AND `uid` = %d", - DBA::escape($profile_name), - DBA::escape($name), - DBA::escape($pdesc), - DBA::escape($gender), - DBA::escape($dob), - DBA::escape($address), - DBA::escape($locality), - DBA::escape($region), - DBA::escape($postal_code), - DBA::escape($country_name), - DBA::escape($marital), - DBA::escape($with), - DBA::escape($howlong), - DBA::escape($sexual), - DBA::escape($xmpp), - DBA::escape($homepage), - DBA::escape($hometown), - DBA::escape($politic), - DBA::escape($religion), - DBA::escape($pub_keywords), - DBA::escape($prv_keywords), - DBA::escape($likes), - DBA::escape($dislikes), - DBA::escape($about), - DBA::escape($interest), - DBA::escape($contact), - DBA::escape($music), - DBA::escape($book), - DBA::escape($tv), - DBA::escape($film), - DBA::escape($romance), - DBA::escape($work), - DBA::escape($education), - intval($hide_friends), - intval($a->argv[1]), - intval(local_user()) - ); - - /// @TODO decide to use DBA::isResult() here and check $r - if ($r) { - info(DI::l10n()->t('Profile updated.') . EOL); - } - - if ($is_default) { - if ($namechanged) { - q("UPDATE `user` set `username` = '%s' where `uid` = %d", - DBA::escape($name), - intval(local_user()) - ); - } - - Contact::updateSelfFromUserID(local_user()); - - // Update global directory in background - $url = $_SESSION['my_url']; - if ($url && strlen(DI::config()->get('system', 'directory'))) { - Worker::add(PRIORITY_LOW, "Directory", $url); - } - - Worker::add(PRIORITY_LOW, 'ProfileUpdate', local_user()); - - // Update the global contact for the user - GContact::updateForUser(local_user()); - } - } -} - -function profiles_content(App $a) { - - if (! local_user()) { - notice(DI::l10n()->t('Permission denied.') . EOL); - return Login::form(); - } - - $o = ''; - - if (($a->argc > 1) && (intval($a->argv[1]))) { - $r = q("SELECT * FROM `profile` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($a->argv[1]), - intval(local_user()) - ); - if (! DBA::isResult($r)) { - notice(DI::l10n()->t('Profile not found.') . EOL); - return; - } - - DI::page()['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('profed_head.tpl'), [ - '$baseurl' => DI::baseUrl()->get(true), - ]); - - $opt_tpl = Renderer::getMarkupTemplate("profile-hide-friends.tpl"); - $hide_friends = Renderer::replaceMacros($opt_tpl,[ - '$yesno' => [ - 'hide-friends', //Name - DI::l10n()->t('Hide contacts and friends:'), //Label - !!$r[0]['hide-friends'], //Value - '', //Help string - [DI::l10n()->t('No'), DI::l10n()->t('Yes')] //Off - On strings - ], - '$desc' => DI::l10n()->t('Hide your contact/friend list from viewers of this profile?'), - '$yes_str' => DI::l10n()->t('Yes'), - '$no_str' => DI::l10n()->t('No'), - '$yes_selected' => (($r[0]['hide-friends']) ? " checked=\"checked\" " : ""), - '$no_selected' => (($r[0]['hide-friends'] == 0) ? " checked=\"checked\" " : "") - ]); - - $personal_account = !(in_array($a->user["page-flags"], - [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP])); - - $detailed_profile = (DI::pConfig()->get(local_user(), 'system', 'detailled_profile') AND $personal_account); - - $is_default = (($r[0]['is-default']) ? 1 : 0); - $tpl = Renderer::getMarkupTemplate("profile_edit.tpl"); - $o .= Renderer::replaceMacros($tpl, [ - '$personal_account' => $personal_account, - '$detailled_profile' => $detailed_profile, - - '$details' => [ - 'detailed_profile', //Name - DI::l10n()->t('Show more profile fields:'), //Label - $detailed_profile, //Value - '', //Help string - [DI::l10n()->t('No'), DI::l10n()->t('Yes')] //Off - On strings - ], - - '$multi_profiles' => Feature::isEnabled(local_user(), 'multi_profiles'), - '$form_security_token' => BaseModule::getFormSecurityToken("profile_edit"), - '$form_security_token_photo' => BaseModule::getFormSecurityToken("profile_photo"), - '$profile_clone_link' => ((Feature::isEnabled(local_user(), 'multi_profiles')) ? 'profiles/clone/' . $r[0]['id'] . '?t=' . BaseModule::getFormSecurityToken("profile_clone") : ""), - '$profile_drop_link' => 'profiles/drop/' . $r[0]['id'] . '?t=' . BaseModule::getFormSecurityToken("profile_drop"), - - '$profile_action' => DI::l10n()->t('Profile Actions'), - '$banner' => DI::l10n()->t('Edit Profile Details'), - '$submit' => DI::l10n()->t('Submit'), - '$profpic' => DI::l10n()->t('Change Profile Photo'), - '$profpiclink' => '/photos/' . $a->user['nickname'], - '$viewprof' => DI::l10n()->t('View this profile'), - '$viewallprof' => DI::l10n()->t('View all profiles'), - '$editvis' => DI::l10n()->t('Edit visibility'), - '$cr_prof' => DI::l10n()->t('Create a new profile using these settings'), - '$cl_prof' => DI::l10n()->t('Clone this profile'), - '$del_prof' => DI::l10n()->t('Delete this profile'), - - '$lbl_basic_section' => DI::l10n()->t('Basic information'), - '$lbl_picture_section' => DI::l10n()->t('Profile picture'), - '$lbl_location_section' => DI::l10n()->t('Location'), - '$lbl_preferences_section' => DI::l10n()->t('Preferences'), - '$lbl_status_section' => DI::l10n()->t('Status information'), - '$lbl_about_section' => DI::l10n()->t('Additional information'), - '$lbl_interests_section' => DI::l10n()->t('Interests'), - '$lbl_personal_section' => DI::l10n()->t('Personal'), - '$lbl_relation_section' => DI::l10n()->t('Relation'), - '$lbl_miscellaneous_section' => DI::l10n()->t('Miscellaneous'), - - '$lbl_profile_photo' => DI::l10n()->t('Upload Profile Photo'), - '$lbl_gender' => DI::l10n()->t('Your Gender:'), - '$lbl_marital' => DI::l10n()->t(' Marital Status:'), - '$lbl_sexual' => DI::l10n()->t('Sexual Preference:'), - '$lbl_ex2' => DI::l10n()->t('Example: fishing photography software'), - - '$disabled' => (($is_default) ? 'onclick="return false;" style="color: #BBBBFF;"' : ''), - '$baseurl' => DI::baseUrl()->get(true), - '$profile_id' => $r[0]['id'], - '$profile_name' => ['profile_name', DI::l10n()->t('Profile Name:'), $r[0]['profile-name'], DI::l10n()->t('Required'), '*'], - '$is_default' => $is_default, - '$default' => (($is_default) ? '

' . DI::l10n()->t('This is your public profile.
It may be visible to anybody using the internet.') . '

' : ""), - '$name' => ['name', DI::l10n()->t('Your Full Name:'), $r[0]['name']], - '$pdesc' => ['pdesc', DI::l10n()->t('Title/Description:'), $r[0]['pdesc']], - '$dob' => Temporal::getDateofBirthField($r[0]['dob'], $a->user['timezone']), - '$hide_friends' => $hide_friends, - '$address' => ['address', DI::l10n()->t('Street Address:'), $r[0]['address']], - '$locality' => ['locality', DI::l10n()->t('Locality/City:'), $r[0]['locality']], - '$region' => ['region', DI::l10n()->t('Region/State:'), $r[0]['region']], - '$postal_code' => ['postal_code', DI::l10n()->t('Postal/Zip Code:'), $r[0]['postal-code']], - '$country_name' => ['country_name', DI::l10n()->t('Country:'), $r[0]['country-name']], - '$age' => ((intval($r[0]['dob'])) ? '(' . DI::l10n()->t('Age: ') . DI::l10n()->tt('%d year old', '%d years old', Temporal::getAgeByTimezone($r[0]['dob'], $a->user['timezone'])) . ')' : ''), - '$gender' => DI::l10n()->t(ContactSelector::gender($r[0]['gender'])), - '$marital' => ['selector' => ContactSelector::maritalStatus($r[0]['marital']), 'value' => DI::l10n()->t($r[0]['marital'])], - '$with' => ['with', DI::l10n()->t("Who: \x28if applicable\x29"), strip_tags($r[0]['with']), DI::l10n()->t('Examples: cathy123, Cathy Williams, cathy@example.com')], - '$howlong' => ['howlong', DI::l10n()->t('Since [date]:'), ($r[0]['howlong'] <= DBA::NULL_DATETIME ? '' : DateTimeFormat::local($r[0]['howlong']))], - '$sexual' => ['selector' => ContactSelector::sexualPreference($r[0]['sexual']), 'value' => DI::l10n()->t($r[0]['sexual'])], - '$about' => ['about', DI::l10n()->t('Tell us about yourself...'), $r[0]['about']], - '$xmpp' => ['xmpp', DI::l10n()->t("XMPP \x28Jabber\x29 address:"), $r[0]['xmpp'], DI::l10n()->t("The XMPP address will be propagated to your contacts so that they can follow you.")], - '$homepage' => ['homepage', DI::l10n()->t('Homepage URL:'), $r[0]['homepage']], - '$hometown' => ['hometown', DI::l10n()->t('Hometown:'), $r[0]['hometown']], - '$politic' => ['politic', DI::l10n()->t('Political Views:'), $r[0]['politic']], - '$religion' => ['religion', DI::l10n()->t('Religious Views:'), $r[0]['religion']], - '$pub_keywords' => ['pub_keywords', DI::l10n()->t('Public Keywords:'), $r[0]['pub_keywords'], DI::l10n()->t("\x28Used for suggesting potential friends, can be seen by others\x29")], - '$prv_keywords' => ['prv_keywords', DI::l10n()->t('Private Keywords:'), $r[0]['prv_keywords'], DI::l10n()->t("\x28Used for searching profiles, never shown to others\x29")], - '$likes' => ['likes', DI::l10n()->t('Likes:'), $r[0]['likes']], - '$dislikes' => ['dislikes', DI::l10n()->t('Dislikes:'), $r[0]['dislikes']], - '$music' => ['music', DI::l10n()->t('Musical interests'), $r[0]['music']], - '$book' => ['book', DI::l10n()->t('Books, literature'), $r[0]['book']], - '$tv' => ['tv', DI::l10n()->t('Television'), $r[0]['tv']], - '$film' => ['film', DI::l10n()->t('Film/dance/culture/entertainment'), $r[0]['film']], - '$interest' => ['interest', DI::l10n()->t('Hobbies/Interests'), $r[0]['interest']], - '$romance' => ['romance', DI::l10n()->t('Love/romance'), $r[0]['romance']], - '$work' => ['work', DI::l10n()->t('Work/employment'), $r[0]['work']], - '$education' => ['education', DI::l10n()->t('School/education'), $r[0]['education']], - '$contact' => ['contact', DI::l10n()->t('Contact information and Social Networks'), $r[0]['contact']], - ]); - - $arr = ['profile' => $r[0], 'entry' => $o]; - Hook::callAll('profile_edit', $arr); - - return $o; - } else { - // If we don't support multi profiles, don't display this list. - if (!Feature::isEnabled(local_user(), 'multi_profiles')) { - $r = q("SELECT * FROM `profile` WHERE `uid` = %d AND `is-default`=1", - local_user() - ); - if (DBA::isResult($r)) { - //Go to the default profile. - DI::baseUrl()->redirect('profiles/' . $r[0]['id']); - } - } - - $r = q("SELECT * FROM `profile` WHERE `uid` = %d", - local_user()); - - if (DBA::isResult($r)) { - - $tpl = Renderer::getMarkupTemplate('profile_entry.tpl'); - - $profiles = ''; - foreach ($r as $rr) { - $profiles .= Renderer::replaceMacros($tpl, [ - '$photo' => DI::baseUrl()->remove($rr['thumb']), - '$id' => $rr['id'], - '$alt' => DI::l10n()->t('Profile Image'), - '$profile_name' => $rr['profile-name'], - '$visible' => (($rr['is-default']) ? '' . DI::l10n()->t('visible to everybody') . '' - : '' . DI::l10n()->t('Edit visibility') . '') - ]); - } - - $tpl_header = Renderer::getMarkupTemplate('profile_listing_header.tpl'); - $o .= Renderer::replaceMacros($tpl_header,[ - '$header' => DI::l10n()->t('Edit/Manage Profiles'), - '$chg_photo' => DI::l10n()->t('Change profile photo'), - '$cr_new' => DI::l10n()->t('Create New Profile'), - '$cr_new_link' => 'profiles/new?t=' . BaseModule::getFormSecurityToken("profile_new"), - '$profiles' => $profiles - ]); - } - return $o; - } - -} diff --git a/mod/settings.php b/mod/settings.php index 00991d8919..a07ad24ccd 100644 --- a/mod/settings.php +++ b/mod/settings.php @@ -73,9 +73,9 @@ function settings_init(App $a) ]; $tabs[] = [ - 'label' => DI::l10n()->t('Profiles'), - 'url' => 'profiles', - 'selected' => (($a->argc == 1) && ($a->argv[0] === 'profiles')?'active':''), + 'label' => DI::l10n()->t('Profile'), + 'url' => 'settings/profile', + 'selected' => (($a->argc > 1) && ($a->argv[1] === 'profile')?'active':''), 'accesskey' => 'p', ]; diff --git a/mod/update_profile.php b/mod/update_profile.php deleted file mode 100644 index 348a384c2e..0000000000 --- a/mod/update_profile.php +++ /dev/null @@ -1,49 +0,0 @@ -\r\n"; - - // We can remove this hack once Internet Explorer recognises HTML5 natively - echo "
"; - - /** - * Grab the page inner contents by calling the content function from the profile module directly, - * but move any image src attributes to another attribute name. This is because - * some browsers will prefetch all the images for the page even if we don't need them. - * The only ones we need to fetch are those for new page additions, which we'll discover - * on the client side and then swap the image back. - */ - - $text = Profile::content([], $profile_uid); - - if (DI::pConfig()->get(local_user(), "system", "bandwidth_saver")) { - $replace = "
" . DI::l10n()->t("[Embedded content - reload page to view]") . "
"; - $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; - $text = preg_replace($pattern, $replace, $text); - } - - // reportedly some versions of MSIE don't handle tabs in XMLHttpRequest documents very well - echo str_replace("\t", " ", $text); - echo "
"; - echo "\r\n"; - exit(); -} \ No newline at end of file diff --git a/src/Model/Profile.php b/src/Model/Profile.php index b993562cec..b77bfa8e1d 100644 --- a/src/Model/Profile.php +++ b/src/Model/Profile.php @@ -202,7 +202,7 @@ class Profile if (local_user() && local_user() == $a->profile['uid'] && $profiledata) { DI::page()['aside'] .= Renderer::replaceMacros( - Renderer::getMarkupTemplate('profile_edlink.tpl'), + Renderer::getMarkupTemplate('settings/profile/link.tpl'), [ '$editprofile' => DI::l10n()->t('Edit profile'), '$profid' => $a->profile['id'] @@ -388,40 +388,12 @@ class Profile // show edit profile to yourself if (!$is_contact && $local_user_is_self) { - if (Feature::isEnabled(local_user(), 'multi_profiles')) { - $profile['edit'] = [DI::baseUrl() . '/profiles', DI::l10n()->t('Profiles'), '', DI::l10n()->t('Manage/edit profiles')]; - $r = q( - "SELECT * FROM `profile` WHERE `uid` = %d", - local_user() - ); - - $profile['menu'] = [ - 'chg_photo' => DI::l10n()->t('Change profile photo'), - 'cr_new' => DI::l10n()->t('Create New Profile'), - 'entries' => [], - ]; - - if (DBA::isResult($r)) { - foreach ($r as $rr) { - $profile['menu']['entries'][] = [ - 'photo' => $rr['thumb'], - 'id' => $rr['id'], - 'alt' => DI::l10n()->t('Profile Image'), - 'profile_name' => $rr['profile-name'], - 'isdefault' => $rr['is-default'], - 'visibile_to_everybody' => DI::l10n()->t('visible to everybody'), - 'edit_visibility' => DI::l10n()->t('Edit visibility'), - ]; - } - } - } else { - $profile['edit'] = [DI::baseUrl() . '/profiles/' . $profile['id'], DI::l10n()->t('Edit profile'), '', DI::l10n()->t('Edit profile')]; - $profile['menu'] = [ - 'chg_photo' => DI::l10n()->t('Change profile photo'), - 'cr_new' => null, - 'entries' => [], - ]; - } + $profile['edit'] = [DI::baseUrl() . '/settings/profile', DI::l10n()->t('Edit profile'), '', DI::l10n()->t('Edit profile')]; + $profile['menu'] = [ + 'chg_photo' => DI::l10n()->t('Change profile photo'), + 'cr_new' => null, + 'entries' => [], + ]; } // Fetch the account type @@ -870,7 +842,7 @@ class Profile } if ($a->profile['uid'] == local_user()) { - $profile['edit'] = [DI::baseUrl() . '/profiles/' . $a->profile['id'], DI::l10n()->t('Edit profile'), '', DI::l10n()->t('Edit profile')]; + $profile['edit'] = [DI::baseUrl() . '/settings/profile', DI::l10n()->t('Edit profile'), '', DI::l10n()->t('Edit profile')]; } $tpl = Renderer::getMarkupTemplate('profile/advanced.tpl'); @@ -902,22 +874,22 @@ class Profile $baseProfileUrl = DI::baseUrl() . '/profile/' . $nickname; $tabs = [ - [ - 'label' => DI::l10n()->t('Status'), - 'url' => $baseProfileUrl, - 'sel' => !$current ? 'active' : '', - 'title' => DI::l10n()->t('Status Messages and Posts'), - 'id' => 'status-tab', - 'accesskey' => 'm', - ], [ 'label' => DI::l10n()->t('Profile'), - 'url' => $baseProfileUrl . '/?tab=profile', + 'url' => $baseProfileUrl, 'sel' => $current == 'profile' ? 'active' : '', 'title' => DI::l10n()->t('Profile Details'), 'id' => 'profile-tab', 'accesskey' => 'r', ], + [ + 'label' => DI::l10n()->t('Status'), + 'url' => $baseProfileUrl . '/status', + 'sel' => $current == 'status' ? 'active' : '', + 'title' => DI::l10n()->t('Status Messages and Posts'), + 'id' => 'status-tab', + 'accesskey' => 'm', + ], [ 'label' => DI::l10n()->t('Photos'), 'url' => DI::baseUrl() . '/photos/' . $nickname, @@ -970,17 +942,7 @@ class Profile ]; } - if (!empty($_SESSION['new_member']) && $is_owner) { - $tabs[] = [ - 'label' => DI::l10n()->t('Tips for New Members'), - 'url' => DI::baseUrl() . '/newmember', - 'sel' => false, - 'title' => DI::l10n()->t('Tips for New Members'), - 'id' => 'newmember-tab', - ]; - } - - if ($is_owner || empty($a->profile['hide-friends'])) { + if (empty($a->profile['hide-friends'])) { $tabs[] = [ 'label' => DI::l10n()->t('Contacts'), 'url' => $baseProfileUrl . '/contacts', @@ -991,7 +953,18 @@ class Profile ]; } + if (!empty($_SESSION['new_member']) && $is_owner) { + $tabs[] = [ + 'label' => DI::l10n()->t('Tips for New Members'), + 'url' => DI::baseUrl() . '/newmember', + 'sel' => false, + 'title' => DI::l10n()->t('Tips for New Members'), + 'id' => 'newmember-tab', + ]; + } + $arr = ['is_owner' => $is_owner, 'nickname' => $nickname, 'tab' => $current, 'tabs' => $tabs]; + Hook::callAll('profile_tabs', $arr); $tpl = Renderer::getMarkupTemplate('common_tabs.tpl'); diff --git a/src/Module/BaseSettingsModule.php b/src/Module/BaseSettingsModule.php index 2f51dde645..225f5ed4ae 100644 --- a/src/Module/BaseSettingsModule.php +++ b/src/Module/BaseSettingsModule.php @@ -35,9 +35,9 @@ class BaseSettingsModule extends BaseModule ]; $tabs[] = [ - 'label' => DI::l10n()->t('Profiles'), - 'url' => 'profiles', - 'selected' => (($a->argc == 1) && ($a->argv[0] === 'profiles') ? 'active' : ''), + 'label' => DI::l10n()->t('Profile'), + 'url' => 'settings/profile', + 'selected' => (($a->argc > 1) && ($a->argv[1] === 'profile') ? 'active' : ''), 'accesskey' => 'p', ]; diff --git a/src/Module/Profile.php b/src/Module/Profile.php deleted file mode 100644 index e3ae7b3f57..0000000000 --- a/src/Module/Profile.php +++ /dev/null @@ -1,361 +0,0 @@ -argc < 2) { - throw new \Friendica\Network\HTTPException\BadRequestException(); - } - - self::$which = filter_var($a->argv[1], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK); - - // @TODO: Replace with parameter from router - if (local_user() && $a->argc > 2 && $a->argv[2] === 'view') { - self::$which = $a->user['nickname']; - self::$profile = filter_var($a->argv[1], FILTER_SANITIZE_NUMBER_INT); - } - } - - public static function rawContent(array $parameters = []) - { - if (ActivityPub::isRequest()) { - $user = DBA::selectFirst('user', ['uid'], ['nickname' => self::$which]); - if (DBA::isResult($user)) { - // The function returns an empty array when the account is removed, expired or blocked - $data = ActivityPub\Transmitter::getProfile($user['uid']); - if (!empty($data)) { - System::jsonExit($data, 'application/activity+json'); - } - } - - if (DBA::exists('userd', ['username' => self::$which])) { - // Known deleted user - $data = ActivityPub\Transmitter::getDeletedUser(self::$which); - - System::jsonError(410, $data); - } else { - // Any other case (unknown, blocked, unverified, expired, no profile, no self contact) - System::jsonError(404, []); - } - } - } - - public static function content(array $parameters = [], $update = 0) - { - $a = DI::app(); - - if (!$update) { - ProfileModel::load($a, self::$which, self::$profile); - - $page = DI::page(); - - $page['htmlhead'] .= "\n"; - - $blocked = !local_user() && !Session::getRemoteContactID($a->profile['uid']) && DI::config()->get('system', 'block_public'); - $userblock = !local_user() && !Session::getRemoteContactID($a->profile['uid']) && $a->profile['hidewall']; - - if (!empty($a->profile['page-flags']) && $a->profile['page-flags'] == User::PAGE_FLAGS_COMMUNITY) { - $page['htmlhead'] .= '' . "\n"; - } - - if (!empty($a->profile['openidserver'])) { - $page['htmlhead'] .= '' . "\n"; - } - - if (!empty($a->profile['openid'])) { - $delegate = strstr($a->profile['openid'], '://') ? $a->profile['openid'] : 'https://' . $a->profile['openid']; - $page['htmlhead'] .= '' . "\n"; - } - - // site block - if (!$blocked && !$userblock) { - $keywords = str_replace(['#', ',', ' ', ',,'], ['', ' ', ',', ','], $a->profile['pub_keywords'] ?? ''); - if (strlen($keywords)) { - $page['htmlhead'] .= '' . "\n"; - } - } - - $page['htmlhead'] .= '' . "\n"; - - if (!$a->profile['net-publish'] || $a->profile['hidewall']) { - $page['htmlhead'] .= '' . "\n"; - } - - $page['htmlhead'] .= '' . "\n"; - $page['htmlhead'] .= '' . "\n"; - $page['htmlhead'] .= '' . "\n"; - $page['htmlhead'] .= '' . "\n"; - $uri = urlencode('acct:' . $a->profile['nickname'] . '@' . DI::baseUrl()->getHostname() . (DI::baseUrl()->getUrlPath() ? '/' . DI::baseUrl()->getUrlPath() : '')); - $page['htmlhead'] .= '' . "\n"; - header('Link: <' . DI::baseUrl() . '/xrd/?uri=' . $uri . '>; rel="lrdd"; type="application/xrd+xml"', false); - - $dfrn_pages = ['request', 'confirm', 'notify', 'poll']; - foreach ($dfrn_pages as $dfrn) { - $page['htmlhead'] .= '' . "\n"; - } - $page['htmlhead'] .= '' . "\n"; - } - - $category = $datequery = $datequery2 = ''; - - if ($a->argc > 2) { - for ($x = 2; $x < $a->argc; $x ++) { - if (DI::dtFormat()->isYearMonth($a->argv[$x])) { - if ($datequery) { - $datequery2 = Strings::escapeHtml($a->argv[$x]); - } else { - $datequery = Strings::escapeHtml($a->argv[$x]); - } - } else { - $category = $a->argv[$x]; - } - } - } - - if (empty($category)) { - $category = $_GET['category'] ?? ''; - } - - $hashtags = $_GET['tag'] ?? ''; - - if (DI::config()->get('system', 'block_public') && !local_user() && !Session::getRemoteContactID($a->profile['uid'])) { - return Login::form(); - } - - $o = ''; - - if ($update) { - // Ensure we've got a profile owner if updating. - $a->profile['uid'] = $update; - } elseif ($a->profile['uid'] == local_user()) { - Nav::setSelected('home'); - } - - $remote_contact = Session::getRemoteContactID($a->profile['uid']); - $is_owner = local_user() == $a->profile['uid']; - $last_updated_key = "profile:" . $a->profile['uid'] . ":" . local_user() . ":" . $remote_contact; - - if (!empty($a->profile['hidewall']) && !$is_owner && !$remote_contact) { - notice(DI::l10n()->t('Access to this profile has been restricted.') . EOL); - return ''; - } - - if (!$update) { - $tab = Strings::escapeTags(trim($_GET['tab'] ?? '')); - - $o .= ProfileModel::getTabs($a, $tab, $is_owner, $a->profile['nickname']); - - if ($tab === 'profile') { - $o .= ProfileModel::getAdvanced($a); - Hook::callAll('profile_advanced', $o); - return $o; - } - - $o .= Widget::commonFriendsVisitor($a->profile['uid']); - - $commpage = $a->profile['page-flags'] == User::PAGE_FLAGS_COMMUNITY; - $commvisitor = $commpage && $remote_contact; - - DI::page()['aside'] .= Widget::postedByYear(DI::baseUrl()->get(true) . '/profile/' . $a->profile['nickname'], $a->profile['uid'] ?? 0, true); - DI::page()['aside'] .= Widget::categories(DI::baseUrl()->get(true) . '/profile/' . $a->profile['nickname'], XML::escape($category)); - DI::page()['aside'] .= Widget::tagCloud(); - - if (Security::canWriteToUserWall($a->profile['uid'])) { - $x = [ - 'is_owner' => $is_owner, - 'allow_location' => ($is_owner || $commvisitor) && $a->profile['allow_location'], - 'default_location' => $is_owner ? $a->user['default-location'] : '', - 'nickname' => $a->profile['nickname'], - 'lockstate' => is_array($a->user) - && (strlen($a->user['allow_cid']) - || strlen($a->user['allow_gid']) - || strlen($a->user['deny_cid']) - || strlen($a->user['deny_gid']) - ) ? 'lock' : 'unlock', - 'acl' => $is_owner ? ACL::getFullSelectorHTML(DI::page(), $a->user, true) : '', - 'bang' => '', - 'visitor' => $is_owner || $commvisitor ? 'block' : 'none', - 'profile_uid' => $a->profile['uid'], - ]; - - $o .= status_editor($a, $x); - } - } - - // Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched his/her groups - $sql_extra = Item::getPermissionsSQLByUserId($a->profile['uid']); - $sql_extra2 = ''; - - $last_updated_array = Session::get('last_updated', []); - - if ($update) { - $last_updated = $last_updated_array[$last_updated_key] ?? 0; - - // If the page user is the owner of the page we should query for unseen - // items. Otherwise use a timestamp of the last succesful update request. - if ($is_owner || !$last_updated) { - $sql_extra4 = " AND `item`.`unseen`"; - } else { - $gmupdate = gmdate(DateTimeFormat::MYSQL, $last_updated); - $sql_extra4 = " AND `item`.`received` > '" . $gmupdate . "'"; - } - - $items_stmt = DBA::p( - "SELECT DISTINCT(`parent-uri`) AS `uri`, `item`.`created` - FROM `item` - INNER JOIN `contact` - ON `contact`.`id` = `item`.`contact-id` - AND NOT `contact`.`blocked` - AND NOT `contact`.`pending` - WHERE `item`.`uid` = ? - AND `item`.`visible` - AND (NOT `item`.`deleted` OR `item`.`gravity` = ?) - AND NOT `item`.`moderated` - AND `item`.`wall` - $sql_extra4 - $sql_extra - ORDER BY `item`.`received` DESC", - $a->profile['uid'], - GRAVITY_ACTIVITY - ); - - if (!DBA::isResult($items_stmt)) { - return ''; - } - - $pager = new Pager(DI::args()->getQueryString()); - } else { - $sql_post_table = ""; - - if (!empty($category)) { - $sql_post_table = sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", - DBA::escape(Strings::protectSprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($a->profile['uid'])); - } - - if (!empty($hashtags)) { - $sql_post_table .= sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", - DBA::escape(Strings::protectSprintf($hashtags)), intval(TERM_OBJ_POST), intval(TERM_HASHTAG), intval($a->profile['uid'])); - } - - if (!empty($datequery)) { - $sql_extra2 .= Strings::protectSprintf(sprintf(" AND `thread`.`received` <= '%s' ", DBA::escape(DateTimeFormat::convert($datequery, 'UTC', date_default_timezone_get())))); - } - if (!empty($datequery2)) { - $sql_extra2 .= Strings::protectSprintf(sprintf(" AND `thread`.`received` >= '%s' ", DBA::escape(DateTimeFormat::convert($datequery2, 'UTC', date_default_timezone_get())))); - } - - // Does the profile page belong to a forum? - // If not then we can improve the performance with an additional condition - $condition = ['uid' => $a->profile['uid'], 'page-flags' => [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]]; - if (!DBA::exists('user', $condition)) { - $sql_extra3 = sprintf(" AND `thread`.`contact-id` = %d ", intval(intval($a->profile['contact_id']))); - } else { - $sql_extra3 = ""; - } - - // check if we serve a mobile device and get the user settings - // accordingly - if (DI::mode()->isMobile()) { - $itemspage_network = DI::pConfig()->get(local_user(), 'system', 'itemspage_mobile_network', 10); - } else { - $itemspage_network = DI::pConfig()->get(local_user(), 'system', 'itemspage_network', 20); - } - - // now that we have the user settings, see if the theme forces - // a maximum item number which is lower then the user choice - if (($a->force_max_items > 0) && ($a->force_max_items < $itemspage_network)) { - $itemspage_network = $a->force_max_items; - } - - $pager = new Pager(DI::args()->getQueryString(), $itemspage_network); - - $pager_sql = sprintf(" LIMIT %d, %d ", $pager->getStart(), $pager->getItemsPerPage()); - - $items_stmt = DBA::p( - "SELECT `item`.`uri` - FROM `thread` - STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid` - $sql_post_table - STRAIGHT_JOIN `contact` - ON `contact`.`id` = `thread`.`contact-id` - AND NOT `contact`.`blocked` - AND NOT `contact`.`pending` - WHERE `thread`.`uid` = ? - AND `thread`.`visible` - AND NOT `thread`.`deleted` - AND NOT `thread`.`moderated` - AND `thread`.`wall` - $sql_extra3 - $sql_extra - $sql_extra2 - ORDER BY `thread`.`received` DESC - $pager_sql", - $a->profile['uid'] - ); - } - - // Set a time stamp for this page. We will make use of it when we - // search for new items (update routine) - $last_updated_array[$last_updated_key] = time(); - Session::set('last_updated', $last_updated_array); - - if ($is_owner && !$update && !DI::config()->get('theme', 'hide_eventlist')) { - $o .= ProfileModel::getBirthdays(); - $o .= ProfileModel::getEventsReminderHTML(); - } - - if ($is_owner) { - $unseen = Item::exists(['wall' => true, 'unseen' => true, 'uid' => local_user()]); - if ($unseen) { - Item::update(['unseen' => false], ['wall' => true, 'unseen' => true, 'uid' => local_user()]); - } - } - - $items = DBA::toArray($items_stmt); - - if ($pager->getStart() == 0 && !empty($a->profile['uid'])) { - $pinned_items = Item::selectPinned($a->profile['uid'], ['uri', 'pinned'], ['true' . $sql_extra]); - $pinned = Item::inArray($pinned_items); - $items = array_merge($items, $pinned); - } - - $o .= conversation($a, $items, $pager, 'profile', $update, false, 'pinned_received', $a->profile['uid']); - - if (!$update) { - $o .= $pager->renderMinimal(count($items)); - } - - return $o; - } -} diff --git a/src/Module/Profile/Index.php b/src/Module/Profile/Index.php new file mode 100644 index 0000000000..27d5047d1b --- /dev/null +++ b/src/Module/Profile/Index.php @@ -0,0 +1,121 @@ + $parameters['nickname']]); + if (DBA::isResult($user)) { + // The function returns an empty array when the account is removed, expired or blocked + $data = ActivityPub\Transmitter::getProfile($user['uid']); + if (!empty($data)) { + System::jsonExit($data, 'application/activity+json'); + } + } + + if (DBA::exists('userd', ['username' => $parameters['nickname']])) { + // Known deleted user + $data = ActivityPub\Transmitter::getDeletedUser($parameters['nickname']); + + System::jsonError(410, $data); + } else { + // Any other case (unknown, blocked, nverified, expired, no profile, no self contact) + System::jsonError(404, []); + } + } + } + + public static function content(array $parameters = []) + { + $a = DI::app(); + + if (DI::config()->get('system', 'block_public') && !local_user() && !Session::getRemoteContactID($a->profile['profile_uid'])) { + return Login::form(); + } + + ProfileModel::load($a, $parameters['nickname']); + + DI::page()['htmlhead'] .= "\n"; + + $blocked = !local_user() && !Session::getRemoteContactID($a->profile['profile_uid']) && DI::config()->get('system', 'block_public'); + $userblock = !local_user() && !Session::getRemoteContactID($a->profile['profile_uid']) && $a->profile['hidewall']; + + if (!empty($a->profile['page-flags']) && $a->profile['page-flags'] == User::PAGE_FLAGS_COMMUNITY) { + DI::page()['htmlhead'] .= '' . "\n"; + } + + if (!empty($a->profile['openidserver'])) { + DI::page()['htmlhead'] .= '' . "\n"; + } + + if (!empty($a->profile['openid'])) { + $delegate = strstr($a->profile['openid'], '://') ? $a->profile['openid'] : 'https://' . $a->profile['openid']; + DI::page()['htmlhead'] .= '' . "\n"; + } + + // site block + if (!$blocked && !$userblock) { + $keywords = str_replace(['#', ',', ' ', ',,'], ['', ' ', ',', ','], $a->profile['pub_keywords'] ?? ''); + if (strlen($keywords)) { + DI::page()['htmlhead'] .= '' . "\n"; + } + } + + DI::page()['htmlhead'] .= '' . "\n"; + + if (!$a->profile['net-publish'] || $a->profile['hidewall']) { + DI::page()['htmlhead'] .= '' . "\n"; + } + + DI::page()['htmlhead'] .= '' . "\n"; + DI::page()['htmlhead'] .= '' . "\n"; + DI::page()['htmlhead'] .= '' . "\n"; + DI::page()['htmlhead'] .= '' . "\n"; + $uri = urlencode('acct:' . $a->profile['nickname'] . '@' . DI::baseUrl()->getHostname() . (DI::baseUrl()->getUrlPath() ? '/' . DI::baseUrl()->getUrlPath() : '')); + DI::page()['htmlhead'] .= '' . "\n"; + header('Link: <' . DI::baseUrl() . '/xrd/?uri=' . $uri . '>; rel="lrdd"; type="application/xrd+xml"', false); + + $dfrn_pages = ['request', 'confirm', 'notify', 'poll']; + foreach ($dfrn_pages as $dfrn) { + DI::page()['htmlhead'] .= '' . "\n"; + } + DI::page()['htmlhead'] .= '' . "\n"; + + $o = ''; + + Nav::setSelected('home'); + + $remote_contact = Session::getRemoteContactID($a->profile['profile_uid']); + $is_owner = local_user() == $a->profile['profile_uid']; + + if (!empty($a->profile['hidewall']) && !$is_owner && !$remote_contact) { + notice(DI::l10n()->t('Access to this profile has been restricted.')); + return ''; + } + + $o .= ProfileModel::getTabs($a, 'profile', $is_owner, $a->profile['nickname']); + + $o .= ProfileModel::getAdvanced($a); + + Hook::callAll('profile_advanced', $o); + + return $o; + } +} diff --git a/src/Module/Profile/Status.php b/src/Module/Profile/Status.php new file mode 100644 index 0000000000..56247b20e1 --- /dev/null +++ b/src/Module/Profile/Status.php @@ -0,0 +1,217 @@ +profile['net-publish'] || $a->profile['hidewall']) { + DI::page()['htmlhead'] .= '' . "\n"; + } + + DI::page()['htmlhead'] .= '' . "\n"; + DI::page()['htmlhead'] .= '' . "\n"; + DI::page()['htmlhead'] .= '' . "\n"; + DI::page()['htmlhead'] .= '' . "\n"; + + $category = $datequery = $datequery2 = ''; + + $dtFormat = DI::dtFormat(); + + if ($args->getArgc() > 2) { + for ($x = 2; $x < $args->getArgc(); $x++) { + if ($dtFormat->isYearMonth($args->get($x))) { + if ($datequery) { + $datequery2 = Strings::escapeHtml($args->get($x)); + } else { + $datequery = Strings::escapeHtml($args->get($x)); + } + } else { + $category = $args->get($x); + } + } + } + + if (empty($category)) { + $category = $_GET['category'] ?? ''; + } + + $hashtags = $_GET['tag'] ?? ''; + + if (DI::config()->get('system', 'block_public') && !local_user() && !Session::getRemoteContactID($a->profile['profile_uid'])) { + return Login::form(); + } + + $o = ''; + + if ($a->profile['profile_uid'] == local_user()) { + Nav::setSelected('home'); + } + + $remote_contact = Session::getRemoteContactID($a->profile['profile_uid']); + $is_owner = local_user() == $a->profile['profile_uid']; + $last_updated_key = "profile:" . $a->profile['profile_uid'] . ":" . local_user() . ":" . $remote_contact; + + if (!empty($a->profile['hidewall']) && !$is_owner && !$remote_contact) { + notice(DI::l10n()->t('Access to this profile has been restricted.') . EOL); + return ''; + } + + $o .= ProfileModel::getTabs($a, 'status', $is_owner, $a->profile['nickname']); + + $o .= Widget::commonFriendsVisitor($a->profile['profile_uid']); + + $commpage = $a->profile['page-flags'] == User::PAGE_FLAGS_COMMUNITY; + $commvisitor = $commpage && $remote_contact; + + DI::page()['aside'] .= Widget::postedByYear(DI::baseUrl() . '/profile/' . $a->profile['nickname'] . '/status', $a->profile['profile_uid'] ?? 0, true); + DI::page()['aside'] .= Widget::categories(DI::baseUrl() . '/profile/' . $a->profile['nickname'] . '/status', XML::escape($category)); + DI::page()['aside'] .= Widget::tagCloud(); + + if (Security::canWriteToUserWall($a->profile['profile_uid'])) { + $x = [ + 'is_owner' => $is_owner, + 'allow_location' => ($is_owner || $commvisitor) && $a->profile['allow_location'], + 'default_location' => $is_owner ? $a->user['default-location'] : '', + 'nickname' => $a->profile['nickname'], + 'lockstate' => is_array($a->user) + && (strlen($a->user['allow_cid']) + || strlen($a->user['allow_gid']) + || strlen($a->user['deny_cid']) + || strlen($a->user['deny_gid']) + ) ? 'lock' : 'unlock', + 'acl' => $is_owner ? ACL::getFullSelectorHTML(DI::page(), $a->user, true) : '', + 'bang' => '', + 'visitor' => $is_owner || $commvisitor ? 'block' : 'none', + 'profile_uid' => $a->profile['profile_uid'], + ]; + + $o .= status_editor($a, $x); + } + + // Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched his/her groups + $sql_extra = Item::getPermissionsSQLByUserId($a->profile['profile_uid']); + $sql_extra2 = ''; + + $last_updated_array = Session::get('last_updated', []); + + $sql_post_table = ""; + + if (!empty($category)) { + $sql_post_table = sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", + DBA::escape(Strings::protectSprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($a->profile['profile_uid'])); + } + + if (!empty($hashtags)) { + $sql_post_table .= sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", + DBA::escape(Strings::protectSprintf($hashtags)), intval(TERM_OBJ_POST), intval(TERM_HASHTAG), intval($a->profile['profile_uid'])); + } + + if (!empty($datequery)) { + $sql_extra2 .= Strings::protectSprintf(sprintf(" AND `thread`.`received` <= '%s' ", DBA::escape(DateTimeFormat::convert($datequery, 'UTC', date_default_timezone_get())))); + } + if (!empty($datequery2)) { + $sql_extra2 .= Strings::protectSprintf(sprintf(" AND `thread`.`received` >= '%s' ", DBA::escape(DateTimeFormat::convert($datequery2, 'UTC', date_default_timezone_get())))); + } + + // Does the profile page belong to a forum? + // If not then we can improve the performance with an additional condition + $condition = ['uid' => $a->profile['profile_uid'], 'page-flags' => [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]]; + if (!DBA::exists('user', $condition)) { + $sql_extra3 = sprintf(" AND `thread`.`contact-id` = %d ", intval(intval($a->profile['contact_id']))); + } else { + $sql_extra3 = ""; + } + + // check if we serve a mobile device and get the user settings + // accordingly + if (DI::mode()->isMobile()) { + $itemspage_network = DI::pConfig()->get(local_user(), 'system', 'itemspage_mobile_network', 10); + } else { + $itemspage_network = DI::pConfig()->get(local_user(), 'system', 'itemspage_network', 20); + } + + // now that we have the user settings, see if the theme forces + // a maximum item number which is lower then the user choice + if (($a->force_max_items > 0) && ($a->force_max_items < $itemspage_network)) { + $itemspage_network = $a->force_max_items; + } + + $pager = new Pager($args->getQueryString(), $itemspage_network); + + $pager_sql = sprintf(" LIMIT %d, %d ", $pager->getStart(), $pager->getItemsPerPage()); + + $items_stmt = DBA::p( + "SELECT `item`.`uri` + FROM `thread` + STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid` + $sql_post_table + STRAIGHT_JOIN `contact` + ON `contact`.`id` = `thread`.`contact-id` + AND NOT `contact`.`blocked` + AND NOT `contact`.`pending` + WHERE `thread`.`uid` = ? + AND `thread`.`visible` + AND NOT `thread`.`deleted` + AND NOT `thread`.`moderated` + AND `thread`.`wall` + $sql_extra3 + $sql_extra + $sql_extra2 + ORDER BY `thread`.`received` DESC + $pager_sql", + $a->profile['profile_uid'] + ); + + // Set a time stamp for this page. We will make use of it when we + // search for new items (update routine) + $last_updated_array[$last_updated_key] = time(); + Session::set('last_updated', $last_updated_array); + + if ($is_owner && !DI::config()->get('theme', 'hide_eventlist')) { + $o .= ProfileModel::getBirthdays(); + $o .= ProfileModel::getEventsReminderHTML(); + } + + if ($is_owner) { + $unseen = Item::exists(['wall' => true, 'unseen' => true, 'uid' => local_user()]); + if ($unseen) { + Item::update(['unseen' => false], ['wall' => true, 'unseen' => true, 'uid' => local_user()]); + } + } + + $items = DBA::toArray($items_stmt); + + $o .= conversation($a, $items, $pager, 'profile', false, false, 'received', $a->profile['profile_uid']); + + $o .= $pager->renderMinimal(count($items)); + + return $o; + } +} diff --git a/src/Module/Settings/Profile/Index.php b/src/Module/Settings/Profile/Index.php new file mode 100644 index 0000000000..e1b1d96b90 --- /dev/null +++ b/src/Module/Settings/Profile/Index.php @@ -0,0 +1,388 @@ +t('Profile Name is required.')); + return; + } + + $namechanged = $profile['username'] != $name; + + $pdesc = Strings::escapeTags(trim($_POST['pdesc'])); + $gender = Strings::escapeTags(trim($_POST['gender'])); + $address = Strings::escapeTags(trim($_POST['address'])); + $locality = Strings::escapeTags(trim($_POST['locality'])); + $region = Strings::escapeTags(trim($_POST['region'])); + $postal_code = Strings::escapeTags(trim($_POST['postal_code'])); + $country_name = Strings::escapeTags(trim($_POST['country_name'])); + $pub_keywords = self::cleanKeywords(Strings::escapeTags(trim($_POST['pub_keywords']))); + $prv_keywords = self::cleanKeywords(Strings::escapeTags(trim($_POST['prv_keywords']))); + $marital = Strings::escapeTags(trim($_POST['marital'])); + $howlong = Strings::escapeTags(trim($_POST['howlong'])); + + $with = (!empty($_POST['with']) ? Strings::escapeTags(trim($_POST['with'])) : ''); + + if (!strlen($howlong)) { + $howlong = DBA::NULL_DATETIME; + } else { + $howlong = DateTimeFormat::convert($howlong, 'UTC', date_default_timezone_get()); + } + + // linkify the relationship target if applicable + if (strlen($with)) { + if ($with != strip_tags($profile['with'])) { + $contact_url = ''; + $lookup = $with; + if (strpos($lookup, '@') === 0) { + $lookup = substr($lookup, 1); + } + $lookup = str_replace('_', ' ', $lookup); + if (strpos($lookup, '@') || (strpos($lookup, 'http://'))) { + $contact_name = $lookup; + $links = @Probe::lrdd($lookup); + if (count($links)) { + foreach ($links as $link) { + if ($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') { + $contact_url = $link['@attributes']['href']; + } + } + } + } else { + $contact_name = $lookup; + + $contact = Contact::selectFirst( + ['url', 'name'], + ['? IN (`name`, `nick`) AND `uid` = ?', $lookup, local_user()] + ); + + if (DBA::isResult($contact)) { + $contact_url = $contact['url']; + $contact_name = $contact['name']; + } + } + + if ($contact_url) { + $with = str_replace($lookup, '' . $contact_name . '', $with); + if (strpos($with, '@') === 0) { + $with = substr($with, 1); + } + } + } else { + $with = $profile['with']; + } + } + + /// @TODO Not flexible enough for later expansion, let's have more OOP here + $sexual = Strings::escapeTags(trim($_POST['sexual'])); + $xmpp = Strings::escapeTags(trim($_POST['xmpp'])); + $homepage = Strings::escapeTags(trim($_POST['homepage'])); + if ((strpos($homepage, 'http') !== 0) && (strlen($homepage))) { + // neither http nor https in URL, add them + $homepage = 'http://' . $homepage; + } + + $hometown = Strings::escapeTags(trim($_POST['hometown'])); + $politic = Strings::escapeTags(trim($_POST['politic'])); + $religion = Strings::escapeTags(trim($_POST['religion'])); + + $likes = Strings::escapeHtml(trim($_POST['likes'])); + $dislikes = Strings::escapeHtml(trim($_POST['dislikes'])); + + $about = Strings::escapeHtml(trim($_POST['about'])); + $interest = Strings::escapeHtml(trim($_POST['interest'])); + $contact = Strings::escapeHtml(trim($_POST['contact'])); + $music = Strings::escapeHtml(trim($_POST['music'])); + $book = Strings::escapeHtml(trim($_POST['book'])); + $tv = Strings::escapeHtml(trim($_POST['tv'])); + $film = Strings::escapeHtml(trim($_POST['film'])); + $romance = Strings::escapeHtml(trim($_POST['romance'])); + $work = Strings::escapeHtml(trim($_POST['work'])); + $education = Strings::escapeHtml(trim($_POST['education'])); + + $hide_friends = intval(!empty($_POST['hide-friends'])); + + DI::pConfig()->set(local_user(), 'system', 'detailed_profile', intval(!empty($_POST['detailed_profile']))); + + $result = DBA::update( + 'profile', + [ + 'name' => $name, + 'pdesc' => $pdesc, + 'gender' => $gender, + 'dob' => $dob, + 'address' => $address, + 'locality' => $locality, + 'region' => $region, + 'postal-code' => $postal_code, + 'country-name' => $country_name, + 'marital' => $marital, + 'with' => $with, + 'howlong' => $howlong, + 'sexual' => $sexual, + 'xmpp' => $xmpp, + 'homepage' => $homepage, + 'hometown' => $hometown, + 'politic' => $politic, + 'religion' => $religion, + 'pub_keywords' => $pub_keywords, + 'prv_keywords' => $prv_keywords, + 'likes' => $likes, + 'dislikes' => $dislikes, + 'about' => $about, + 'interest' => $interest, + 'contact' => $contact, + 'music' => $music, + 'book' => $book, + 'tv' => $tv, + 'film' => $film, + 'romance' => $romance, + 'work' => $work, + 'education' => $education, + 'hide-friends' => $hide_friends, + ], + [ + 'uid' => local_user(), + 'is-default' => true, + ] + ); + + if ($result) { + info(DI::l10n()->t('Profile updated.')); + } else { + notice(DI::l10n()->t('Profile couldn\'t be updated.')); + return; + } + + if ($namechanged) { + DBA::update('user', ['username' => $name], ['uid' => local_user()]); + } + + Contact::updateSelfFromUserID(local_user()); + + // Update global directory in background + if (Session::get('my_url') && strlen(DI::config()->get('system', 'directory'))) { + Worker::add(PRIORITY_LOW, 'Directory', Session::get('my_url')); + } + + Worker::add(PRIORITY_LOW, 'ProfileUpdate', local_user()); + + // Update the global contact for the user + GContact::updateForUser(local_user()); + } + + public static function content(array $parameters = []) + { + if (!local_user()) { + notice(DI::l10n()->t('You must be logged in to use this module')); + return Login::form(); + } + + parent::content(); + + $o = ''; + + $profile = ProfileModel::getByUID(local_user()); + if (!DBA::isResult($profile)) { + throw new HTTPException\NotFoundException(); + } + + $a = DI::app(); + + DI::page()['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('settings/profile/index_head.tpl'), [ + '$baseurl' => DI::baseUrl()->get(true), + ]); + + $opt_tpl = Renderer::getMarkupTemplate('settings/profile/hide-friends.tpl'); + $hide_friends = Renderer::replaceMacros($opt_tpl, [ + '$yesno' => [ + 'hide-friends', //Name + DI::l10n()->t('Hide contacts and friends:'), //Label + !!$profile['hide-friends'], //Value + '', //Help string + [DI::l10n()->t('No'), DI::l10n()->t('Yes')] //Off - On strings + ], + '$desc' => DI::l10n()->t('Hide your contact/friend list from viewers of this profile?'), + '$yes_str' => DI::l10n()->t('Yes'), + '$no_str' => DI::l10n()->t('No'), + '$yes_selected' => (($profile['hide-friends']) ? ' checked="checked"' : ''), + '$no_selected' => (($profile['hide-friends'] == 0) ? ' checked="checked"' : '') + ]); + + $personal_account = !in_array($a->user['page-flags'], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]); + + $detailed_profile = + $personal_account + && DI::pConfig()->get(local_user(), 'system', 'detailed_profile', + DI::pConfig()->get(local_user(), 'system', 'detailled_profile') + ) + ; + + $tpl = Renderer::getMarkupTemplate('settings/profile/index.tpl'); + $o .= Renderer::replaceMacros($tpl, [ + '$personal_account' => $personal_account, + '$detailed_profile' => $detailed_profile, + + '$details' => [ + 'detailed_profile', //Name + DI::l10n()->t('Show more profile fields:'), //Label + $detailed_profile, //Value + '', //Help string + [DI::l10n()->t('No'), DI::l10n()->t('Yes')] //Off - On strings + ], + + '$form_security_token' => self::getFormSecurityToken('settings_profile'), + '$form_security_token_photo' => self::getFormSecurityToken('settings_profile_photo'), + + '$profile_action' => DI::l10n()->t('Profile Actions'), + '$banner' => DI::l10n()->t('Edit Profile Details'), + '$submit' => DI::l10n()->t('Submit'), + '$profpic' => DI::l10n()->t('Change Profile Photo'), + '$profpiclink' => '/photos/' . $a->user['nickname'], + '$viewprof' => DI::l10n()->t('View this profile'), + '$viewallprof' => DI::l10n()->t('View all profiles'), + '$editvis' => DI::l10n()->t('Edit visibility'), + '$cr_prof' => DI::l10n()->t('Create a new profile using these settings'), + '$cl_prof' => DI::l10n()->t('Clone this profile'), + '$del_prof' => DI::l10n()->t('Delete this profile'), + + '$lbl_basic_section' => DI::l10n()->t('Basic information'), + '$lbl_picture_section' => DI::l10n()->t('Profile picture'), + '$lbl_location_section' => DI::l10n()->t('Location'), + '$lbl_preferences_section' => DI::l10n()->t('Preferences'), + '$lbl_status_section' => DI::l10n()->t('Status information'), + '$lbl_about_section' => DI::l10n()->t('Additional information'), + '$lbl_interests_section' => DI::l10n()->t('Interests'), + '$lbl_personal_section' => DI::l10n()->t('Personal'), + '$lbl_relation_section' => DI::l10n()->t('Relation'), + '$lbl_miscellaneous_section' => DI::l10n()->t('Miscellaneous'), + + '$lbl_profile_photo' => DI::l10n()->t('Upload Profile Photo'), + '$lbl_gender' => DI::l10n()->t('Your Gender:'), + '$lbl_marital' => DI::l10n()->t(' Marital Status:'), + '$lbl_sexual' => DI::l10n()->t('Sexual Preference:'), + '$lbl_ex2' => DI::l10n()->t('Example: fishing photography software'), + + '$default' => '

' . DI::l10n()->t('This is your public profile.
It may be visible to anybody using the internet.') . '

', + '$baseurl' => DI::baseUrl()->get(true), + '$nickname' => $a->user['nickname'], + '$name' => ['name', DI::l10n()->t('Display name:'), $profile['name']], + '$pdesc' => ['pdesc', DI::l10n()->t('Title/Description:'), $profile['pdesc']], + '$dob' => Temporal::getDateofBirthField($profile['dob'], $a->user['timezone']), + '$hide_friends' => $hide_friends, + '$address' => ['address', DI::l10n()->t('Street Address:'), $profile['address']], + '$locality' => ['locality', DI::l10n()->t('Locality/City:'), $profile['locality']], + '$region' => ['region', DI::l10n()->t('Region/State:'), $profile['region']], + '$postal_code' => ['postal_code', DI::l10n()->t('Postal/Zip Code:'), $profile['postal-code']], + '$country_name' => ['country_name', DI::l10n()->t('Country:'), $profile['country-name']], + '$age' => ((intval($profile['dob'])) ? '(' . DI::l10n()->t('Age: ') . Temporal::getAgeByTimezone($profile['dob'], $a->user['timezone'], $a->user['timezone']) . ')' : ''), + '$gender' => DI::l10n()->t(ContactSelector::gender($profile['gender'])), + '$marital' => ['selector' => ContactSelector::maritalStatus($profile['marital']), 'value' => DI::l10n()->t($profile['marital'])], + '$with' => ['with', DI::l10n()->t('Who: (if applicable)'), strip_tags($profile['with']), DI::l10n()->t('Examples: cathy123, Cathy Williams, cathy@example.com')], + '$howlong' => ['howlong', DI::l10n()->t('Since [date]:'), ($profile['howlong'] <= DBA::NULL_DATETIME ? '' : DateTimeFormat::local($profile['howlong']))], + '$sexual' => ['selector' => ContactSelector::sexualPreference($profile['sexual']), 'value' => DI::l10n()->t($profile['sexual'])], + '$about' => ['about', DI::l10n()->t('Tell us about yourself...'), $profile['about']], + '$xmpp' => ['xmpp', DI::l10n()->t('XMPP (Jabber) address:'), $profile['xmpp'], DI::l10n()->t('The XMPP address will be propagated to your contacts so that they can follow you.')], + '$homepage' => ['homepage', DI::l10n()->t('Homepage URL:'), $profile['homepage']], + '$hometown' => ['hometown', DI::l10n()->t('Hometown:'), $profile['hometown']], + '$politic' => ['politic', DI::l10n()->t('Political Views:'), $profile['politic']], + '$religion' => ['religion', DI::l10n()->t('Religious Views:'), $profile['religion']], + '$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)')], + '$prv_keywords' => ['prv_keywords', DI::l10n()->t('Private Keywords:'), $profile['prv_keywords'], DI::l10n()->t('(Used for searching profiles, never shown to others)')], + '$likes' => ['likes', DI::l10n()->t('Likes:'), $profile['likes']], + '$dislikes' => ['dislikes', DI::l10n()->t('Dislikes:'), $profile['dislikes']], + '$music' => ['music', DI::l10n()->t('Musical interests'), $profile['music']], + '$book' => ['book', DI::l10n()->t('Books, literature'), $profile['book']], + '$tv' => ['tv', DI::l10n()->t('Television'), $profile['tv']], + '$film' => ['film', DI::l10n()->t('Film/dance/culture/entertainment'), $profile['film']], + '$interest' => ['interest', DI::l10n()->t('Hobbies/Interests'), $profile['interest']], + '$romance' => ['romance', DI::l10n()->t('Love/romance'), $profile['romance']], + '$work' => ['work', DI::l10n()->t('Work/employment'), $profile['work']], + '$education' => ['education', DI::l10n()->t('School/education'), $profile['education']], + '$contact' => ['contact', DI::l10n()->t('Contact information and Social Networks'), $profile['contact']], + ]); + + $arr = ['profile' => $profile, 'entry' => $o]; + Hook::callAll('profile_edit', $arr); + + return $o; + } + + private static function cleanKeywords($keywords) + { + $keywords = str_replace(',', ' ', $keywords); + $keywords = explode(' ', $keywords); + + $cleaned = []; + foreach ($keywords as $keyword) { + $keyword = trim(strtolower($keyword)); + $keyword = trim($keyword, '#'); + if ($keyword != '') { + $cleaned[] = $keyword; + } + } + + $keywords = implode(', ', $cleaned); + + return $keywords; + } +} diff --git a/src/Module/Update/Profile.php b/src/Module/Update/Profile.php new file mode 100644 index 0000000000..e67082191c --- /dev/null +++ b/src/Module/Update/Profile.php @@ -0,0 +1,127 @@ +get('system', 'block_public') && !local_user() && !Session::getRemoteContactID($a->profile['profile_uid'])) { + throw new ForbiddenException(); + } + + $o = ''; + + $profile_uid = intval($_GET['p'] ?? 0); + + // Ensure we've got a profile owner if updating. + $a->profile['profile_uid'] = $profile_uid; + + $remote_contact = Session::getRemoteContactID($a->profile['profile_uid']); + $is_owner = local_user() == $a->profile['profile_uid']; + $last_updated_key = "profile:" . $a->profile['profile_uid'] . ":" . local_user() . ":" . $remote_contact; + + if (!empty($a->profile['hidewall']) && !$is_owner && !$remote_contact) { + throw new ForbiddenException(DI::l10n()->t('Access to this profile has been restricted.')); + } + + // Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched his/her groups + $sql_extra = Item::getPermissionsSQLByUserId($a->profile['profile_uid']); + + $last_updated_array = Session::get('last_updated', []); + + $last_updated = $last_updated_array[$last_updated_key] ?? 0; + + // If the page user is the owner of the page we should query for unseen + // items. Otherwise use a timestamp of the last succesful update request. + if ($is_owner || !$last_updated) { + $sql_extra4 = " AND `item`.`unseen`"; + } else { + $gmupdate = gmdate(DateTimeFormat::MYSQL, $last_updated); + $sql_extra4 = " AND `item`.`received` > '" . $gmupdate . "'"; + } + + $items_stmt = DBA::p( + "SELECT DISTINCT(`parent-uri`) AS `uri`, `item`.`created` + FROM `item` + INNER JOIN `contact` + ON `contact`.`id` = `item`.`contact-id` + AND NOT `contact`.`blocked` + AND NOT `contact`.`pending` + WHERE `item`.`uid` = ? + AND `item`.`visible` + AND (NOT `item`.`deleted` OR `item`.`gravity` = ?) + AND NOT `item`.`moderated` + AND `item`.`wall` + $sql_extra4 + $sql_extra + ORDER BY `item`.`received` DESC", + $a->profile['profile_uid'], + GRAVITY_ACTIVITY + ); + + if (!DBA::isResult($items_stmt)) { + return ''; + } + + $pager = new Pager(DI::args()->getQueryString()); + + // Set a time stamp for this page. We will make use of it when we + // search for new items (update routine) + $last_updated_array[$last_updated_key] = time(); + Session::set('last_updated', $last_updated_array); + + if ($is_owner && !$profile_uid && !DI::config()->get('theme', 'hide_eventlist')) { + $o .= ProfileModel::getBirthdays(); + $o .= ProfileModel::getEventsReminderHTML(); + } + + if ($is_owner) { + $unseen = Item::exists(['wall' => true, 'unseen' => true, 'uid' => local_user()]); + if ($unseen) { + Item::update(['unseen' => false], ['wall' => true, 'unseen' => true, 'uid' => local_user()]); + } + } + + $items = DBA::toArray($items_stmt); + + $o .= conversation($a, $items, $pager, 'profile', $profile_uid, false, 'received', $a->profile['profile_uid']); + + header("Content-type: text/html"); + echo "\r\n"; + // We can remove this hack once Internet Explorer recognises HTML5 natively + echo "
"; + echo $o; + if (DI::pConfig()->get(local_user(), "system", "bandwidth_saver")) { + $replace = "
".DI::l10n()->t("[Embedded content - reload page to view]")."
"; + $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; + $o = preg_replace($pattern, $replace, $o); + $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; + $o = preg_replace($pattern, $replace, $o); + $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; + $o = preg_replace($pattern, $replace, $o); + $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; + $o = preg_replace($pattern, $replace, $o); + } + + // reportedly some versions of MSIE don't handle tabs in XMLHttpRequest documents very well + echo str_replace("\t", " ", $o); + echo "
"; + echo "\r\n"; + exit(); + } +} diff --git a/static/routes.config.php b/static/routes.config.php index 05f2599561..ca1f9bf2f3 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -195,10 +195,9 @@ return [ '/probe' => [Module\Debug\Probe::class, [R::GET]], '/profile' => [ - '/{nickname}' => [Module\Profile::class, [R::GET]], - '/{nickname}/{to:\d{4}-\d{2}-\d{2}}/{from:\d{4}-\d{2}-\d{2}}' => [Module\Profile::class, [R::GET]], - '/{nickname}/contacts[/{type}]' => [Module\Profile\Contacts::class, [R::GET]], - '/{profile:\d+}/view' => [Module\Profile::class, [R::GET]], + '/{nickname}' => [Module\Profile\Index::class, [R::GET]], + '/{nickname}/contacts[/{type}]' => [Module\Profile\Contacts::class, [R::GET]], + '/{nickname}/status[/{category}[/{date1}[/{date2}]]]' => [Module\Profile\Status::class, [R::GET]], ], '/proxy' => [ @@ -229,6 +228,7 @@ return [ ], '/delegation[/{action}/{user_id}]' => [Module\Settings\Delegation::class, [R::GET, R::POST]], '/profile' => [ + '[/]' => [Module\Settings\Profile\Index::class, [R::GET, R::POST]], '/photo[/new]' => [Module\Settings\Profile\Photo\Index::class, [R::GET, R::POST]], '/photo/crop/{guid}' => [Module\Settings\Profile\Photo\Crop::class, [R::GET, R::POST]], ], @@ -244,6 +244,9 @@ return [ '/starred/{item:\d+}' => [Module\Starred::class, [R::GET]], '/toggle_mobile' => [Module\ToggleMobile::class, [R::GET]], '/tos' => [Module\Tos::class, [R::GET]], + + '/update_profile' => [Module\Update\Profile::class, [R::GET]], + '/view/theme/{theme}/style.pcss' => [Module\Theme::class, [R::GET]], '/viewsrc/{item:\d+}' => [Module\Debug\ItemBody::class, [R::GET]], '/webfinger' => [Module\Debug\WebFinger::class, [R::GET]], diff --git a/tests/src/App/RouterTest.php b/tests/src/App/RouterTest.php index fc34df9575..6d4b8770d0 100644 --- a/tests/src/App/RouterTest.php +++ b/tests/src/App/RouterTest.php @@ -159,7 +159,7 @@ class RouterTest extends TestCase '/post' => [ '/it' => [Module\NodeInfo::class, [Router::POST]], ], - '/double' => [Module\Profile::class, [Router::GET, Router::POST]] + '/double' => [Module\Profile\Index::class, [Router::GET, Router::POST]] ], ], ]; @@ -177,7 +177,7 @@ class RouterTest extends TestCase $this->assertEquals(Module\Home::class, $router->getModuleClass('/')); $this->assertEquals(Module\Friendica::class, $router->getModuleClass('/group/route')); $this->assertEquals(Module\Xrd::class, $router->getModuleClass('/group2/group3/route')); - $this->assertEquals(Module\Profile::class, $router->getModuleClass('/double')); + $this->assertEquals(Module\Profile\Index::class, $router->getModuleClass('/double')); } /** @@ -191,6 +191,6 @@ class RouterTest extends TestCase // Don't find GET $this->assertEquals(Module\NodeInfo::class, $router->getModuleClass('/post/it')); - $this->assertEquals(Module\Profile::class, $router->getModuleClass('/double')); + $this->assertEquals(Module\Profile\Index::class, $router->getModuleClass('/double')); } } diff --git a/view/templates/profile-hide-wall.tpl b/view/templates/profile-hide-wall.tpl deleted file mode 100644 index ff106fa29f..0000000000 --- a/view/templates/profile-hide-wall.tpl +++ /dev/null @@ -1,17 +0,0 @@ - -

-{{$desc nofilter}} -

- -
- - - -
-
-
- - - -
-
diff --git a/view/templates/profile-in-directory.tpl b/view/templates/profile-in-directory.tpl deleted file mode 100644 index bfc13e85eb..0000000000 --- a/view/templates/profile-in-directory.tpl +++ /dev/null @@ -1,17 +0,0 @@ - -

-{{$desc nofilter}} -

- -
- - - -
-
-
- - - -
-
diff --git a/view/templates/profile-in-netdir.tpl b/view/templates/profile-in-netdir.tpl deleted file mode 100644 index c91601bce8..0000000000 --- a/view/templates/profile-in-netdir.tpl +++ /dev/null @@ -1,17 +0,0 @@ - -

-{{$desc nofilter}} -

- -
- - - -
-
-
- - - -
-
diff --git a/view/templates/profile_edlink.tpl b/view/templates/profile_edlink.tpl deleted file mode 100644 index 54d7a34dd0..0000000000 --- a/view/templates/profile_edlink.tpl +++ /dev/null @@ -1,3 +0,0 @@ - -
-
\ No newline at end of file diff --git a/view/templates/profile-hide-friends.tpl b/view/templates/settings/profile/hide-friends.tpl similarity index 100% rename from view/templates/profile-hide-friends.tpl rename to view/templates/settings/profile/hide-friends.tpl diff --git a/view/templates/profile_edit.tpl b/view/templates/settings/profile/index.tpl similarity index 91% rename from view/templates/profile_edit.tpl rename to view/templates/settings/profile/index.tpl index 08e833f10a..b02ee175eb 100644 --- a/view/templates/profile_edit.tpl +++ b/view/templates/settings/profile/index.tpl @@ -1,16 +1,12 @@ -{{$default nofilter}} -

{{$banner}}

+{{$default nofilter}} + @@ -18,17 +14,11 @@
-
- + + -{{if $detailled_profile}} +{{if $detailed_profile}} {{include file="field_yesno.tpl" field=$details}} -
- -
*
-
-
-
@@ -328,12 +318,6 @@ {{if $personal_account}} {{include file="field_yesno.tpl" field=$details}} {{/if}} -
- -
*
-
-
-
diff --git a/view/templates/profed_head.tpl b/view/templates/settings/profile/index_head.tpl similarity index 100% rename from view/templates/profed_head.tpl rename to view/templates/settings/profile/index_head.tpl diff --git a/view/templates/settings/profile/link.tpl b/view/templates/settings/profile/link.tpl new file mode 100644 index 0000000000..d387ea683c --- /dev/null +++ b/view/templates/settings/profile/link.tpl @@ -0,0 +1,2 @@ +
+
diff --git a/view/templates/welcome.tpl b/view/templates/welcome.tpl index 4e0ae7754d..0ac061b47e 100644 --- a/view/templates/welcome.tpl +++ b/view/templates/welcome.tpl @@ -26,11 +26,11 @@ {{$profile_photo_txt nofilter}}
  • - {{$profiles_link}}
    + {{$profiles_link}}
    {{$profiles_txt nofilter}}
  • - {{$profiles_keywords_link}}
    + {{$profiles_keywords_link}}
    {{$profiles_keywords_txt nofilter}}
  • diff --git a/view/theme/frio/templates/profile_edit.tpl b/view/theme/frio/templates/settings/profile/index.tpl similarity index 76% rename from view/theme/frio/templates/profile_edit.tpl rename to view/theme/frio/templates/settings/profile/index.tpl index 946443cf11..b88a6f1a84 100644 --- a/view/theme/frio/templates/profile_edit.tpl +++ b/view/theme/frio/templates/settings/profile/index.tpl @@ -7,37 +7,22 @@
    - - - + +
    @@ -46,8 +31,8 @@
    -
    - +
    +
    @@ -60,39 +45,37 @@ 3 => The additional help text (if available) *}} - - + + {{* Some hints to characteristics of the current profile (if available) *}} - {{if $is_default}} - {{/if}} + + {{if $personal_account}} +

    {{include file="field_yesno.tpl" field=$details}}

    + {{/if}} {{* friendica differs in $detailled_profile (all fields available and a short Version if this is variable false *}} - {{if $detailled_profile}} + {{if $detailed_profile}}
    {{* The personal settings *}}
    - {{* for the $detailled_profile we use bootstraps collapsable panel-groups to have expandable groups *}} -
    + {{* for the $detailed_profile we use bootstraps collapsable panel-groups to have expandable groups *}} +
    - {{include file="field_yesno.tpl" field=$details}} - - {{include file="field_input.tpl" field=$profile_name}} - {{include file="field_input.tpl" field=$name}} {{include file="field_input.tpl" field=$pdesc}}
    - + {{$gender nofilter}}
    @@ -101,7 +84,7 @@ {{$hide_friends nofilter}} -
    +
    @@ -128,18 +111,18 @@ {{include file="field_input.tpl" field=$postal_code}}
    - +
    - - +
    @@ -147,7 +130,7 @@ {{include file="field_input.tpl" field=$hometown}} -
    +
    @@ -166,8 +149,8 @@
    -
    - +
    + {{$marital.selector nofilter}}
    @@ -176,13 +159,13 @@ {{include file="field_input.tpl" field=$howlong}} -
    - +
    + {{$sexual.selector nofilter}}
    -
    +
    @@ -238,7 +221,7 @@ {{include file="field_textarea.tpl" field=$education}} -
    +
    @@ -247,19 +230,13 @@
    - {{else}} - {{* if $detailled_profile not available a short version of the setting page is displayed *}} - {{if $personal_account}} - {{include file="field_yesno.tpl" field=$details}} - {{/if}} - - {{include file="field_input.tpl" field=$profile_name}} - + {{else}} + {{* if $detailed_profile not available a short version of the setting page is displayed *}} {{include file="field_input.tpl" field=$name}} {{if $personal_account}}
    - + {{$gender nofilter}}
    @@ -278,22 +255,21 @@ {{include file="field_input.tpl" field=$locality}} - {{include file="field_input.tpl" field=$postal_code}}
    - +
    - - +
    @@ -305,7 +281,7 @@ {{include file="field_textarea.tpl" field=$about}} -
    +
    diff --git a/view/theme/vier/templates/profile_edit.tpl b/view/theme/vier/templates/settings/profile/index.tpl similarity index 93% rename from view/theme/vier/templates/profile_edit.tpl rename to view/theme/vier/templates/settings/profile/index.tpl index 066b2566f6..841c6d17e8 100644 --- a/view/theme/vier/templates/profile_edit.tpl +++ b/view/theme/vier/templates/settings/profile/index.tpl @@ -1,7 +1,7 @@ diff --git a/view/theme/vier/templates/profile_edlink.tpl b/view/theme/vier/templates/settings/profile/link.tpl similarity index 100% rename from view/theme/vier/templates/profile_edlink.tpl rename to view/theme/vier/templates/settings/profile/link.tpl From f6f4cbab9d8b973aa4acf3af43df9334a4cb291b Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 27 Oct 2019 10:09:38 -0400 Subject: [PATCH 02/19] Remove multi profiles feature - Remove mod/profperm - Remove additional feature - Remove profile visibility on contact page - Remove profile list templates --- doc/API-Friendica.md | 1 - doc/Profiles.md | 77 -------- doc/de/Account-Basics.md | 2 - doc/de/Home.md | 1 - doc/de/Profiles.md | 79 -------- mod/profperm.php | 171 ------------------ src/Content/ContactSelector.php | 27 --- src/Content/Feature.php | 1 - src/Content/Nav.php | 4 - src/Model/Profile.php | 50 ++--- src/Module/Contact.php | 19 -- view/templates/contact_edit.tpl | 9 - view/templates/profile_entry.tpl | 12 -- view/templates/profile_listing_header.tpl | 14 -- view/theme/frio/templates/contact_edit.tpl | 29 --- view/theme/frio/templates/profile_entry.tpl | 15 -- .../frio/templates/profile_listing_header.tpl | 16 -- view/theme/vier/templates/contact_edit.tpl | 9 - 18 files changed, 13 insertions(+), 523 deletions(-) delete mode 100644 doc/Profiles.md delete mode 100644 doc/de/Profiles.md delete mode 100644 mod/profperm.php delete mode 100644 view/templates/profile_entry.tpl delete mode 100644 view/templates/profile_listing_header.tpl delete mode 100644 view/theme/frio/templates/profile_entry.tpl delete mode 100644 view/theme/frio/templates/profile_listing_header.tpl diff --git a/doc/API-Friendica.md b/doc/API-Friendica.md index 76440600c4..84467430ae 100644 --- a/doc/API-Friendica.md +++ b/doc/API-Friendica.md @@ -655,7 +655,6 @@ Returns the [Profile](help/API-Entities#Profile) data of all profiles or a singl On success: Array of: -* `multi_profiles`: true if user has activated multi_profiles * `global_dir`: URL of the global directory set in server settings * `friendica_owner`: user data of the authenticated user * `profiles`: array of the profile data diff --git a/doc/Profiles.md b/doc/Profiles.md deleted file mode 100644 index aceb94da39..0000000000 --- a/doc/Profiles.md +++ /dev/null @@ -1,77 +0,0 @@ -Profiles -======== - -* [Home](help) - -Friendica has unlimited profiles. -You may use different profiles to present different aspects of yourself to different audiences. - -Default / public profile ---- -You always have a profile known as your "default" or "public" profile. -This profile is always available to the general public and usually cannot be hidden. -You may, and probably should restrict the personal information you make available on your public profile. - -That said, if you want other friends to be able to find you, it helps to have the following information in your public profile: - -* Your real name -* A photo of **you** -* Your location, preferably at least the country. - -In addition, if you'd like to meet people that share some general interests with you, add some "Public Keywords" to your profile. -Such as "music, linux, photography" or whatever. -You can add as many keywords as you like. - -Your default or public profile is also shown to contacts on other networks, since they do not have the ability to view your private profiles. -Only members of the Friendica network can see alternate/ private profiles. - -Alternate/ private profiles ---- -To create an alternate profile, select "Profiles" from the menu of your Friendica site. -You may edit an existing profile, change the profile photo, or create a new profile. -You may also "clone" your existing profile if you only wish to change a few items but don't wish to enter all the information again. - -To assign a profile to specific persons, select the person from your "Contacts" page and click the pencil "Edit" icon. -You will find a dropdown box listing the various profiles available. -If this box is not selectable, the person is not in a supported network and cannot be assigned a specific profile. - -Once a profile has been selected, when the person views your profile from one of the "magic profile links" on their site, they will see the private profile you have assigned. -If they are not logged into their site or view your profile from elsewhere, they will see your public profile. - -A magic profile link is indicated by a special cursor when hovering over a contact's name or photo. -Currently this cursor is a hand next to a small padlock. -These magic cursors indicate that by following the link, you are able to access special areas of the other person's pages which are only available to friends and may not be available to the general public. - -You may also discover that (assuming you have the proper permissions) you may be able to post directly on the other person's profile (often called a "wall-to-wall" post). -You may also be able to comment directly on posts from while visiting the other person's profile page. - -There are two settings which allow you to publish your profile to a directory and ensure that it can be found by others. -You can change these through settings on the "Settings" page. -One setting allows you to publish your profile in the site directory of this Friendica server. -Another option (this may have been disabled by the site admin) allows you to publish your profile in a [Global Directory](Making-Friends.md#the-directories). - -If you do not wish to be visible to any of these directories, do not published your profile. - -Although you may have multiple profiles, you only have one profile photo. -This is intentional; it avoids confusion by potentially seeing different profile pictures of a contact depending on what website you visit or conversation you participate in. -You can always can use the free text information boxes within a profile such as "Tell us about yourself" and link other photos for yourself. - -Keywords and Directory Search ---- -On the site Directory page, you may search for people with published profiles who are on this site. -The search is typically for your nickname or part of your full name. -However this search will also match against other profile fields - such as gender, location, "about", work, and education. -You may also include "Keywords" in your default profile - which may be used to search for common interests with other members. -You have two sets of keywords available - public and private. -Private keywords are *not* visible on your profile, but will bring up your profile when matched in a search of the site directory. -Public keywords are used in the friend suggestion tool and although they aren't readily visible, they may be seen by viewing the HTML of your profile page. - -Directory searches are also able to use "boolean" logic so that you can search for "+lesbian +Florida" and find those who's sexual preference (or keywords) contain the world "lesbian" and that live in Florida. -See the section on "Topical Tags" on the [Tags-and-Mentions](help/Tags-and-Mentions) page for more information on performing boolean searches. - -On your Contacts page is a link to "Find People with Shared Interests" (unless your site administrator has disabled the global directory). -This will combine both your public and private keywords, and find people in the global directory who have matching and/or similar keywords. -Private keywords are not identified or stored on the global directory. -The more keywords you provide, the more relevant the search results that are returned. -These are sorted by relevance. -You may discover that you are the first person on the list - because you are very likely the most relevant match for your keywords in the directory. diff --git a/doc/de/Account-Basics.md b/doc/de/Account-Basics.md index 193835f5a9..81ce68c041 100644 --- a/doc/de/Account-Basics.md +++ b/doc/de/Account-Basics.md @@ -109,8 +109,6 @@ Ein ['Tipp für neue Mitglieder'](newmember)-Link zeigt sich in den ersten beide ## Schau Dir ebenfalls folgende Seiten an -* [Profile](help/Profiles) - * [Gruppen und Privatssphäre](help/Groups-and-Privacy) * [Account löschen](help/Remove-Account) diff --git a/doc/de/Home.md b/doc/de/Home.md index 536bff7201..d008b90c36 100644 --- a/doc/de/Home.md +++ b/doc/de/Home.md @@ -9,7 +9,6 @@ Friendica - Dokumentation und Ressourcen * [Beiträge erstellen](help/Text_editor) * [Referenz der BBCode Elemente](help/BBCode) * [Beiträge kommentieren, einordnen und löschen](help/Text_comment) - * [Profile](help/Profiles) * [Referenz der Accesskeys](help/Accesskeys) * [Veranstaltungen](help/events) * Du und andere Nutzer diff --git a/doc/de/Profiles.md b/doc/de/Profiles.md deleted file mode 100644 index 311f1c7929..0000000000 --- a/doc/de/Profiles.md +++ /dev/null @@ -1,79 +0,0 @@ -Profile -======== - -* [Zur Startseite der Hilfe](help) - -Mit Friendica kann eine unbegrenzte Anzahl an Profilen angelegt werden. -Du kannst verschiedene Profile nutzen, um verschiedenen Gruppen verschiedene Seiten von dir zu zeigen. - -Du hast immer ein Profil, das als dein "Standard"- (default) oder "öffentliches" (public) Profil angelegt ist. -Dieses Profil ist immer für die Öffentlichkeit zugänglich und kann nicht versteckt werden (hier mag es einige wenige Ausnahmen auf privaten oder getrennten Seiten geben). -Du kannst und solltest die Informationen, die du in deinem öffentlichen Profil veröffentlichst, begrenzen. - -Das bedeutet, dass du folgende Informationen in dein öffentlichen Profil eintragen solltest, wenn du willst, dass Freunde dich finden können ... - -* Dein richtiger Name -* Ein Foto von **dir** -* Dein geographischer Standort; zumindest das Land, in dem du lebst. - -Ohne diese Basisinformationen kannst du hier sehr einsam sein. -Die meisten Leute, auch deine besten Freunde, werden nicht versuchen, einen Account mit Spitznamen und ohne Foto zu verbinden. - -Wenn du außerdem Leute mit gleichen Interessen treffen willst, dann nimm dir etwas Zeit und trage einige Stichworte ein. -Zum Beispiel etwas wie "Musik, Linux, Photographie" oder andere Dinge. -Du kannst so viele Stichworte eintragen, wie du willst. - -Dein "Standard-" oder "öffentliches" Profil wird außerdem Kontakten in anderen Netzwerken gezeigt, auch wenn sie nicht die Möglichkeit haben, die privaten Profile einzusehen. -Nur Mitglieder des Friendica-Netzwerks können alternative oder private Profile sehen. - -Um ein alternatives Profil zu erstellen, gehe auf "Profil verwalten/editieren". -Du kannst entweder ein bestehendes Profil bearbeiten, das Foto ändern, oder ein neues Profil erstellen. -Du kannst ebenfalls einen Klon eines bestehenden Profils erstellen, falls du nur einige wenige Einstellungen ändern, aber nicht alle Daten noch mal eingeben willst. - -Um bestimmten Personen ein Profil zuzuweisen, wähle die Person über "Kontakte" und klicke auf das Bearbeiten-Symbol (Stift). -Du wirst ein Auswahlmenü mit verschiedenen vorhandenen Profilen angezeigt bekommen. -Wenn diese Auswahl nicht angezeigt wird, dann ist die Person in einem nicht unterstützten Netzwerk und kann dadurch auch kein Profil zugewiesen bekommen. - -Wenn eine befreundete Person auf den "magischen Profillink" klickt, sieht sie das private Profil, das du dieser Person zugewiesen hast. -Wenn sie nicht eingeloggt ist oder das Profil von woanders angeschaut wird, wird nur das öffentliche Profil angezeigt. - -Ein "magischer Profillink" erscheint, wenn man mit der Maus über den Kontaktnamen oder das Foto geht. -Der Cursor wird zur Hand und auf dem Bild erscheint ein Pfeil, der nach unten zeigt. -Dieser "magische Cursor" zeigt an, dass du ein spezielles Profil angezeigt bekommst, das nur für Freunde, aber nicht für die Öffentlichkeit sichtbar ist. - -Du wirst außerdem möglicherweise entdecken (vorausgesetzt, du hast die nötigen Zugriffsrechte), dass du direkt auf die Seite einer anderen Person schreiben kannst (oft wird diese Beitragsart "wall-to-wall" genannt). -Ebenso kannst du die Möglichkeit haben, direkt Beiträge zu kommentieren, während du die Seite der anderen Person besuchst. - -Es gibt zwei Einstellungen, welche erlauben, dein Profil ins Verzeichnis einzutragen, so dass du von anderen Personen gefunden werden kannst. -Du kannst diese Einstellungen auf deiner "Einstellungen"-Seite ändern. -Die eine Einstellung erlaubt dir, dein Profil im Verzeichnis dieses Servers zu veröffentlichen. -Die zweite Option erlaubt es dir, dich in das globale Friendica-Verzeichnis einzutragen. -Dies ist ein riesiges Verzeichnis, dass alle Personen von vielen Friendica-Installationen weltweit umfasst. - -Wenn du für andere nicht sichtbar sein willst, dann kannst du dein Profil einfach unveröffentlicht lassen. - -Außerdem hast du möglicherweise mehrere Profile, aber nur ein Profilfoto. Dies ist beabsichtigt. -In frühen Tests haben wir mit verschiedenen Fotos für jedes Profil experimentiert und herausgefunden, dass es sehr verwirrend für die Nutzer ist. -Sie sehen möglicherweise je nach Profil, Seite oder Unterhaltung verschiedene Fotos und merken, dass es unterschiedliche Profile gibt, die sie nicht einsehen können. - -(Du kannst aber die Rich-Text-Infoboxen in deinem Profil nutzen und dort weitere Bilder in das Feld "Erzähle uns ein bisschen von dir …" einfügen.) - - -**Schlüsselwörter und Verzeichnissuche** - -Auf der Verzeichnisseite willst du vielleicht nach Personen deines Servers suchen, die ihre Profile veröffentlicht haben. -Die Suche richtet sich normalerweise nach deinem Spitznamen oder Teilen deines richtigen Namens. -Darüber hinaus wird dieses Feld auch andere Felder deines Profils wie Geschlecht, Ort, "über mich", Arbeit und Bildung finden. -Du kannst zudem auch "Schlüsselwörter" in dein Standardprofil eintragen, so dass dich andere Personen über deine Interessen finden können. -Du hast zwei Schlüsselwortarten zur Auswahl - öffentlich und privat. Private Schlüsselwörter werden *nicht* jedem angezeigt. -Du kannst diese Schlüsselwörter nutzen, um andere Personen zu finden, die ebenfalls in einer bestimmten Gruppe sind oder z.B. das Fischen mögen, ohne dass es jeder in einem öffentlichen Profil sieht. -Öffentliche Schlüsselwörter werden auf der "Kontaktvorschläge"-Seite genutzt. -Auch wenn die Schlüsselwörter hier nicht direkt angezeigt werden, kann es trotzdem sein, dass diese im HTML-Code der Seite gesehen werden könnten. - -In der Verzeichnis-Suche kannst du ebenfalls die "booleasche"-Logik zu nutzen. Mit "+lesbisch +Florida" kannst du Leute finden, deren sexuelle Einstellung (oder andere Schlüsselwörter) das Wort "lesbisch" enthält und die in Florida leben. -Schau dir den Bereich über "Thematische Tags" auf der "[Tags und Erwähnungen-Seite](help/Tags-and-Mentions) für weitere Informationen, um booleansche Suchen durchzuführen. - -Auf deiner Kontaktseite ist der Link "Ähnliche Interessen", um damit andere Leute zu finden (falls dein Seitenadministrator das globale Verzeichnis nicht ausgeschaltet hat). -Hierfür werden die Schlüsselwörter aus deinen öffentlichen und privaten Profilen genutzt, um Personen im globalen Verzeichnis zu finden, die gleiche oder ähnliche Schlüsselwörter haben (deine privaten Schlüsselwörter werden nicht in das globale Verzeichnis übertragen oder gespeichert). -Je mehr Schlüsselwörter du einträgst, umso genauer ist die Suche. Das Suchergebnis ist nach Relevanz sortiert. -Gegebenenfalls stehst du ganz oben auf der Liste - schließlich bist du die Person, die am besten zu deinen Schlüsselwörtern passt. diff --git a/mod/profperm.php b/mod/profperm.php deleted file mode 100644 index f17d1d66b7..0000000000 --- a/mod/profperm.php +++ /dev/null @@ -1,171 +0,0 @@ -user['nickname']; - $profile = $a->argv[1]; - - Profile::load($a, $which, $profile); -} - - -function profperm_content(App $a) { - - if (!local_user()) { - notice(DI::l10n()->t('Permission denied') . EOL); - return; - } - - - if ($a->argc < 2) { - notice(DI::l10n()->t('Invalid profile identifier.') . EOL ); - return; - } - - $o = ''; - - // Switch to text mod interface if we have more than 'n' contacts or group members - - $switchtotext = DI::pConfig()->get(local_user(),'system','groupedit_image_limit'); - if (is_null($switchtotext)) { - $switchtotext = DI::config()->get('system','groupedit_image_limit', 400); - } - - if (($a->argc > 2) && intval($a->argv[1]) && intval($a->argv[2])) { - $r = q("SELECT `id` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `self` = 0 - AND `network` = '%s' AND `id` = %d AND `uid` = %d LIMIT 1", - DBA::escape(Protocol::DFRN), - intval($a->argv[2]), - intval(local_user()) - ); - - if (DBA::isResult($r)) { - $change = intval($a->argv[2]); - } - } - - - if (($a->argc > 1) && (intval($a->argv[1]))) { - $r = q("SELECT * FROM `profile` WHERE `id` = %d AND `uid` = %d AND `is-default` = 0 LIMIT 1", - intval($a->argv[1]), - intval(local_user()) - ); - if (!DBA::isResult($r)) { - notice(DI::l10n()->t('Invalid profile identifier.') . EOL ); - return; - } - $profile = $r[0]; - - $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `profile-id` = %d", - intval(local_user()), - intval($a->argv[1]) - ); - - $ingroup = []; - if (DBA::isResult($r)) - foreach($r as $member) - $ingroup[] = $member['id']; - - $members = $r; - - if (!empty($change)) { - if (in_array($change,$ingroup)) { - q("UPDATE `contact` SET `profile-id` = 0 WHERE `id` = %d AND `uid` = %d", - intval($change), - intval(local_user()) - ); - } - else { - q("UPDATE `contact` SET `profile-id` = %d WHERE `id` = %d AND `uid` = %d", - intval($a->argv[1]), - intval($change), - intval(local_user()) - ); - - } - - $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `profile-id` = %d", - intval(local_user()), - intval($a->argv[1]) - ); - - $members = $r; - - $ingroup = []; - if (DBA::isResult($r)) - foreach($r as $member) - $ingroup[] = $member['id']; - } - - $o .= '

    ' . DI::l10n()->t('Profile Visibility Editor') . '

    '; - - $o .= '

    ' . DI::l10n()->t('Profile') . ' \'' . $profile['profile-name'] . '\'

    '; - - $o .= '
    ' . DI::l10n()->t('Click on a contact to add or remove.') . '
    '; - - } - - $o .= '
    '; - if (!empty($change)) - $o = ''; - - $o .= '
    '; - $o .= '

    ' . DI::l10n()->t('Visible To') . '

    '; - $o .= '
    '; - $o .= '
    '; - - $textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : false); - - foreach($members as $member) { - if ($member['url']) { - $member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['id'] . '); return true;'; - $o .= HTML::micropro($member,true,'mpprof', $textmode); - } - } - $o .= '
    '; - $o .= '
    '; - - $o .= '
    '; - $o .= '

    ' . DI::l10n()->t("All Contacts \x28with secure profile access\x29") . '

    '; - $o .= '
    '; - $o .= '
    '; - - $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `blocked` = 0 and `pending` = 0 and `self` = 0 - AND `network` = '%s' ORDER BY `name` ASC", - intval(local_user()), - DBA::escape(Protocol::DFRN) - ); - - if (DBA::isResult($r)) { - $textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : false); - foreach($r as $member) { - if (!in_array($member['id'],$ingroup)) { - $member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['id'] . '); return true;'; - $o .= HTML::micropro($member,true,'mpprof',$textmode); - } - } - } - - $o .= '
    '; - - if (!empty($change)) { - echo $o; - exit(); - } - $o .= '
    '; - return $o; - -} diff --git a/src/Content/ContactSelector.php b/src/Content/ContactSelector.php index 0328f063e0..a9c6bc269d 100644 --- a/src/Content/ContactSelector.php +++ b/src/Content/ContactSelector.php @@ -16,33 +16,6 @@ use Friendica\Util\Strings; */ class ContactSelector { - /** - * @param string $current current - * @param string $foreign_net network - * @return string - * @throws \Exception - */ - public static function profileAssign($current, $foreign_net) - { - $o = ''; - - $disabled = (($foreign_net) ? ' disabled="true" ' : ''); - - $o .= "\r\n"; - return $o; - } - /** * @param string $current current * @param boolean $disabled optional, default false diff --git a/src/Content/Feature.php b/src/Content/Feature.php index 91a319677f..59eea16377 100644 --- a/src/Content/Feature.php +++ b/src/Content/Feature.php @@ -79,7 +79,6 @@ class Feature 'general' => [ DI::l10n()->t('General Features'), //array('expire', DI::l10n()->t('Content Expiration'), DI::l10n()->t('Remove old posts/comments after a period of time')), - ['multi_profiles', DI::l10n()->t('Multiple Profiles'), DI::l10n()->t('Ability to create multiple profiles'), false, DI::config()->get('feature_lock', 'multi_profiles', false)], ['photo_location', DI::l10n()->t('Photo Location'), DI::l10n()->t("Photo metadata is normally stripped. This extracts the location \x28if present\x29 prior to stripping metadata and links it to a map."), false, DI::config()->get('feature_lock', 'photo_location', false)], ['export_calendar', DI::l10n()->t('Export Public Calendar'), DI::l10n()->t('Ability for visitors to download the public calendar'), false, DI::config()->get('feature_lock', 'export_calendar', false)], ['trending_tags', DI::l10n()->t('Trending Tags'), DI::l10n()->t('Show a community page widget with a list of the most popular tags in recent public posts.'), false, DI::config()->get('feature_lock', 'trending_tags', false)], diff --git a/src/Content/Nav.php b/src/Content/Nav.php index 6b4de60361..3024fcaea1 100644 --- a/src/Content/Nav.php +++ b/src/Content/Nav.php @@ -258,10 +258,6 @@ class Nav $nav['settings'] = ['settings', DI::l10n()->t('Settings'), '', DI::l10n()->t('Account settings')]; - if (Feature::isEnabled(local_user(), 'multi_profiles')) { - $nav['profiles'] = ['profiles', DI::l10n()->t('Profiles'), '', DI::l10n()->t('Manage/Edit Profiles')]; - } - $nav['contacts'] = ['contact', DI::l10n()->t('Contacts'), '', DI::l10n()->t('Manage/edit friends and contacts')]; } diff --git a/src/Model/Profile.php b/src/Model/Profile.php index b77bfa8e1d..c40516907e 100644 --- a/src/Model/Profile.php +++ b/src/Model/Profile.php @@ -240,44 +240,20 @@ class Profile * @return array * @throws \Exception */ - public static function getByNickname($nickname, $uid = 0, $profile_id = 0) + public static function getByNickname($nickname, $uid = 0) { - if (!empty(Session::getRemoteContactID($uid))) { - $contact = DBA::selectFirst('contact', ['profile-id'], ['id' => Session::getRemoteContactID($uid)]); - if (DBA::isResult($contact)) { - $profile_id = $contact['profile-id']; - } - } - - $profile = null; - - if ($profile_id) { - $profile = DBA::fetchFirst( - "SELECT `contact`.`id` AS `contact_id`, `contact`.`photo` AS `contact_photo`, - `contact`.`thumb` AS `contact_thumb`, `contact`.`micro` AS `contact_micro`, - `profile`.*, - `contact`.`avatar-date` AS picdate, `contact`.`addr`, `contact`.`url`, `user`.* - FROM `profile` - INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` AND `contact`.`self` - INNER JOIN `user` ON `profile`.`uid` = `user`.`uid` - WHERE `user`.`nickname` = ? AND `profile`.`id` = ? LIMIT 1", - $nickname, - intval($profile_id) - ); - } - if (!DBA::isResult($profile)) { - $profile = DBA::fetchFirst( - "SELECT `contact`.`id` AS `contact_id`, `contact`.`photo` as `contact_photo`, - `contact`.`thumb` AS `contact_thumb`, `contact`.`micro` AS `contact_micro`, - `profile`.*, - `contact`.`avatar-date` AS picdate, `contact`.`addr`, `contact`.`url`, `user`.* - FROM `profile` - INNER JOIN `contact` ON `contact`.`uid` = `profile`.`uid` AND `contact`.`self` - INNER JOIN `user` ON `profile`.`uid` = `user`.`uid` - WHERE `user`.`nickname` = ? AND `profile`.`is-default` LIMIT 1", - $nickname - ); - } + $profile = DBA::fetchFirst( + "SELECT `contact`.`id` AS `contact_id`, `contact`.`photo` AS `contact_photo`, + `contact`.`thumb` AS `contact_thumb`, `contact`.`micro` AS `contact_micro`, + `profile`.*, + `contact`.`avatar-date` AS picdate, `contact`.`addr`, `contact`.`url`, `user`.* + FROM `profile` + INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` AND `contact`.`self` + INNER JOIN `user` ON `profile`.`uid` = `user`.`uid` + WHERE `user`.`nickname` = ? AND `profile`.`uid` = ? LIMIT 1", + $nickname, + intval($uid) + ); return $profile; } diff --git a/src/Module/Contact.php b/src/Module/Contact.php index 6549dd1e0f..a76c2d89c9 100644 --- a/src/Module/Contact.php +++ b/src/Module/Contact.php @@ -100,14 +100,6 @@ class Contact extends BaseModule Hook::callAll('contact_edit_post', $_POST); - $profile_id = intval($_POST['profile-assign'] ?? 0); - if ($profile_id) { - if (!DBA::exists('profile', ['id' => $profile_id, 'uid' => local_user()])) { - notice(DI::l10n()->t('Could not locate selected profile.') . EOL); - return; - } - } - $hidden = !empty($_POST['hidden']); $notify = !empty($_POST['notify']); @@ -124,7 +116,6 @@ class Contact extends BaseModule $info = Strings::escapeHtml(trim($_POST['info'] ?? '')); $r = DBA::update('contact', [ - 'profile-id' => $profile_id, 'priority' => $priority, 'info' => $info, 'hidden' => $hidden, @@ -553,20 +544,13 @@ class Contact extends BaseModule $poll_interval = ContactSelector::pollInterval($contact['priority'], !$poll_enabled); } - $profile_select = null; - if ($contact['network'] == Protocol::DFRN) { - $profile_select = ContactSelector::profileAssign($contact['profile-id'], $contact['network'] !== Protocol::DFRN); - } - // Load contactact related actions like hide, suggest, delete and others $contact_actions = self::getContactActions($contact); if ($contact['uid'] != 0) { - $lbl_vis1 = DI::l10n()->t('Profile Visibility'); $lbl_info1 = DI::l10n()->t('Contact Information / Notes'); $contact_settings_label = DI::l10n()->t('Contact Settings'); } else { - $lbl_vis1 = null; $lbl_info1 = null; $contact_settings_label = null; } @@ -576,8 +560,6 @@ class Contact extends BaseModule '$header' => DI::l10n()->t('Contact'), '$tab_str' => $tab_str, '$submit' => DI::l10n()->t('Submit'), - '$lbl_vis1' => $lbl_vis1, - '$lbl_vis2' => DI::l10n()->t('Please choose the profile you would like to display to %s when viewing your profile securely.', $contact['name']), '$lbl_info1' => $lbl_info1, '$lbl_info2' => DI::l10n()->t('Their personal note'), '$reason' => trim(Strings::escapeTags($contact['reason'])), @@ -598,7 +580,6 @@ class Contact extends BaseModule '$updpub' => DI::l10n()->t('Update public posts'), '$last_update' => $last_update, '$udnow' => DI::l10n()->t('Update now'), - '$profile_select' => $profile_select, '$contact_id' => $contact['id'], '$block_text' => ($contact['blocked'] ? DI::l10n()->t('Unblock') : DI::l10n()->t('Block')), '$ignore_text' => ($contact['readonly'] ? DI::l10n()->t('Unignore') : DI::l10n()->t('Ignore')), diff --git a/view/templates/contact_edit.tpl b/view/templates/contact_edit.tpl index d78d4162ef..5f582e066c 100644 --- a/view/templates/contact_edit.tpl +++ b/view/templates/contact_edit.tpl @@ -84,15 +84,6 @@
    {{/if}} - - {{if $profile_select}} -
    -

    {{$lbl_vis1}}

    -

    {{$lbl_vis2}}

    -
    - {{$profile_select nofilter}} -
    - {{/if}}
    diff --git a/view/templates/profile_entry.tpl b/view/templates/profile_entry.tpl deleted file mode 100644 index e7c3a31dda..0000000000 --- a/view/templates/profile_entry.tpl +++ /dev/null @@ -1,12 +0,0 @@ - -
    -
    - {{$alt}} -
    -
    - -
    {{$visible nofilter}}
    -
    -
    diff --git a/view/templates/profile_listing_header.tpl b/view/templates/profile_listing_header.tpl deleted file mode 100644 index 65f38f3a64..0000000000 --- a/view/templates/profile_listing_header.tpl +++ /dev/null @@ -1,14 +0,0 @@ - -

    {{$header}}

    - -

    - {{$chg_photo}} -

    - - - -
    - {{$profiles nofilter}} -
    diff --git a/view/theme/frio/templates/contact_edit.tpl b/view/theme/frio/templates/contact_edit.tpl index f9454dc654..9bf7b32333 100644 --- a/view/theme/frio/templates/contact_edit.tpl +++ b/view/theme/frio/templates/contact_edit.tpl @@ -172,35 +172,6 @@
    {{/if}} - {{if $lbl_vis1}} -
    - -
    -
    - {{if $profile_select}} -
    -

    {{$lbl_vis2}}

    -
    -
    - {{$profile_select nofilter}} -
    -
    - {{/if}} - -
    - -
    -
    -
    -
    -
    - {{/if}}
    {{* End of the form *}} diff --git a/view/theme/frio/templates/profile_entry.tpl b/view/theme/frio/templates/profile_entry.tpl deleted file mode 100644 index ba8f547171..0000000000 --- a/view/theme/frio/templates/profile_entry.tpl +++ /dev/null @@ -1,15 +0,0 @@ - -
    -
    - {{$alt}} -
    -
    - -
    - {{$visible nofilter}} -
    -
    -
    - diff --git a/view/theme/frio/templates/profile_listing_header.tpl b/view/theme/frio/templates/profile_listing_header.tpl deleted file mode 100644 index 3419c41049..0000000000 --- a/view/theme/frio/templates/profile_listing_header.tpl +++ /dev/null @@ -1,16 +0,0 @@ - -
    -
    -

    {{$header}}

    -
    - - -
    -
    - {{$profiles nofilter}} -
    -
    -
    diff --git a/view/theme/vier/templates/contact_edit.tpl b/view/theme/vier/templates/contact_edit.tpl index bd07f18213..3eaf163fc6 100644 --- a/view/theme/vier/templates/contact_edit.tpl +++ b/view/theme/vier/templates/contact_edit.tpl @@ -85,15 +85,6 @@
    {{/if}} - - {{if $profile_select}} -
    -

    {{$lbl_vis1}}

    -

    {{$lbl_vis2}}

    -
    - {{$profile_select nofilter}} -
    - {{/if}}
    {{/if}} From 62fec2f190a2420b96bbded2880d63e7c8840aab Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 2 Nov 2019 21:19:42 -0400 Subject: [PATCH 03/19] Remove duplicate profile_uid key in App->profile array --- src/Module/Profile/Index.php | 17 +++++++++-------- src/Module/Profile/Status.php | 28 ++++++++++++++-------------- src/Module/Update/Profile.php | 16 ++++++++-------- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/Module/Profile/Index.php b/src/Module/Profile/Index.php index 27d5047d1b..9c5ce05d0c 100644 --- a/src/Module/Profile/Index.php +++ b/src/Module/Profile/Index.php @@ -46,16 +46,18 @@ class Index extends BaseModule { $a = DI::app(); - if (DI::config()->get('system', 'block_public') && !local_user() && !Session::getRemoteContactID($a->profile['profile_uid'])) { + ProfileModel::load($a, $parameters['nickname']); + + $remote_contact_id = Session::getRemoteContactID($a->profile['uid']); + + if (DI::config()->get('system', 'block_public') && !local_user() && !$remote_contact_id) { return Login::form(); } - ProfileModel::load($a, $parameters['nickname']); - DI::page()['htmlhead'] .= "\n"; - $blocked = !local_user() && !Session::getRemoteContactID($a->profile['profile_uid']) && DI::config()->get('system', 'block_public'); - $userblock = !local_user() && !Session::getRemoteContactID($a->profile['profile_uid']) && $a->profile['hidewall']; + $blocked = !local_user() && !$remote_contact_id && DI::config()->get('system', 'block_public'); + $userblock = !local_user() && !$remote_contact_id && $a->profile['hidewall']; if (!empty($a->profile['page-flags']) && $a->profile['page-flags'] == User::PAGE_FLAGS_COMMUNITY) { DI::page()['htmlhead'] .= '' . "\n"; @@ -102,10 +104,9 @@ class Index extends BaseModule Nav::setSelected('home'); - $remote_contact = Session::getRemoteContactID($a->profile['profile_uid']); - $is_owner = local_user() == $a->profile['profile_uid']; + $is_owner = local_user() == $a->profile['uid']; - if (!empty($a->profile['hidewall']) && !$is_owner && !$remote_contact) { + if (!empty($a->profile['hidewall']) && !$is_owner && !$remote_contact_id) { notice(DI::l10n()->t('Access to this profile has been restricted.')); return ''; } diff --git a/src/Module/Profile/Status.php b/src/Module/Profile/Status.php index 56247b20e1..b3d864b512 100644 --- a/src/Module/Profile/Status.php +++ b/src/Module/Profile/Status.php @@ -64,19 +64,19 @@ class Status extends BaseModule $hashtags = $_GET['tag'] ?? ''; - if (DI::config()->get('system', 'block_public') && !local_user() && !Session::getRemoteContactID($a->profile['profile_uid'])) { + if (DI::config()->get('system', 'block_public') && !local_user() && !Session::getRemoteContactID($a->profile['uid'])) { return Login::form(); } $o = ''; - if ($a->profile['profile_uid'] == local_user()) { + if ($a->profile['uid'] == local_user()) { Nav::setSelected('home'); } - $remote_contact = Session::getRemoteContactID($a->profile['profile_uid']); - $is_owner = local_user() == $a->profile['profile_uid']; - $last_updated_key = "profile:" . $a->profile['profile_uid'] . ":" . local_user() . ":" . $remote_contact; + $remote_contact = Session::getRemoteContactID($a->profile['uid']); + $is_owner = local_user() == $a->profile['uid']; + $last_updated_key = "profile:" . $a->profile['uid'] . ":" . local_user() . ":" . $remote_contact; if (!empty($a->profile['hidewall']) && !$is_owner && !$remote_contact) { notice(DI::l10n()->t('Access to this profile has been restricted.') . EOL); @@ -85,7 +85,7 @@ class Status extends BaseModule $o .= ProfileModel::getTabs($a, 'status', $is_owner, $a->profile['nickname']); - $o .= Widget::commonFriendsVisitor($a->profile['profile_uid']); + $o .= Widget::commonFriendsVisitor($a->profile['uid']); $commpage = $a->profile['page-flags'] == User::PAGE_FLAGS_COMMUNITY; $commvisitor = $commpage && $remote_contact; @@ -94,7 +94,7 @@ class Status extends BaseModule DI::page()['aside'] .= Widget::categories(DI::baseUrl() . '/profile/' . $a->profile['nickname'] . '/status', XML::escape($category)); DI::page()['aside'] .= Widget::tagCloud(); - if (Security::canWriteToUserWall($a->profile['profile_uid'])) { + if (Security::canWriteToUserWall($a->profile['uid'])) { $x = [ 'is_owner' => $is_owner, 'allow_location' => ($is_owner || $commvisitor) && $a->profile['allow_location'], @@ -109,14 +109,14 @@ class Status extends BaseModule 'acl' => $is_owner ? ACL::getFullSelectorHTML(DI::page(), $a->user, true) : '', 'bang' => '', 'visitor' => $is_owner || $commvisitor ? 'block' : 'none', - 'profile_uid' => $a->profile['profile_uid'], + 'profile_uid' => $a->profile['uid'], ]; $o .= status_editor($a, $x); } // Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched his/her groups - $sql_extra = Item::getPermissionsSQLByUserId($a->profile['profile_uid']); + $sql_extra = Item::getPermissionsSQLByUserId($a->profile['uid']); $sql_extra2 = ''; $last_updated_array = Session::get('last_updated', []); @@ -125,12 +125,12 @@ class Status extends BaseModule if (!empty($category)) { $sql_post_table = sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", - DBA::escape(Strings::protectSprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($a->profile['profile_uid'])); + DBA::escape(Strings::protectSprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($a->profile['uid'])); } if (!empty($hashtags)) { $sql_post_table .= sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", - DBA::escape(Strings::protectSprintf($hashtags)), intval(TERM_OBJ_POST), intval(TERM_HASHTAG), intval($a->profile['profile_uid'])); + DBA::escape(Strings::protectSprintf($hashtags)), intval(TERM_OBJ_POST), intval(TERM_HASHTAG), intval($a->profile['uid'])); } if (!empty($datequery)) { @@ -142,7 +142,7 @@ class Status extends BaseModule // Does the profile page belong to a forum? // If not then we can improve the performance with an additional condition - $condition = ['uid' => $a->profile['profile_uid'], 'page-flags' => [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]]; + $condition = ['uid' => $a->profile['uid'], 'page-flags' => [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]]; if (!DBA::exists('user', $condition)) { $sql_extra3 = sprintf(" AND `thread`.`contact-id` = %d ", intval(intval($a->profile['contact_id']))); } else { @@ -186,7 +186,7 @@ class Status extends BaseModule $sql_extra2 ORDER BY `thread`.`received` DESC $pager_sql", - $a->profile['profile_uid'] + $a->profile['uid'] ); // Set a time stamp for this page. We will make use of it when we @@ -208,7 +208,7 @@ class Status extends BaseModule $items = DBA::toArray($items_stmt); - $o .= conversation($a, $items, $pager, 'profile', false, false, 'received', $a->profile['profile_uid']); + $o .= conversation($a, $items, $pager, 'profile', false, false, 'received', $a->profile['uid']); $o .= $pager->renderMinimal(count($items)); diff --git a/src/Module/Update/Profile.php b/src/Module/Update/Profile.php index e67082191c..c141bccc35 100644 --- a/src/Module/Update/Profile.php +++ b/src/Module/Update/Profile.php @@ -20,7 +20,7 @@ class Profile extends BaseModule { $a = DI::app(); - if (DI::config()->get('system', 'block_public') && !local_user() && !Session::getRemoteContactID($a->profile['profile_uid'])) { + if (DI::config()->get('system', 'block_public') && !local_user() && !Session::getRemoteContactID($a->profile['uid'])) { throw new ForbiddenException(); } @@ -29,18 +29,18 @@ class Profile extends BaseModule $profile_uid = intval($_GET['p'] ?? 0); // Ensure we've got a profile owner if updating. - $a->profile['profile_uid'] = $profile_uid; + $a->profile['uid'] = $profile_uid; - $remote_contact = Session::getRemoteContactID($a->profile['profile_uid']); - $is_owner = local_user() == $a->profile['profile_uid']; - $last_updated_key = "profile:" . $a->profile['profile_uid'] . ":" . local_user() . ":" . $remote_contact; + $remote_contact = Session::getRemoteContactID($a->profile['uid']); + $is_owner = local_user() == $a->profile['uid']; + $last_updated_key = "profile:" . $a->profile['uid'] . ":" . local_user() . ":" . $remote_contact; if (!empty($a->profile['hidewall']) && !$is_owner && !$remote_contact) { throw new ForbiddenException(DI::l10n()->t('Access to this profile has been restricted.')); } // Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched his/her groups - $sql_extra = Item::getPermissionsSQLByUserId($a->profile['profile_uid']); + $sql_extra = Item::getPermissionsSQLByUserId($a->profile['uid']); $last_updated_array = Session::get('last_updated', []); @@ -70,7 +70,7 @@ class Profile extends BaseModule $sql_extra4 $sql_extra ORDER BY `item`.`received` DESC", - $a->profile['profile_uid'], + $a->profile['uid'], GRAVITY_ACTIVITY ); @@ -99,7 +99,7 @@ class Profile extends BaseModule $items = DBA::toArray($items_stmt); - $o .= conversation($a, $items, $pager, 'profile', $profile_uid, false, 'received', $a->profile['profile_uid']); + $o .= conversation($a, $items, $pager, 'profile', $profile_uid, false, 'received', $a->profile['uid']); header("Content-type: text/html"); echo "\r\n"; From 6857d24995b0844a0cec89588fe874399f631a71 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 7 Nov 2019 22:09:19 -0500 Subject: [PATCH 04/19] [Database] Structure version 1331 - Add profile_field table --- database.sql | 21 ++++++++++++++++++++- static/dbstructure.config.php | 21 ++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/database.sql b/database.sql index 8db6c1d6f0..2b93174546 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2020.03-dev (Dalmatian Bellflower) --- DB_UPDATE_VERSION 1330 +-- DB_UPDATE_VERSION 1331 -- ------------------------------------------ @@ -1053,6 +1053,25 @@ CREATE TABLE IF NOT EXISTS `profile_check` ( PRIMARY KEY(`id`) ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='DFRN remote auth use'; +-- +-- TABLE profile_field +-- +CREATE TABLE IF NOT EXISTS `profile_field` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'sequential ID', + `uid` mediumint(8) unsigned NOT NULL DEFAULT 0 COMMENT 'Owner user id', + `psid` int(10) unsigned DEFAULT NULL COMMENT 'ID of the permission set of this profile field - 0 = public', + `name` varchar(255) NOT NULL DEFAULT '' COMMENT 'Name of the field', + `value` text COMMENT 'Value of the field', + `order` mediumint(8) unsigned NOT NULL DEFAULT 1 COMMENT 'Field ordering per user', + `label` varchar(255) NOT NULL DEFAULT '' COMMENT 'Label of the field', + `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', + `edited` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', + PRIMARY KEY (`id`), + KEY `uid` (`uid`), + KEY `psid` (`psid`), + KEY `order` (`order`) +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Custom profile fields'; + -- -- TABLE push_subscriber -- diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 49934c63cf..6ad1d24178 100755 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -34,7 +34,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1330); + define('DB_UPDATE_VERSION', 1331); } return [ @@ -1145,6 +1145,25 @@ return [ "PRIMARY" => ["id"], ] ], + "profile_field" => [ + "comment" => "Custom profile fields", + "fields" => [ + "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"], + "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "Owner user id"], + "order" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "1", "comment" => "Field ordering per user"], + "psid" => ["type" => "int unsigned", "relation" => ["permissionset" => "id"], "comment" => "ID of the permission set of this profile field - 0 = public"], + "label" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Label of the field"], + "value" => ["type" => "text", "comment" => "Value of the field"], + "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "creation time"], + "edited" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "last edit time"], + ], + "indexes" => [ + "PRIMARY" => ["id"], + "uid" => ["uid"], + "order" => ["order"], + "psid" => ["psid"], + ] + ], "push_subscriber" => [ "comment" => "Used for OStatus: Contains feed subscribers", "fields" => [ From 3297d5c3e66675fff455ba31fc3fdbd5f683e1c5 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 19 Jan 2020 19:21:30 -0500 Subject: [PATCH 05/19] Create new ProfileField classes - Create ProfileField model class - Remove obsolete BaseCollection->models property --- src/BaseCollection.php | 1 - src/Collection/ProfileFields.php | 10 +++ src/Model/ProfileField.php | 24 ++++++ src/Repository/ProfileField.php | 122 +++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 src/Collection/ProfileFields.php create mode 100644 src/Model/ProfileField.php create mode 100644 src/Repository/ProfileField.php diff --git a/src/BaseCollection.php b/src/BaseCollection.php index 4d5803d585..5a20acee7f 100644 --- a/src/BaseCollection.php +++ b/src/BaseCollection.php @@ -24,7 +24,6 @@ abstract class BaseCollection extends \ArrayIterator { parent::__construct($models); - $this->models = $models; $this->totalCount = $totalCount ?? count($models); } diff --git a/src/Collection/ProfileFields.php b/src/Collection/ProfileFields.php new file mode 100644 index 0000000000..e171b839b2 --- /dev/null +++ b/src/Collection/ProfileFields.php @@ -0,0 +1,10 @@ +dba, $this->logger, $data); + } + + /** + * @param array $condition + * @return Model\ProfileField + * @throws \Friendica\Network\HTTPException\NotFoundException + */ + public function selectFirst(array $condition) + { + return parent::selectFirst($condition); + } + + /** + * @param array $condition + * @param array $params + * @return Collection\ProfileFields + * @throws \Exception + */ + public function select(array $condition = [], array $params = []) + { + return parent::select($condition, $params); + } + + /** + * @param array $condition + * @param array $params + * @param int|null $max_id + * @param int|null $since_id + * @param int $limit + * @return Collection\ProfileFields + * @throws \Exception + */ + public function selectByBoundaries(array $condition = [], array $params = [], int $max_id = null, int $since_id = null, int $limit = self::LIMIT) + { + return parent::selectByBoundaries($condition, $params, $max_id, $since_id, $limit); + } + + /** + * @param int $uid Field owner user Id + * @return Collection\ProfileFields + * @throws \Exception + */ + public function selectByUserId(int $uid) + { + return $this->select( + ['uid' => $uid], + ['order' => ['order']] + ); + } + + /** + * Retrieve all custom profile field a given contact is able to access to, including public profile fields. + * + * @param int $cid Private contact id, must be owned by $uid + * @param int $uid Field owner user id + * @return Collection\ProfileFields + * @throws \Exception + */ + public function selectByContactId(int $cid, int $uid) + { + $psids = PermissionSet::get($uid, $cid); + + // Includes public custom fields + $psids[] = 0; + + return $this->select( + ['uid' => $uid, 'psid' => $psids], + ['order' => ['order']] + ); + } + + /** + * @param array $fields + * @return Model\ProfileField|bool + * @throws \Exception + */ + public function insert(array $fields) + { + $fields['created'] = DateTimeFormat::utcNow(); + $fields['edited'] = DateTimeFormat::utcNow(); + + return parent::insert($fields); + } + + /** + * @param Model\ProfileField $model + * @return bool + * @throws \Exception + */ + public function update(BaseModel $model) + { + $model->edited = DateTimeFormat::utcNow(); + + return parent::update($model); + } +} From d475cb50280ccab05b68316884d6931df123665f Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 7 Nov 2019 22:15:57 -0500 Subject: [PATCH 06/19] Replace advanced profile display with custom profile fields - Merge all profile/advanced.tpl theme templates into profile/index.tpl - Remove obsolete Model\Profile::getAdvanced method --- src/DI.php | 8 + src/Model/Profile.php | 147 ---------- src/Module/Profile/Index.php | 271 +++++++++++++++--- src/Module/Settings/Profile/Index.php | 2 +- view/templates/profile/advanced.tpl | 184 ------------ view/templates/profile/index.tpl | 124 ++++++++ view/theme/duepuntozero/style.css | 6 +- .../theme/frio/templates/profile/advanced.tpl | 234 --------------- view/theme/quattro/dark/style.css | 3 + view/theme/quattro/green/style.css | 3 + view/theme/quattro/lilac/style.css | 3 + view/theme/quattro/quattro.less | 4 + view/theme/smoothly/style.css | 12 + view/theme/vier/style.css | 4 + .../theme/vier/templates/profile/advanced.tpl | 186 ------------ 15 files changed, 392 insertions(+), 799 deletions(-) delete mode 100644 view/templates/profile/advanced.tpl create mode 100644 view/templates/profile/index.tpl delete mode 100644 view/theme/frio/templates/profile/advanced.tpl delete mode 100644 view/theme/vier/templates/profile/advanced.tpl diff --git a/src/DI.php b/src/DI.php index e6d9c341b7..709f57707b 100644 --- a/src/DI.php +++ b/src/DI.php @@ -292,6 +292,14 @@ abstract class DI return self::$dice->create(Repository\PermissionSet::class); } + /** + * @return Repository\ProfileField + */ + public static function profileField() + { + return self::$dice->create(Repository\ProfileField::class); + } + // // "Protocol" namespace instances // diff --git a/src/Model/Profile.php b/src/Model/Profile.php index c40516907e..774f419ee7 100644 --- a/src/Model/Profile.php +++ b/src/Model/Profile.php @@ -5,10 +5,7 @@ namespace Friendica\Model; use Friendica\App; -use Friendica\Content\Feature; -use Friendica\Content\ForumManager; use Friendica\Content\Text\BBCode; -use Friendica\Content\Text\HTML; use Friendica\Content\Widget\ContactBlock; use Friendica\Core\Cache\Duration; use Friendica\Core\Hook; @@ -25,7 +22,6 @@ use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; use Friendica\Util\Proxy as ProxyUtils; use Friendica\Util\Strings; -use Friendica\Util\Temporal; class Profile { @@ -690,149 +686,6 @@ class Profile ]); } - public static function getAdvanced(App $a) - { - $uid = intval($a->profile['uid']); - - if ($a->profile['name']) { - $profile = []; - - $profile['fullname'] = [DI::l10n()->t('Full Name:'), $a->profile['name']]; - - if (Feature::isEnabled($uid, 'profile_membersince')) { - $profile['membersince'] = [DI::l10n()->t('Member since:'), DateTimeFormat::local($a->profile['register_date'])]; - } - - if ($a->profile['gender']) { - $profile['gender'] = [DI::l10n()->t('Gender:'), DI::l10n()->t($a->profile['gender'])]; - } - - if (!empty($a->profile['dob']) && $a->profile['dob'] > DBA::NULL_DATE) { - $year_bd_format = DI::l10n()->t('j F, Y'); - $short_bd_format = DI::l10n()->t('j F'); - - $val = DI::l10n()->getDay( - intval($a->profile['dob']) ? - DateTimeFormat::utc($a->profile['dob'] . ' 00:00 +00:00', $year_bd_format) - : DateTimeFormat::utc('2001-' . substr($a->profile['dob'], 5) . ' 00:00 +00:00', $short_bd_format) - ); - - $profile['birthday'] = [DI::l10n()->t('Birthday:'), $val]; - } - - if (!empty($a->profile['dob']) - && $a->profile['dob'] > DBA::NULL_DATE - && $age = Temporal::getAgeByTimezone($a->profile['dob'], $a->profile['timezone']) - ) { - $profile['age'] = [DI::l10n()->t('Age: ') , DI::l10n()->tt('%d year old', '%d years old', $age)]; - } - - if ($a->profile['marital']) { - $profile['marital'] = [DI::l10n()->t('Status:'), DI::l10n()->t($a->profile['marital'])]; - } - - /// @TODO Maybe use x() here, plus below? - if ($a->profile['with']) { - $profile['marital']['with'] = $a->profile['with']; - } - - if (strlen($a->profile['howlong']) && $a->profile['howlong'] > DBA::NULL_DATETIME) { - $profile['howlong'] = Temporal::getRelativeDate($a->profile['howlong'], DI::l10n()->t('for %1$d %2$s')); - } - - if ($a->profile['sexual']) { - $profile['sexual'] = [DI::l10n()->t('Sexual Preference:'), DI::l10n()->t($a->profile['sexual'])]; - } - - if ($a->profile['homepage']) { - $profile['homepage'] = [DI::l10n()->t('Homepage:'), HTML::toLink($a->profile['homepage'])]; - } - - if ($a->profile['hometown']) { - $profile['hometown'] = [DI::l10n()->t('Hometown:'), HTML::toLink($a->profile['hometown'])]; - } - - if ($a->profile['pub_keywords']) { - $profile['pub_keywords'] = [DI::l10n()->t('Tags:'), $a->profile['pub_keywords']]; - } - - if ($a->profile['politic']) { - $profile['politic'] = [DI::l10n()->t('Political Views:'), $a->profile['politic']]; - } - - if ($a->profile['religion']) { - $profile['religion'] = [DI::l10n()->t('Religion:'), $a->profile['religion']]; - } - - if ($txt = BBCode::convert($a->profile['about'])) { - $profile['about'] = [DI::l10n()->t('About:'), $txt]; - } - - if ($txt = BBCode::convert($a->profile['interest'])) { - $profile['interest'] = [DI::l10n()->t('Hobbies/Interests:'), $txt]; - } - - if ($txt = BBCode::convert($a->profile['likes'])) { - $profile['likes'] = [DI::l10n()->t('Likes:'), $txt]; - } - - if ($txt = BBCode::convert($a->profile['dislikes'])) { - $profile['dislikes'] = [DI::l10n()->t('Dislikes:'), $txt]; - } - - if ($txt = BBCode::convert($a->profile['contact'])) { - $profile['contact'] = [DI::l10n()->t('Contact information and Social Networks:'), $txt]; - } - - if ($txt = BBCode::convert($a->profile['music'])) { - $profile['music'] = [DI::l10n()->t('Musical interests:'), $txt]; - } - - if ($txt = BBCode::convert($a->profile['book'])) { - $profile['book'] = [DI::l10n()->t('Books, literature:'), $txt]; - } - - if ($txt = BBCode::convert($a->profile['tv'])) { - $profile['tv'] = [DI::l10n()->t('Television:'), $txt]; - } - - if ($txt = BBCode::convert($a->profile['film'])) { - $profile['film'] = [DI::l10n()->t('Film/dance/culture/entertainment:'), $txt]; - } - - if ($txt = BBCode::convert($a->profile['romance'])) { - $profile['romance'] = [DI::l10n()->t('Love/Romance:'), $txt]; - } - - if ($txt = BBCode::convert($a->profile['work'])) { - $profile['work'] = [DI::l10n()->t('Work/employment:'), $txt]; - } - - if ($txt = BBCode::convert($a->profile['education'])) { - $profile['education'] = [DI::l10n()->t('School/education:'), $txt]; - } - - //show subcribed forum if it is enabled in the usersettings - if (Feature::isEnabled($uid, 'forumlist_profile')) { - $profile['forumlist'] = [DI::l10n()->t('Forums:'), ForumManager::profileAdvanced($uid)]; - } - - if ($a->profile['uid'] == local_user()) { - $profile['edit'] = [DI::baseUrl() . '/settings/profile', DI::l10n()->t('Edit profile'), '', DI::l10n()->t('Edit profile')]; - } - - $tpl = Renderer::getMarkupTemplate('profile/advanced.tpl'); - return Renderer::replaceMacros($tpl, [ - '$title' => DI::l10n()->t('Profile'), - '$basic' => DI::l10n()->t('Basic'), - '$advanced' => DI::l10n()->t('Advanced'), - '$profile' => $profile - ]); - } - - return ''; - } - /** * @param App $a * @param string $current diff --git a/src/Module/Profile/Index.php b/src/Module/Profile/Index.php index 9c5ce05d0c..c0ca0ea066 100644 --- a/src/Module/Profile/Index.php +++ b/src/Module/Profile/Index.php @@ -3,16 +3,27 @@ namespace Friendica\Module\Profile; use Friendica\BaseModule; +use Friendica\Content\Feature; +use Friendica\Content\ForumManager; use Friendica\Content\Nav; +use Friendica\Content\Text\BBCode; +use Friendica\Content\Text\HTML; use Friendica\Core\Hook; +use Friendica\Core\Protocol; +use Friendica\Core\Renderer; use Friendica\Core\Session; use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\DI; -use Friendica\Model\Profile as ProfileModel; +use Friendica\Model\Contact; +use Friendica\Model\Profile; +use Friendica\Model\Term; use Friendica\Model\User; use Friendica\Module\Security\Login; +use Friendica\Network\HTTPException; use Friendica\Protocol\ActivityPub; +use Friendica\Util\DateTimeFormat; +use Friendica\Util\Temporal; require_once 'boot.php'; @@ -46,77 +57,245 @@ class Index extends BaseModule { $a = DI::app(); - ProfileModel::load($a, $parameters['nickname']); + Profile::load($a, $parameters['nickname']); - $remote_contact_id = Session::getRemoteContactID($a->profile['uid']); + if (!$a->profile) { + throw new HTTPException\NotFoundException(DI::l10n()->t('Profile not found.')); + } + + $remote_contact_id = Session::getRemoteContactID($a->profile_uid); if (DI::config()->get('system', 'block_public') && !local_user() && !$remote_contact_id) { return Login::form(); } - DI::page()['htmlhead'] .= "\n"; + $is_owner = local_user() == $a->profile_uid; - $blocked = !local_user() && !$remote_contact_id && DI::config()->get('system', 'block_public'); - $userblock = !local_user() && !$remote_contact_id && $a->profile['hidewall']; + $o = ''; + if (!empty($a->profile['hidewall']) && !$is_owner && !$remote_contact_id) { + throw new HTTPException\ForbiddenException(DI::l10n()->t('Access to this profile has been restricted.')); + } if (!empty($a->profile['page-flags']) && $a->profile['page-flags'] == User::PAGE_FLAGS_COMMUNITY) { DI::page()['htmlhead'] .= '' . "\n"; } - if (!empty($a->profile['openidserver'])) { - DI::page()['htmlhead'] .= '' . "\n"; - } - - if (!empty($a->profile['openid'])) { - $delegate = strstr($a->profile['openid'], '://') ? $a->profile['openid'] : 'https://' . $a->profile['openid']; - DI::page()['htmlhead'] .= '' . "\n"; - } - - // site block - if (!$blocked && !$userblock) { - $keywords = str_replace(['#', ',', ' ', ',,'], ['', ' ', ',', ','], $a->profile['pub_keywords'] ?? ''); - if (strlen($keywords)) { - DI::page()['htmlhead'] .= '' . "\n"; - } - } - - DI::page()['htmlhead'] .= '' . "\n"; - - if (!$a->profile['net-publish'] || $a->profile['hidewall']) { - DI::page()['htmlhead'] .= '' . "\n"; - } - - DI::page()['htmlhead'] .= '' . "\n"; - DI::page()['htmlhead'] .= '' . "\n"; - DI::page()['htmlhead'] .= '' . "\n"; - DI::page()['htmlhead'] .= '' . "\n"; - $uri = urlencode('acct:' . $a->profile['nickname'] . '@' . DI::baseUrl()->getHostname() . (DI::baseUrl()->getUrlPath() ? '/' . DI::baseUrl()->getUrlPath() : '')); - DI::page()['htmlhead'] .= '' . "\n"; - header('Link: <' . DI::baseUrl() . '/xrd/?uri=' . $uri . '>; rel="lrdd"; type="application/xrd+xml"', false); - - $dfrn_pages = ['request', 'confirm', 'notify', 'poll']; - foreach ($dfrn_pages as $dfrn) { - DI::page()['htmlhead'] .= '' . "\n"; - } - DI::page()['htmlhead'] .= '' . "\n"; - - $o = ''; + DI::page()['htmlhead'] .= self::buildHtmlHead($a->profile, $parameters['nickname'], $remote_contact_id); Nav::setSelected('home'); $is_owner = local_user() == $a->profile['uid']; + $o = Profile::getTabs($a, 'profile', $is_owner, $a->profile['nickname']); if (!empty($a->profile['hidewall']) && !$is_owner && !$remote_contact_id) { notice(DI::l10n()->t('Access to this profile has been restricted.')); return ''; } - $o .= ProfileModel::getTabs($a, 'profile', $is_owner, $a->profile['nickname']); + $view_as_contacts = []; + $view_as_contact_id = 0; + if ($is_owner) { + $view_as_contact_id = intval($_GET['viewas'] ?? 0); - $o .= ProfileModel::getAdvanced($a); + $view_as_contacts = Contact::selectToArray(['id', 'name'], [ + 'uid' => local_user(), + 'rel' => [Contact::FOLLOWER, Contact::SHARING, Contact::FRIEND], + 'network' => Protocol::DFRN, + 'blocked' => false, + ]); + + // User manually provided a contact ID they aren't privy to, silently defaulting to their own view + if (!in_array($view_as_contact_id, array_column($view_as_contacts, 'id'))) { + $view_as_contact_id = 0; + } + } + + $basic_fields = []; + + $basic_fields += self::buildField('fullname', DI::l10n()->t('Full Name:'), $a->profile['name']); + + if (Feature::isEnabled($a->profile_uid, 'profile_membersince')) { + $basic_fields += self::buildField( + 'membersince', + DI::l10n()->t('Member since:'), + DateTimeFormat::local($a->profile['register_date']) + ); + } + + if (!empty($a->profile['dob']) && $a->profile['dob'] > DBA::NULL_DATE) { + $year_bd_format = DI::l10n()->t('j F, Y'); + $short_bd_format = DI::l10n()->t('j F'); + + $dob = DI::l10n()->getDay( + intval($a->profile['dob']) ? + DateTimeFormat::utc($a->profile['dob'] . ' 00:00 +00:00', $year_bd_format) + : DateTimeFormat::utc('2001-' . substr($a->profile['dob'], 5) . ' 00:00 +00:00', $short_bd_format) + ); + + $basic_fields += self::buildField('dob', DI::l10n()->t('Birthday:'), $dob); + + if ($age = Temporal::getAgeByTimezone($a->profile['dob'], $a->profile['timezone'])) { + $basic_fields += self::buildField('age', DI::l10n()->t('Age: '), DI::l10n()->tt('%d year old', '%d years old', $age)); + } + } + + if ($a->profile['pdesc']) { + $basic_fields += self::buildField('pdesc', DI::l10n()->t('Description:'), HTML::toLink($a->profile['pdesc'])); + } + + if ($a->profile['xmpp']) { + $basic_fields += self::buildField('xmpp', DI::l10n()->t('XMPP:'), $a->profile['xmpp']); + } + + if ($a->profile['homepage']) { + $basic_fields += self::buildField('homepage', DI::l10n()->t('Homepage:'), HTML::toLink($a->profile['homepage'])); + } + + $o .= Profile::getTabs($a, 'profile', $is_owner, $a->profile['nickname']); + if ( + $a->profile['address'] + || $a->profile['locality'] + || $a->profile['postal-code'] + || $a->profile['region'] + || $a->profile['country-name'] + ) { + $basic_fields += self::buildField('location', DI::l10n()->t('Location:'), Profile::formatLocation($a->profile)); + } + + if ($a->profile['pub_keywords']) { + $tags = []; + foreach (explode(',', $a->profile['pub_keywords']) as $tag_label) { + $tags[] = [ + 'url' => '/search?tag=' . $tag_label, + 'label' => Term::TAG_CHARACTER[Term::HASHTAG] . $tag_label, + ]; + } + + $basic_fields += self::buildField('pub_keywords', DI::l10n()->t('Tags:'), $tags); + } + + $custom_fields = []; + + // Defaults to the current logged in user self contact id to show self-only fields + $contact_id = $view_as_contact_id ?: $remote_contact_id ?: 0; + + if ($is_owner && $contact_id === 0) { + $profile_fields = DI::profileField()->selectByUserId($a->profile_uid); + } else { + $profile_fields = DI::profileField()->selectByContactId($contact_id, $a->profile_uid); + } + + foreach ($profile_fields as $profile_field) { + $custom_fields += self::buildField( + 'custom_' . $profile_field->order, + $profile_field->label, + BBCode::convert($profile_field->value), + 'aprofile custom' + ); + }; + + //show subcribed forum if it is enabled in the usersettings + if (Feature::isEnabled($a->profile_uid, 'forumlist_profile')) { + $custom_fields += self::buildField( + 'forumlist', + DI::l10n()->t('Forums:'), + ForumManager::profileAdvanced($a->profile_uid) + ); + } + + $tpl = Renderer::getMarkupTemplate('profile/index.tpl'); + $o .= Renderer::replaceMacros($tpl, [ + '$title' => DI::l10n()->t('Profile'), + '$view_as_contacts' => $view_as_contacts, + '$view_as_contact_id' => $view_as_contact_id, + '$view_as' => DI::l10n()->t('View profile as:'), + '$basic' => DI::l10n()->t('Basic'), + '$advanced' => DI::l10n()->t('Advanced'), + '$is_owner' => $a->profile_uid == local_user(), + '$query_string' => DI::args()->getQueryString(), + '$basic_fields' => $basic_fields, + '$custom_fields' => $custom_fields, + '$profile' => $a->profile, + '$edit_link' => [ + 'url' => DI::baseUrl() . '/settings/profile', DI::l10n()->t('Edit profile'), + 'title' => '', + 'label' => DI::l10n()->t('Edit profile') + ], + ]); Hook::callAll('profile_advanced', $o); return $o; } + + /** + * Creates a profile field structure to be used in the profile template + * + * @param string $name Arbitrary name of the field + * @param string $label Display label of the field + * @param mixed $value Display value of the field + * @param string $class Optional CSS class to apply to the field + * @return array + */ + private static function buildField(string $name, string $label, $value, string $class = 'aprofile') + { + return [$name => [ + 'id' => 'aprofile-' . $name, + 'class' => $class, + 'label' => $label, + 'value' => $value, + ]]; + } + + private static function buildHtmlHead(array $profile, string $nickname, int $remote_contact_id) + { + $baseUrl = DI::baseUrl(); + + $htmlhead = "\n"; + + if (!empty($profile['page-flags']) && $profile['page-flags'] == User::PAGE_FLAGS_COMMUNITY) { + $htmlhead .= '' . "\n"; + } + + if (!empty($profile['openidserver'])) { + $htmlhead .= '' . "\n"; + } + + if (!empty($profile['openid'])) { + $delegate = strstr($profile['openid'], '://') ? $profile['openid'] : 'https://' . $profile['openid']; + $htmlhead .= '' . "\n"; + } + + // site block + $blocked = !local_user() && !$remote_contact_id && DI::config()->get('system', 'block_public'); + $userblock = !local_user() && !$remote_contact_id && $profile['hidewall']; + if (!$blocked && !$userblock) { + $keywords = str_replace(['#', ',', ' ', ',,'], ['', ' ', ',', ','], $profile['pub_keywords'] ?? ''); + if (strlen($keywords)) { + $htmlhead .= '' . "\n"; + } + } + + $htmlhead .= '' . "\n"; + + if (!$profile['net-publish'] || $profile['hidewall']) { + $htmlhead .= '' . "\n"; + } + + $htmlhead .= '' . "\n"; + $htmlhead .= '' . "\n"; + $htmlhead .= '' . "\n"; + $htmlhead .= '' . "\n"; + $uri = urlencode('acct:' . $profile['nickname'] . '@' . $baseUrl->getHostname() . ($baseUrl->getUrlPath() ? '/' . $baseUrl->getUrlPath() : '')); + $htmlhead .= '' . "\n"; + header('Link: <' . $baseUrl . '/xrd/?uri=' . $uri . '>; rel="lrdd"; type="application/xrd+xml"', false); + + $dfrn_pages = ['request', 'confirm', 'notify', 'poll']; + foreach ($dfrn_pages as $dfrn) { + $htmlhead .= '' . "\n"; + } + $htmlhead .= '' . "\n"; + + return $htmlhead; + } } diff --git a/src/Module/Settings/Profile/Index.php b/src/Module/Settings/Profile/Index.php index e1b1d96b90..c717833670 100644 --- a/src/Module/Settings/Profile/Index.php +++ b/src/Module/Settings/Profile/Index.php @@ -334,7 +334,7 @@ class Index extends BaseSettingsModule '$region' => ['region', DI::l10n()->t('Region/State:'), $profile['region']], '$postal_code' => ['postal_code', DI::l10n()->t('Postal/Zip Code:'), $profile['postal-code']], '$country_name' => ['country_name', DI::l10n()->t('Country:'), $profile['country-name']], - '$age' => ((intval($profile['dob'])) ? '(' . DI::l10n()->t('Age: ') . Temporal::getAgeByTimezone($profile['dob'], $a->user['timezone'], $a->user['timezone']) . ')' : ''), + '$age' => ((intval($profile['dob'])) ? '(' . DI::l10n()->t('Age: ') . DI::l10n()->tt('%d year old', '%d years old', Temporal::getAgeByTimezone($profile['dob'], $a->user['timezone'])) . ')' : ''), '$gender' => DI::l10n()->t(ContactSelector::gender($profile['gender'])), '$marital' => ['selector' => ContactSelector::maritalStatus($profile['marital']), 'value' => DI::l10n()->t($profile['marital'])], '$with' => ['with', DI::l10n()->t('Who: (if applicable)'), strip_tags($profile['with']), DI::l10n()->t('Examples: cathy123, Cathy Williams, cathy@example.com')], diff --git a/view/templates/profile/advanced.tpl b/view/templates/profile/advanced.tpl deleted file mode 100644 index 44e763f393..0000000000 --- a/view/templates/profile/advanced.tpl +++ /dev/null @@ -1,184 +0,0 @@ - -{{include file="section_title.tpl"}} - -
    -
    {{$profile.fullname.0}}
    -
    {{$profile.fullname.1}}
    -
    - -{{if $profile.membersince}} -
    -
    {{$profile.membersince.0}}
    -
    {{$profile.membersince.1}}
    -
    -{{/if}} - -{{if $profile.gender}} -
    -
    {{$profile.gender.0}}
    -
    {{$profile.gender.1}}
    -
    -{{/if}} - -{{if $profile.birthday}} -
    -
    {{$profile.birthday.0}}
    -
    {{$profile.birthday.1}}
    -
    -{{/if}} - -{{if $profile.age}} -
    -
    {{$profile.age.0}}
    -
    {{$profile.age.1}}
    -
    -{{/if}} - -{{if $profile.marital}} -
    -
    {{$profile.marital.0}}
    -
    {{$profile.marital.1}}{{if $profile.marital.with}} ({{$profile.marital.with nofilter}}){{/if}}{{if $profile.howlong}} {{$profile.howlong}}{{/if}}
    -
    -{{/if}} - -{{if $profile.sexual}} -
    -
    {{$profile.sexual.0}}
    -
    {{$profile.sexual.1}}
    -
    -{{/if}} - -{{if $profile.pub_keywords}} -
    -
    {{$profile.pub_keywords.0}}
    -
    {{$profile.pub_keywords.1}}
    -
    -{{/if}} - -{{if $profile.homepage}} -
    -
    {{$profile.homepage.0}}
    -
    {{$profile.homepage.1 nofilter}}
    -
    -{{/if}} - -{{if $profile.hometown}} -
    -
    {{$profile.hometown.0}}
    -
    {{$profile.hometown.1}}
    -
    -{{/if}} - -{{if $profile.politic}} -
    -
    {{$profile.politic.0}}
    -
    {{$profile.politic.1}}
    -
    -{{/if}} - -{{if $profile.religion}} -
    -
    {{$profile.religion.0}}
    -
    {{$profile.religion.1}}
    -
    -{{/if}} - -{{if $profile.about}} -
    -
    {{$profile.about.0}}
    -
    {{$profile.about.1 nofilter}}
    -
    -{{/if}} - -{{if $profile.interest}} -
    -
    {{$profile.interest.0}}
    -
    {{$profile.interest.1 nofilter}}
    -
    -{{/if}} - -{{if $profile.likes}} -
    -
    {{$profile.likes.0}}
    -
    {{$profile.likes.1 nofilter}}
    -
    -{{/if}} - -{{if $profile.dislikes}} -
    -
    {{$profile.dislikes.0}}
    -
    {{$profile.dislikes.1 nofilter}}
    -
    -{{/if}} - -{{if $profile.contact}} -
    -
    {{$profile.contact.0}}
    -
    {{$profile.contact.1 nofilter}}
    -
    -{{/if}} - - -{{if $profile.music}} -
    -
    {{$profile.music.0}}
    -
    {{$profile.music.1 nofilter}}
    -
    -{{/if}} - - -{{if $profile.book}} -
    -
    {{$profile.book.0}}
    -
    {{$profile.book.1 nofilter}}
    -
    -{{/if}} - - -{{if $profile.tv}} -
    -
    {{$profile.tv.0}}
    -
    {{$profile.tv.1 nofilter}}
    -
    -{{/if}} - - -{{if $profile.film}} -
    -
    {{$profile.film.0}}
    -
    {{$profile.film.1 nofilter}}
    -
    -{{/if}} - - -{{if $profile.romance}} -
    -
    {{$profile.romance.0}}
    -
    {{$profile.romance.1 nofilter}}
    -
    -{{/if}} - - -{{if $profile.work}} -
    -
    {{$profile.work.0}}
    -
    {{$profile.work.1 nofilter}}
    -
    -{{/if}} - -{{if $profile.education}} -
    -
    {{$profile.education.0}}
    -
    {{$profile.education.1 nofilter}}
    -
    -{{/if}} - - -{{if $profile.forumlist}} -
    -
    {{$profile.forumlist.0}}
    -
    {{$profile.forumlist.1 nofilter}}
    -
    -{{/if}} - - diff --git a/view/templates/profile/index.tpl b/view/templates/profile/index.tpl new file mode 100644 index 0000000000..8ad4d5eba1 --- /dev/null +++ b/view/templates/profile/index.tpl @@ -0,0 +1,124 @@ +
    + {{include file="section_title.tpl"}} + + {{* The link to edit the profile*}} +{{if $is_owner}} + +{{/if}} + + {{* Frio does split the profile information in "standard" and "advanced". This is the tab menu for switching between this modes *}} + {{if count($custom_fields)}} + + {{/if}} + +
    +
    +
    +
    {{$basic_fields.fullname.label}}
    +
    {{$basic_fields.fullname.value}}
    +
    + + {{if $basic_fields.membersince}} +
    +
    +
    {{$basic_fields.membersince.label}}
    +
    {{$basic_fields.membersince.value}}
    +
    + {{/if}} + + {{if $basic_fields.birthday}} +
    +
    +
    {{$basic_fields.birthday.label}}
    +
    {{$basic_fields.birthday.value}}
    +
    + {{/if}} + + {{if $basic_fields.age}} +
    +
    +
    {{$basic_fields.age.label}}
    +
    {{$basic_fields.age.value}}
    +
    + {{/if}} + + {{if $basic_fields.location}} +
    +
    +
    {{$basic_fields.location.label}}
    +
    {{$basic_fields.location.value}}
    +
    + {{/if}} + + {{if $basic_fields.homepage}} +
    +
    +
    {{$basic_fields.homepage.label}}
    +
    {{$basic_fields.homepage.value nofilter}}
    +
    + {{/if}} + + {{if $basic_fields.xmpp}} +
    +
    +
    {{$basic_fields.xmpp.label}}
    +
    {{$basic_fields.xmpp.value nofilter}}
    +
    + {{/if}} + + {{if $basic_fields.pub_keywords}} +
    +
    +
    {{$basic_fields.pub_keywords.label}}
    +
    + {{foreach $basic_fields.pub_keywords.value as $tag}} + {{$tag.label}} + {{/foreach}} +
    +
    + {{/if}} +
    + + {{if count($custom_fields)}} +
    + {{foreach $custom_fields as $custom_field}} +
    +
    +
    {{$custom_field.label}}
    +
    {{$custom_field.value nofilter}}
    +
    + {{/foreach}} +
    + {{/if}} +
    +
    diff --git a/view/theme/duepuntozero/style.css b/view/theme/duepuntozero/style.css index eceaed1247..b92f0ed0a9 100644 --- a/view/theme/duepuntozero/style.css +++ b/view/theme/duepuntozero/style.css @@ -646,10 +646,14 @@ input#dfrn-url { #profile-edit-links ul { list-style-type: none; } - #profile-edit-links li { margin-top: 10px; } + +#profile-menu { + display: none; +} + .profile-edit-side-div { float: right; } diff --git a/view/theme/frio/templates/profile/advanced.tpl b/view/theme/frio/templates/profile/advanced.tpl deleted file mode 100644 index 3ca4000e6a..0000000000 --- a/view/theme/frio/templates/profile/advanced.tpl +++ /dev/null @@ -1,234 +0,0 @@ -
    -

    {{$title}}

    - - {{* The link to edit the profile*}} - {{if $profile.edit}} - -
    - {{/if}} - - {{* Frio does split the profile information in "standard" and "advanced". This is the tab menu for swithching between this modes *}} - - -
    -
    -
    -
    {{$profile.fullname.0}}
    -
    {{$profile.fullname.1}}
    -
    - - {{if $profile.membersince}} -
    -
    -
    {{$profile.membersince.0}}
    -
    {{$profile.membersince.1}}
    -
    - {{/if}} - - {{if $profile.gender}} -
    -
    -
    {{$profile.gender.0}}
    -
    {{$profile.gender.1}}
    -
    - {{/if}} - - {{if $profile.birthday}} -
    -
    -
    {{$profile.birthday.0}}
    -
    {{$profile.birthday.1}}
    -
    - {{/if}} - - {{if $profile.age}} -
    -
    -
    {{$profile.age.0}}
    -
    {{$profile.age.1}}
    -
    - {{/if}} - - {{if $profile.hometown}} -
    -
    -
    {{$profile.hometown.0}}
    -
    {{$profile.hometown.1}}
    -
    - {{/if}} - - {{if $profile.marital}} -
    -
    -
    {{$profile.marital.0}}
    -
    {{$profile.marital.1}}{{if $profile.marital.with}} ({{$profile.marital.with nofilter}}){{/if}}{{if $profile.howlong}} {{$profile.howlong}}{{/if}}
    -
    - {{/if}} - - {{if $profile.homepage}} -
    -
    -
    {{$profile.homepage.0}}
    -
    {{$profile.homepage.1 nofilter}}
    -
    - {{/if}} - - {{if $profile.about}} -
    -
    -
    {{$profile.about.0}}
    -
    {{$profile.about.1 nofilter}}
    -
    - {{/if}} - - {{if $profile.pub_keywords}} -
    -
    -
    {{$profile.pub_keywords.0}}
    -
    {{$profile.pub_keywords.1}}
    -
    - {{/if}} -
    - -
    - {{if $profile.sexual}} -
    -
    -
    {{$profile.sexual.0}}
    -
    {{$profile.sexual.1}}
    -
    - {{/if}} - - {{if $profile.politic}} -
    -
    -
    {{$profile.politic.0}}
    -
    {{$profile.politic.1}}
    -
    - {{/if}} - - {{if $profile.religion}} -
    -
    -
    {{$profile.religion.0}}
    -
    {{$profile.religion.1}}
    -
    - {{/if}} - - - {{if $profile.interest}} -
    -
    -
    {{$profile.interest.0}}
    -
    {{$profile.interest.1 nofilter}}
    -
    - {{/if}} - - {{if $profile.likes}} -
    -
    -
    {{$profile.likes.0}}
    -
    {{$profile.likes.1 nofilter}}
    -
    - {{/if}} - - {{if $profile.dislikes}} -
    -
    -
    {{$profile.dislikes.0}}
    -
    {{$profile.dislikes.1 nofilter}}
    -
    - {{/if}} - - {{if $profile.contact}} -
    -
    -
    {{$profile.contact.0}}
    -
    {{$profile.contact.1 nofilter}}
    -
    - {{/if}} - - {{if $profile.music}} -
    -
    -
    {{$profile.music.0}}
    -
    {{$profile.music.1 nofilter}}
    -
    - {{/if}} - - - {{if $profile.book}} -
    -
    -
    {{$profile.book.0}}
    -
    {{$profile.book.1 nofilter}}
    -
    - {{/if}} - - - {{if $profile.tv}} -
    -
    -
    {{$profile.tv.0}}
    -
    {{$profile.tv.1 nofilter}}
    -
    - {{/if}} - - - {{if $profile.film}} -
    -
    -
    {{$profile.film.0}}
    -
    {{$profile.film.1 nofilter}}
    -
    - {{/if}} - - - {{if $profile.romance}} -
    -
    -
    {{$profile.romance.0}}
    -
    {{$profile.romance.1 nofilter}}
    -
    - {{/if}} - - - {{if $profile.work}} -
    -
    -
    {{$profile.work.0}}
    -
    {{$profile.work.1 nofilter}}
    -
    - {{/if}} - - {{if $profile.education}} -
    -
    -
    {{$profile.education.0}}
    -
    {{$profile.education.1 nofilter}}
    -
    - {{/if}} - - {{if $profile.forumlist}} -
    -
    -
    {{$profile.forumlist.0}}
    -
    {{$profile.forumlist.1 nofilter}}
    -
    - {{/if}} -
    -
    -
    diff --git a/view/theme/quattro/dark/style.css b/view/theme/quattro/dark/style.css index 0ce009cdb7..4421d5d5d1 100644 --- a/view/theme/quattro/dark/style.css +++ b/view/theme/quattro/dark/style.css @@ -1964,6 +1964,9 @@ ul.tabs li .active { list-style: none; margin-top: 10px; } +#profile-menu { + display: none; +} #profile-edit-default-desc { color: #FF0000; border: 1px solid #FF8888; diff --git a/view/theme/quattro/green/style.css b/view/theme/quattro/green/style.css index c0a1befad9..7bc4a1268a 100644 --- a/view/theme/quattro/green/style.css +++ b/view/theme/quattro/green/style.css @@ -1964,6 +1964,9 @@ ul.tabs li .active { list-style: none; margin-top: 10px; } +#profile-menu { + display: none; +} #profile-edit-default-desc { color: #FF0000; border: 1px solid #FF8888; diff --git a/view/theme/quattro/lilac/style.css b/view/theme/quattro/lilac/style.css index 05cb05b186..7ecad35b22 100644 --- a/view/theme/quattro/lilac/style.css +++ b/view/theme/quattro/lilac/style.css @@ -1964,6 +1964,9 @@ ul.tabs li .active { list-style: none; margin-top: 10px; } +#profile-menu { + display: none; +} #profile-edit-default-desc { color: #FF0000; border: 1px solid #FF8888; diff --git a/view/theme/quattro/quattro.less b/view/theme/quattro/quattro.less index 2406fea538..86cc0ae082 100644 --- a/view/theme/quattro/quattro.less +++ b/view/theme/quattro/quattro.less @@ -1257,6 +1257,10 @@ ul.tabs { margin-top: 10px; } +#profile-menu { + display: none; +} + #profile-edit-default-desc { color: #FF0000; border: 1px solid #FF8888; diff --git a/view/theme/smoothly/style.css b/view/theme/smoothly/style.css index 7e276f4597..61392a2cd1 100644 --- a/view/theme/smoothly/style.css +++ b/view/theme/smoothly/style.css @@ -104,6 +104,14 @@ input[type=submit]:active { top: 1px; } +.btn { + background-color: transparent; + box-shadow: none; + border: none; + padding: 0; + text-align: inherit; +} + #search-text, #search-submit, #search-save { @@ -2127,6 +2135,10 @@ div[id$="wrapper"] br { position: absolute; } +#profile-menu { + display: none; +} + #cropimage-wrapper { float:left; } diff --git a/view/theme/vier/style.css b/view/theme/vier/style.css index d9e1304a90..1655e783bd 100644 --- a/view/theme/vier/style.css +++ b/view/theme/vier/style.css @@ -2406,6 +2406,10 @@ aside #id_password { list-style: none; } +#profile-menu { + display: none; +} + .profile-edit-side-div { /* display: none; */ float: right; diff --git a/view/theme/vier/templates/profile/advanced.tpl b/view/theme/vier/templates/profile/advanced.tpl deleted file mode 100644 index 20c4e84b13..0000000000 --- a/view/theme/vier/templates/profile/advanced.tpl +++ /dev/null @@ -1,186 +0,0 @@ -{{if $profile.edit}} - -{{/if}} - -{{include file="section_title.tpl"}} - -
    -
    {{$profile.fullname.0}}
    -
    {{$profile.fullname.1}}
    -
    - -{{if $profile.membersince}} -
    -
    {{$profile.membersince.0}}
    -
    {{$profile.membersince.1}}
    -
    -{{/if}} - -{{if $profile.gender}} -
    -
    {{$profile.gender.0}}
    -
    {{$profile.gender.1}}
    -
    -{{/if}} - -{{if $profile.birthday}} -
    -
    {{$profile.birthday.0}}
    -
    {{$profile.birthday.1}}
    -
    -{{/if}} - -{{if $profile.age}} -
    -
    {{$profile.age.0}}
    -
    {{$profile.age.1}}
    -
    -{{/if}} - -{{if $profile.marital}} -
    -
    {{$profile.marital.0}}
    -
    {{$profile.marital.1}}{{if $profile.marital.with}} ({{$profile.marital.with}}){{/if}}{{if $profile.howlong}} {{$profile.howlong}}{{/if}}
    -
    -{{/if}} - -{{if $profile.sexual}} -
    -
    {{$profile.sexual.0}}
    -
    {{$profile.sexual.1}}
    -
    -{{/if}} - -{{if $profile.pub_keywords}} -
    -
    {{$profile.pub_keywords.0}}
    -
    {{$profile.pub_keywords.1}}
    -
    -{{/if}} - -{{if $profile.homepage}} -
    -
    {{$profile.homepage.0}}
    -
    {{$profile.homepage.1 nofilter}}
    -
    -{{/if}} - -{{if $profile.hometown}} -
    -
    {{$profile.hometown.0}}
    -
    {{$profile.hometown.1}}
    -
    -{{/if}} - -{{if $profile.politic}} -
    -
    {{$profile.politic.0}}
    -
    {{$profile.politic.1}}
    -
    -{{/if}} - -{{if $profile.religion}} -
    -
    {{$profile.religion.0}}
    -
    {{$profile.religion.1}}
    -
    -{{/if}} - -{{if $profile.about}} -
    -
    {{$profile.about.0}}
    -
    {{$profile.about.1 nofilter}}
    -
    -{{/if}} - -{{if $profile.interest}} -
    -
    {{$profile.interest.0}}
    -
    {{$profile.interest.1 nofilter}}
    -
    -{{/if}} - -{{if $profile.likes}} -
    -
    {{$profile.likes.0}}
    -
    {{$profile.likes.1 nofilter}}
    -
    -{{/if}} - -{{if $profile.dislikes}} -
    -
    {{$profile.dislikes.0}}
    -
    {{$profile.dislikes.1 nofilter}}
    -
    -{{/if}} - -{{if $profile.contact}} -
    -
    {{$profile.contact.0}}
    -
    {{$profile.contact.1 nofilter}}
    -
    -{{/if}} - - -{{if $profile.music}} -
    -
    {{$profile.music.0}}
    -
    {{$profile.music.1 nofilter}}
    -
    -{{/if}} - - -{{if $profile.book}} -
    -
    {{$profile.book.0}}
    -
    {{$profile.book.1 nofilter}}
    -
    -{{/if}} - - -{{if $profile.tv}} -
    -
    {{$profile.tv.0}}
    -
    {{$profile.tv.1 nofilter}}
    -
    -{{/if}} - - -{{if $profile.film}} -
    -
    {{$profile.film.0}}
    -
    {{$profile.film.1 nofilter}}
    -
    -{{/if}} - - -{{if $profile.romance}} -
    -
    {{$profile.romance.0}}
    -
    {{$profile.romance.1 nofilter}}
    -
    -{{/if}} - - -{{if $profile.work}} -
    -
    {{$profile.work.0}}
    -
    {{$profile.work.1 nofilter}}
    -
    -{{/if}} - -{{if $profile.education}} -
    -
    {{$profile.education.0}}
    -
    {{$profile.education.1 nofilter}}
    -
    -{{/if}} - -{{if $profile.forumlist}} -
    -
    {{$profile.forumlist.0}}
    -
    {{$profile.forumlist.1 nofilter}}
    -
    -{{/if}} From d11a0d3814ef4ae43f30fdfd5e6a02b193ac9647 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Mon, 13 Jan 2020 22:22:02 -0500 Subject: [PATCH 07/19] Add permission set lazy loading to Profile Field model --- src/Collection/ProfileFields.php | 9 +++++++- src/Model/ProfileField.php | 35 ++++++++++++++++++++++++++++++++ src/Repository/ProfileField.php | 19 ++++++++++++++--- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/Collection/ProfileFields.php b/src/Collection/ProfileFields.php index e171b839b2..223c3ec148 100644 --- a/src/Collection/ProfileFields.php +++ b/src/Collection/ProfileFields.php @@ -6,5 +6,12 @@ use Friendica\BaseCollection; class ProfileFields extends BaseCollection { - + /** + * @param callable $callback + * @return ProfileFields + */ + public function map(callable $callback) + { + return parent::map($callback); + } } diff --git a/src/Model/ProfileField.php b/src/Model/ProfileField.php index 51b43e33c8..e4192a9809 100644 --- a/src/Model/ProfileField.php +++ b/src/Model/ProfileField.php @@ -3,6 +3,9 @@ namespace Friendica\Model; use Friendica\BaseModel; +use Friendica\Database\Database; +use Friendica\Network\HTTPException; +use Psr\Log\LoggerInterface; /** * Custom profile field model class. @@ -17,8 +20,40 @@ use Friendica\BaseModel; * @property string value * @property string created * @property string edited + * @property PermissionSet permissionset */ class ProfileField extends BaseModel { + /** @var PermissionSet */ + private $permissionset; + /** @var \Friendica\Repository\PermissionSet */ + private $permissionSetRepository; + + public function __construct(Database $dba, LoggerInterface $logger, \Friendica\Repository\PermissionSet $permissionSetRepository, array $data = []) + { + parent::__construct($dba, $logger, $data); + + $this->permissionSetRepository = $permissionSetRepository; + } + + public function __get($name) + { + $this->checkValid(); + + switch ($name) { + case 'permissionset': + $this->permissionset = + $this->permissionset ?? + $this->permissionSetRepository->selectFirst(['id' => $this->psid, 'uid' => $this->uid]); + + $return = $this->permissionset; + break; + default: + $return = parent::__get($name); + break; + } + + return $return; + } } diff --git a/src/Repository/ProfileField.php b/src/Repository/ProfileField.php index 21fd2da7c8..d04104898a 100644 --- a/src/Repository/ProfileField.php +++ b/src/Repository/ProfileField.php @@ -5,9 +5,10 @@ namespace Friendica\Repository; use Friendica\BaseModel; use Friendica\BaseRepository; use Friendica\Collection; +use Friendica\Database\Database; use Friendica\Model; -use Friendica\Model\PermissionSet; use Friendica\Util\DateTimeFormat; +use Psr\Log\LoggerInterface; class ProfileField extends BaseRepository { @@ -17,13 +18,23 @@ class ProfileField extends BaseRepository protected static $collection_class = Collection\ProfileFields::class; + /** @var PermissionSet */ + private $permissionSet; + + public function __construct(Database $dba, LoggerInterface $logger, PermissionSet $permissionSet) + { + parent::__construct($dba, $logger); + + $this->permissionSet = $permissionSet; + } + /** * @param array $data * @return Model\ProfileField */ protected function create(array $data) { - return new Model\ProfileField($this->dba, $this->logger, $data); + return new Model\ProfileField($this->dba, $this->logger, $this->permissionSet, $data); } /** @@ -84,7 +95,9 @@ class ProfileField extends BaseRepository */ public function selectByContactId(int $cid, int $uid) { - $psids = PermissionSet::get($uid, $cid); + $permissionSets = $this->permissionSet->selectByContactId($cid, $uid); + + $psids = $permissionSets->column('id'); // Includes public custom fields $psids[] = 0; From 6657cf7bb1862fac05f84c253b1ed35b476e87b0 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Mon, 13 Jan 2020 22:22:50 -0500 Subject: [PATCH 08/19] Rework profile setting page with custom fields --- src/Collection/ProfileFields.php | 10 + src/Module/Settings/Profile/Index.php | 224 +++---- src/Repository/ProfileField.php | 85 +++ .../templates/settings/profile/field/edit.tpl | 13 + view/templates/settings/profile/index.tpl | 533 ++++------------- .../templates/settings/profile/field/edit.tpl | 29 + .../frio/templates/settings/profile/index.tpl | 180 +----- view/theme/vier/style.css | 1 - .../vier/templates/settings/profile/index.tpl | 552 +++++------------- 9 files changed, 463 insertions(+), 1164 deletions(-) create mode 100644 view/templates/settings/profile/field/edit.tpl create mode 100644 view/theme/frio/templates/settings/profile/field/edit.tpl diff --git a/src/Collection/ProfileFields.php b/src/Collection/ProfileFields.php index 223c3ec148..16c267621b 100644 --- a/src/Collection/ProfileFields.php +++ b/src/Collection/ProfileFields.php @@ -14,4 +14,14 @@ class ProfileFields extends BaseCollection { return parent::map($callback); } + + /** + * @param callable|null $callback + * @param int $flag + * @return ProfileFields + */ + public function filter(callable $callback = null, int $flag = 0) + { + return parent::filter($callback, $flag); + } } diff --git a/src/Module/Settings/Profile/Index.php b/src/Module/Settings/Profile/Index.php index c717833670..778f7c09c7 100644 --- a/src/Module/Settings/Profile/Index.php +++ b/src/Module/Settings/Profile/Index.php @@ -2,8 +2,9 @@ namespace Friendica\Module\Settings\Profile; -use Friendica\Content\ContactSelector; +use Friendica\Core\ACL; use Friendica\Core\Hook; +use Friendica\Core\Protocol; use Friendica\Core\Renderer; use Friendica\Core\Session; use Friendica\Core\Worker; @@ -11,12 +12,12 @@ use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Contact; use Friendica\Model\GContact; -use Friendica\Model\Profile as ProfileModel; +use Friendica\Model\Profile; +use Friendica\Model\ProfileField; use Friendica\Model\User; use Friendica\Module\BaseSettingsModule; use Friendica\Module\Security\Login; use Friendica\Network\HTTPException; -use Friendica\Network\Probe; use Friendica\Util\DateTimeFormat; use Friendica\Util\Strings; use Friendica\Util\Temporal; @@ -29,7 +30,7 @@ class Index extends BaseSettingsModule return; } - $profile = ProfileModel::getByUID(local_user()); + $profile = Profile::getByUID(local_user()); if (!DBA::isResult($profile)) { return; } @@ -66,10 +67,9 @@ class Index extends BaseSettingsModule return; } - $namechanged = $profile['username'] != $name; + $namechanged = $profile['name'] != $name; $pdesc = Strings::escapeTags(trim($_POST['pdesc'])); - $gender = Strings::escapeTags(trim($_POST['gender'])); $address = Strings::escapeTags(trim($_POST['address'])); $locality = Strings::escapeTags(trim($_POST['locality'])); $region = Strings::escapeTags(trim($_POST['region'])); @@ -77,63 +77,6 @@ class Index extends BaseSettingsModule $country_name = Strings::escapeTags(trim($_POST['country_name'])); $pub_keywords = self::cleanKeywords(Strings::escapeTags(trim($_POST['pub_keywords']))); $prv_keywords = self::cleanKeywords(Strings::escapeTags(trim($_POST['prv_keywords']))); - $marital = Strings::escapeTags(trim($_POST['marital'])); - $howlong = Strings::escapeTags(trim($_POST['howlong'])); - - $with = (!empty($_POST['with']) ? Strings::escapeTags(trim($_POST['with'])) : ''); - - if (!strlen($howlong)) { - $howlong = DBA::NULL_DATETIME; - } else { - $howlong = DateTimeFormat::convert($howlong, 'UTC', date_default_timezone_get()); - } - - // linkify the relationship target if applicable - if (strlen($with)) { - if ($with != strip_tags($profile['with'])) { - $contact_url = ''; - $lookup = $with; - if (strpos($lookup, '@') === 0) { - $lookup = substr($lookup, 1); - } - $lookup = str_replace('_', ' ', $lookup); - if (strpos($lookup, '@') || (strpos($lookup, 'http://'))) { - $contact_name = $lookup; - $links = @Probe::lrdd($lookup); - if (count($links)) { - foreach ($links as $link) { - if ($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') { - $contact_url = $link['@attributes']['href']; - } - } - } - } else { - $contact_name = $lookup; - - $contact = Contact::selectFirst( - ['url', 'name'], - ['? IN (`name`, `nick`) AND `uid` = ?', $lookup, local_user()] - ); - - if (DBA::isResult($contact)) { - $contact_url = $contact['url']; - $contact_name = $contact['name']; - } - } - - if ($contact_url) { - $with = str_replace($lookup, '' . $contact_name . '', $with); - if (strpos($with, '@') === 0) { - $with = substr($with, 1); - } - } - } else { - $with = $profile['with']; - } - } - - /// @TODO Not flexible enough for later expansion, let's have more OOP here - $sexual = Strings::escapeTags(trim($_POST['sexual'])); $xmpp = Strings::escapeTags(trim($_POST['xmpp'])); $homepage = Strings::escapeTags(trim($_POST['homepage'])); if ((strpos($homepage, 'http') !== 0) && (strlen($homepage))) { @@ -141,63 +84,34 @@ class Index extends BaseSettingsModule $homepage = 'http://' . $homepage; } - $hometown = Strings::escapeTags(trim($_POST['hometown'])); - $politic = Strings::escapeTags(trim($_POST['politic'])); - $religion = Strings::escapeTags(trim($_POST['religion'])); - - $likes = Strings::escapeHtml(trim($_POST['likes'])); - $dislikes = Strings::escapeHtml(trim($_POST['dislikes'])); - - $about = Strings::escapeHtml(trim($_POST['about'])); - $interest = Strings::escapeHtml(trim($_POST['interest'])); - $contact = Strings::escapeHtml(trim($_POST['contact'])); - $music = Strings::escapeHtml(trim($_POST['music'])); - $book = Strings::escapeHtml(trim($_POST['book'])); - $tv = Strings::escapeHtml(trim($_POST['tv'])); - $film = Strings::escapeHtml(trim($_POST['film'])); - $romance = Strings::escapeHtml(trim($_POST['romance'])); - $work = Strings::escapeHtml(trim($_POST['work'])); - $education = Strings::escapeHtml(trim($_POST['education'])); - $hide_friends = intval(!empty($_POST['hide-friends'])); - DI::pConfig()->set(local_user(), 'system', 'detailed_profile', intval(!empty($_POST['detailed_profile']))); + $profileFields = DI::profileField()->selectByUserId(local_user()); + + $profileFields = DI::profileField()->updateCollectionFromForm( + local_user(), + $profileFields, + $_REQUEST['profile_field'], + $_REQUEST['profile_field_order'] + ); + + DI::profileField()->saveCollection($profileFields); $result = DBA::update( 'profile', [ 'name' => $name, 'pdesc' => $pdesc, - 'gender' => $gender, 'dob' => $dob, 'address' => $address, 'locality' => $locality, 'region' => $region, 'postal-code' => $postal_code, 'country-name' => $country_name, - 'marital' => $marital, - 'with' => $with, - 'howlong' => $howlong, - 'sexual' => $sexual, 'xmpp' => $xmpp, 'homepage' => $homepage, - 'hometown' => $hometown, - 'politic' => $politic, - 'religion' => $religion, 'pub_keywords' => $pub_keywords, 'prv_keywords' => $prv_keywords, - 'likes' => $likes, - 'dislikes' => $dislikes, - 'about' => $about, - 'interest' => $interest, - 'contact' => $contact, - 'music' => $music, - 'book' => $book, - 'tv' => $tv, - 'film' => $film, - 'romance' => $romance, - 'work' => $work, - 'education' => $education, 'hide-friends' => $hide_friends, ], [ @@ -205,7 +119,7 @@ class Index extends BaseSettingsModule 'is-default' => true, ] ); - + if ($result) { info(DI::l10n()->t('Profile updated.')); } else { @@ -241,13 +155,59 @@ class Index extends BaseSettingsModule $o = ''; - $profile = ProfileModel::getByUID(local_user()); + $profile = Profile::getByUID(local_user()); if (!DBA::isResult($profile)) { throw new HTTPException\NotFoundException(); } $a = DI::app(); + $custom_fields = []; + + $profileFields = DI::profileField()->selectByUserId(local_user()); + foreach ($profileFields as $profileField) { + /** @var ProfileField $profileField */ + $defaultPermissions = ACL::getDefaultUserPermissions($profileField->permissionset->toArray()); + + $custom_fields[] = [ + 'id' => $profileField->id, + 'legend' => $profileField->label, + 'fields' => [ + 'label' => ['profile_field[' . $profileField->id . '][label]', DI::l10n()->t('Label:'), $profileField->label, DI::l10n()->t('Empty the label to delete this profile field')], + 'value' => ['profile_field[' . $profileField->id . '][value]', DI::l10n()->t('Value:'), $profileField->value, DI::l10n()->t('BBCodes allowed')], + 'acl' => ACL::getFullSelectorHTML( + DI::page(), + $a->user, + false, + $defaultPermissions, + ['network' => Protocol::DFRN], + 'profile_field[' . $profileField->id . ']' + ), + ], + 'permissions' => DI::l10n()->t('Field Permissions'), + 'permdesc' => DI::l10n()->t("(click to open/close)"), + ]; + }; + + $custom_fields[] = [ + 'id' => 'new', + 'legend' => DI::l10n()->t('Add a new profile field'), + 'fields' => [ + 'label' => ['profile_field[new][label]', DI::l10n()->t('Label:')], + 'value' => ['profile_field[new][value]', DI::l10n()->t('Value:'), '', DI::l10n()->t('BBCodes allowed')], + 'acl' => ACL::getFullSelectorHTML( + DI::page(), + $a->user, + false, + ['allow_cid' => []], + ['network' => Protocol::DFRN], + 'profile_field[new]' + ), + ], + 'permissions' => DI::l10n()->t('Field Permissions'), + 'permdesc' => DI::l10n()->t("(click to open/close)"), + ]; + DI::page()['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('settings/profile/index_head.tpl'), [ '$baseurl' => DI::baseUrl()->get(true), ]); @@ -270,25 +230,9 @@ class Index extends BaseSettingsModule $personal_account = !in_array($a->user['page-flags'], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]); - $detailed_profile = - $personal_account - && DI::pConfig()->get(local_user(), 'system', 'detailed_profile', - DI::pConfig()->get(local_user(), 'system', 'detailled_profile') - ) - ; - $tpl = Renderer::getMarkupTemplate('settings/profile/index.tpl'); $o .= Renderer::replaceMacros($tpl, [ '$personal_account' => $personal_account, - '$detailed_profile' => $detailed_profile, - - '$details' => [ - 'detailed_profile', //Name - DI::l10n()->t('Show more profile fields:'), //Label - $detailed_profile, //Value - '', //Help string - [DI::l10n()->t('No'), DI::l10n()->t('Yes')] //Off - On strings - ], '$form_security_token' => self::getFormSecurityToken('settings_profile'), '$form_security_token_photo' => self::getFormSecurityToken('settings_profile_photo'), @@ -299,30 +243,15 @@ class Index extends BaseSettingsModule '$profpic' => DI::l10n()->t('Change Profile Photo'), '$profpiclink' => '/photos/' . $a->user['nickname'], '$viewprof' => DI::l10n()->t('View this profile'), - '$viewallprof' => DI::l10n()->t('View all profiles'), - '$editvis' => DI::l10n()->t('Edit visibility'), - '$cr_prof' => DI::l10n()->t('Create a new profile using these settings'), - '$cl_prof' => DI::l10n()->t('Clone this profile'), - '$del_prof' => DI::l10n()->t('Delete this profile'), - '$lbl_basic_section' => DI::l10n()->t('Basic information'), + '$lbl_personal_section' => DI::l10n()->t('Personal'), '$lbl_picture_section' => DI::l10n()->t('Profile picture'), '$lbl_location_section' => DI::l10n()->t('Location'), - '$lbl_preferences_section' => DI::l10n()->t('Preferences'), - '$lbl_status_section' => DI::l10n()->t('Status information'), - '$lbl_about_section' => DI::l10n()->t('Additional information'), - '$lbl_interests_section' => DI::l10n()->t('Interests'), - '$lbl_personal_section' => DI::l10n()->t('Personal'), - '$lbl_relation_section' => DI::l10n()->t('Relation'), '$lbl_miscellaneous_section' => DI::l10n()->t('Miscellaneous'), + '$lbl_custom_fields_section' => DI::l10n()->t('Custom Profile Fields'), '$lbl_profile_photo' => DI::l10n()->t('Upload Profile Photo'), - '$lbl_gender' => DI::l10n()->t('Your Gender:'), - '$lbl_marital' => DI::l10n()->t(' Marital Status:'), - '$lbl_sexual' => DI::l10n()->t('Sexual Preference:'), - '$lbl_ex2' => DI::l10n()->t('Example: fishing photography software'), - '$default' => '

    ' . DI::l10n()->t('This is your public profile.
    It may be visible to anybody using the internet.') . '

    ', '$baseurl' => DI::baseUrl()->get(true), '$nickname' => $a->user['nickname'], '$name' => ['name', DI::l10n()->t('Display name:'), $profile['name']], @@ -335,30 +264,11 @@ class Index extends BaseSettingsModule '$postal_code' => ['postal_code', DI::l10n()->t('Postal/Zip Code:'), $profile['postal-code']], '$country_name' => ['country_name', DI::l10n()->t('Country:'), $profile['country-name']], '$age' => ((intval($profile['dob'])) ? '(' . DI::l10n()->t('Age: ') . DI::l10n()->tt('%d year old', '%d years old', Temporal::getAgeByTimezone($profile['dob'], $a->user['timezone'])) . ')' : ''), - '$gender' => DI::l10n()->t(ContactSelector::gender($profile['gender'])), - '$marital' => ['selector' => ContactSelector::maritalStatus($profile['marital']), 'value' => DI::l10n()->t($profile['marital'])], - '$with' => ['with', DI::l10n()->t('Who: (if applicable)'), strip_tags($profile['with']), DI::l10n()->t('Examples: cathy123, Cathy Williams, cathy@example.com')], - '$howlong' => ['howlong', DI::l10n()->t('Since [date]:'), ($profile['howlong'] <= DBA::NULL_DATETIME ? '' : DateTimeFormat::local($profile['howlong']))], - '$sexual' => ['selector' => ContactSelector::sexualPreference($profile['sexual']), 'value' => DI::l10n()->t($profile['sexual'])], - '$about' => ['about', DI::l10n()->t('Tell us about yourself...'), $profile['about']], '$xmpp' => ['xmpp', DI::l10n()->t('XMPP (Jabber) address:'), $profile['xmpp'], DI::l10n()->t('The XMPP address will be propagated to your contacts so that they can follow you.')], '$homepage' => ['homepage', DI::l10n()->t('Homepage URL:'), $profile['homepage']], - '$hometown' => ['hometown', DI::l10n()->t('Hometown:'), $profile['hometown']], - '$politic' => ['politic', DI::l10n()->t('Political Views:'), $profile['politic']], - '$religion' => ['religion', DI::l10n()->t('Religious Views:'), $profile['religion']], '$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)')], '$prv_keywords' => ['prv_keywords', DI::l10n()->t('Private Keywords:'), $profile['prv_keywords'], DI::l10n()->t('(Used for searching profiles, never shown to others)')], - '$likes' => ['likes', DI::l10n()->t('Likes:'), $profile['likes']], - '$dislikes' => ['dislikes', DI::l10n()->t('Dislikes:'), $profile['dislikes']], - '$music' => ['music', DI::l10n()->t('Musical interests'), $profile['music']], - '$book' => ['book', DI::l10n()->t('Books, literature'), $profile['book']], - '$tv' => ['tv', DI::l10n()->t('Television'), $profile['tv']], - '$film' => ['film', DI::l10n()->t('Film/dance/culture/entertainment'), $profile['film']], - '$interest' => ['interest', DI::l10n()->t('Hobbies/Interests'), $profile['interest']], - '$romance' => ['romance', DI::l10n()->t('Love/romance'), $profile['romance']], - '$work' => ['work', DI::l10n()->t('Work/employment'), $profile['work']], - '$education' => ['education', DI::l10n()->t('School/education'), $profile['education']], - '$contact' => ['contact', DI::l10n()->t('Contact information and Social Networks'), $profile['contact']], + '$custom_fields' => $custom_fields, ]); $arr = ['profile' => $profile, 'entry' => $o]; diff --git a/src/Repository/ProfileField.php b/src/Repository/ProfileField.php index d04104898a..3a97e23717 100644 --- a/src/Repository/ProfileField.php +++ b/src/Repository/ProfileField.php @@ -6,6 +6,7 @@ use Friendica\BaseModel; use Friendica\BaseRepository; use Friendica\Collection; use Friendica\Database\Database; +use Friendica\DI; use Friendica\Model; use Friendica\Util\DateTimeFormat; use Psr\Log\LoggerInterface; @@ -132,4 +133,88 @@ class ProfileField extends BaseRepository return parent::update($model); } + + /** + * @param int $uid User Id + * @param Collection\ProfileFields $profileFields Collection of existing profile fields + * @param array $profileFieldInputs Array of profile field form inputs indexed by profile field id + * @param array $profileFieldOrder List of profile field id in order + * @return Collection\ProfileFields + * @throws \Exception + */ + public function updateCollectionFromForm(int $uid, Collection\ProfileFields $profileFields, array $profileFieldInputs, array $profileFieldOrder) + { + $aclFormatter = DI::aclFormatter(); + + // Returns an associative array of id => order values + $profileFieldOrder = array_flip($profileFieldOrder); + + // Creation of the new field + if (!empty($profileFieldInputs['new']['label'])) { + $psid = $this->permissionSet->getIdFromACL( + $uid, + $aclFormatter->toString($profileFieldInputs['new']['contact_allow'] ?? ''), + $aclFormatter->toString($profileFieldInputs['new']['group_allow'] ?? ''), + $aclFormatter->toString($profileFieldInputs['new']['contact_deny'] ?? ''), + $aclFormatter->toString($profileFieldInputs['new']['group_deny'] ?? '') + ); + + $newProfileField = $this->insert([ + 'uid' => $uid, + 'label' => $profileFieldInputs['new']['label'], + 'value' => $profileFieldInputs['new']['value'], + 'psid' => $psid, + 'order' => $profileFieldOrder['new'], + ]); + + $profileFieldInputs[$newProfileField->id] = $profileFieldInputs['new']; + $profileFieldOrder[$newProfileField->id] = $profileFieldOrder['new']; + + $profileFields[] = $newProfileField; + } + + unset($profileFieldInputs['new']); + unset($profileFieldOrder['new']); + + // Prunes profile field whose label has been emptied + $profileFields = $profileFields->filter(function (Model\ProfileField $profileField) use (&$profileFieldInputs, &$profileFieldOrder) { + $keepModel = !isset($profileFieldInputs[$profileField->id]) || !empty($profileFieldInputs[$profileField->id]['label']); + + if (!$keepModel) { + unset($profileFieldInputs[$profileField->id]); + unset($profileFieldOrder[$profileField->id]); + $this->delete($profileField); + } + + return $keepModel; + }); + + // Regenerates the order values if items were deleted + $profileFieldOrder = array_flip(array_keys($profileFieldOrder)); + + // Update existing profile fields from form values + $profileFields = $profileFields->map(function (Model\ProfileField $profileField) use ($uid, $aclFormatter, &$profileFieldInputs, &$profileFieldOrder) { + if (isset($profileFieldInputs[$profileField->id]) && isset($profileFieldOrder[$profileField->id])) { + $psid = $this->permissionSet->getIdFromACL( + $uid, + $aclFormatter->toString($profileFieldInputs[$profileField->id]['contact_allow'] ?? ''), + $aclFormatter->toString($profileFieldInputs[$profileField->id]['group_allow'] ?? ''), + $aclFormatter->toString($profileFieldInputs[$profileField->id]['contact_deny'] ?? ''), + $aclFormatter->toString($profileFieldInputs[$profileField->id]['group_deny'] ?? '') + ); + + $profileField->psid = $psid; + $profileField->label = $profileFieldInputs[$profileField->id]['label']; + $profileField->value = $profileFieldInputs[$profileField->id]['value']; + $profileField->order = $profileFieldOrder[$profileField->id]; + + unset($profileFieldInputs[$profileField->id]); + unset($profileFieldOrder[$profileField->id]); + } + + return $profileField; + }); + + return $profileFields; + } } diff --git a/view/templates/settings/profile/field/edit.tpl b/view/templates/settings/profile/field/edit.tpl new file mode 100644 index 0000000000..6254119f32 --- /dev/null +++ b/view/templates/settings/profile/field/edit.tpl @@ -0,0 +1,13 @@ +
    + {{$profile_field.legend}} + + + + {{include file="field_input.tpl" field=$profile_field.fields.label}} + + {{include file="field_textarea.tpl" field=$profile_field.fields.value}} +
    + Permissions + {{$profile_field.fields.acl nofilter}} +
    +
    \ No newline at end of file diff --git a/view/templates/settings/profile/index.tpl b/view/templates/settings/profile/index.tpl index b02ee175eb..979dfcc9ef 100644 --- a/view/templates/settings/profile/index.tpl +++ b/view/templates/settings/profile/index.tpl @@ -1,442 +1,115 @@ -

    {{$banner}}

    {{$default nofilter}} +
    +
    + -
    - - +
    + + +
    +
    +
    + + +
    +
    +
    + {{$dob nofilter}} +
    +
    + {{$hide_friends nofilter}} +
    + +
    +
    +
    + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    +
    + +
    +
    +
    + + +
    +
    +
    + + +
    +
    {{$xmpp.3}}
    +
    +
    + + +
    +
    {{$pub_keywords.3}}
    +
    +
    + + +
    +
    {{$prv_keywords.3}}
    +
    +
    + +
    +
    -{{if $detailed_profile}} -{{include file="field_yesno.tpl" field=$details}} -
    - - +

    {{$lbl_custom_fields_section}}

    + + {{foreach $custom_fields as $custom_field}} + {{include file="settings/profile/field/edit.tpl" profile_field=$custom_field}} + {{/foreach}} + +
    + +
    +
    +
    -
    - -
    - - -
    -
    - - -
    - -{{$gender nofilter}} -
    -
    - -
    -{{$dob nofilter}} -
    -
    - -{{$hide_friends nofilter}} - -
    - -
    -
    - - -
    - - -
    -
    - -
    - - -
    -
    - - -
    - - -
    -
    - -
    - - -
    -
    - -
    - - -
    -
    - -
    - - -
    -
    - -
    - -
    -
    - -
    - -{{$marital nofilter}} -
    - - - - - -
    - -
    - -{{$sexual nofilter}} -
    -
    - - - -
    - - -
    -
    - -
    - - -
    {{$xmpp.3}}
    -
    - - -
    - - -
    -
    - -
    - - -
    -
    - -
    - - -
    {{$pub_keywords.3}}
    -
    - -
    - - -
    {{$prv_keywords.3}}
    -
    - - -
    - -
    -
    - -
    -

    -{{$about.1}} -

    - - - -
    -
    - - -
    -

    -{{$interest.1}} -

    - - - -
    -
    - - -
    -

    -{{$likes.1}} -

    - - - -
    -
    - - -
    -

    -{{$dislikes.1}} -

    - - - -
    -
    - - -
    -

    -{{$contact.1}} -

    - - - -
    -
    - - -
    - -
    -
    - - -
    -

    -{{$music.1}} -

    - - - -
    -
    - -
    -

    -{{$book.1}} -

    - - - -
    -
    - - - -
    -

    -{{$tv.1}} -

    - - - -
    -
    - - - -
    -

    -{{$film.1}} -

    - - - -
    -
    - - -
    - -
    -
    - - -
    -

    -{{$romance.1}} -

    - - - -
    -
    - - - -
    -

    -{{$work.1}} -

    - - - -
    -
    - - - -
    -

    -{{$education.1}} -

    - - - -
    -
    - - - -
    - -
    -
    - -{{else}} -{{if $personal_account}} -{{include file="field_yesno.tpl" field=$details}} -{{/if}} -
    - - -
    -
    - -{{if $personal_account}} -
    - -{{$gender nofilter}} -
    -
    - -
    -{{$dob nofilter}} -
    -
    -{{/if}} - -
    - - -
    -
    - -
    - - -
    {{$xmpp.3}}
    -
    - - -{{$hide_friends nofilter}} - -
    - - -
    -
    - -
    - - -
    -
    - - -
    - - -
    -
    - -
    - - -
    -
    - -
    - - -
    -
    - -
    - - -
    {{$pub_keywords.3}}
    -
    - -
    - - -
    {{$prv_keywords.3}}
    -
    - -
    -

    -{{$about.1}} -

    - - - -
    -
    - -
    - -
    -
    - - - - - - - - - - - - - - - - - - - - - -{{/if}} - -
    - + diff --git a/view/theme/frio/templates/settings/profile/field/edit.tpl b/view/theme/frio/templates/settings/profile/field/edit.tpl new file mode 100644 index 0000000000..cbfb55d3be --- /dev/null +++ b/view/theme/frio/templates/settings/profile/field/edit.tpl @@ -0,0 +1,29 @@ +
    + {{$profile_field.legend}} + + + + {{include file="field_input.tpl" field=$profile_field.fields.label}} + + {{include file="field_textarea.tpl" field=$profile_field.fields.value}} + + {{* Block for setting default permissions *}} +

    + {{$profile_field.permissions}} {{$profile_field.permdesc}} +

    + + {{* We include the aclModal directly into the template since we cant use frio's default modal *}} + +
    \ No newline at end of file diff --git a/view/theme/frio/templates/settings/profile/index.tpl b/view/theme/frio/templates/settings/profile/index.tpl index b88a6f1a84..57f8845b66 100644 --- a/view/theme/frio/templates/settings/profile/index.tpl +++ b/view/theme/frio/templates/settings/profile/index.tpl @@ -1,4 +1,3 @@ -
    {{include file="section_title.tpl" title=$banner}} @@ -48,15 +47,6 @@
    - {{* Some hints to characteristics of the current profile (if available) *}} - - - {{if $personal_account}} -

    {{include file="field_yesno.tpl" field=$details}}

    - {{/if}} - - {{* friendica differs in $detailled_profile (all fields available and a short Version if this is variable false *}} - {{if $detailed_profile}}
    {{* The personal settings *}}
    @@ -74,12 +64,6 @@ {{include file="field_input.tpl" field=$pdesc}} -
    - - {{$gender nofilter}} -
    -
    - {{$dob nofilter}} {{$hide_friends nofilter}} @@ -107,7 +91,6 @@ {{include file="field_input.tpl" field=$locality}} - {{include file="field_input.tpl" field=$postal_code}}
    @@ -128,43 +111,6 @@
    - {{include file="field_input.tpl" field=$hometown}} - -
    - -
    -
    -
    -
    -
    - - {{* The settings for relations *}} -
    - -
    -
    -
    - - {{$marital.selector nofilter}} -
    -
    - - {{include file="field_input.tpl" field=$with}} - - {{include file="field_input.tpl" field=$howlong}} - -
    - - {{$sexual.selector nofilter}} -
    -
    -
    @@ -192,34 +138,28 @@ {{include file="field_input.tpl" field=$prv_keywords}} - {{include file="field_input.tpl" field=$politic}} +
    + +
    +
    +
    +
    +
    - {{include file="field_input.tpl" field=$religion}} - - - {{include file="field_textarea.tpl" field=$about}} - - {{include file="field_textarea.tpl" field=$contact}} - - {{include file="field_textarea.tpl" field=$interest}} - - {{include file="field_textarea.tpl" field=$likes}} - - {{include file="field_textarea.tpl" field=$dislikes}} - - {{include file="field_textarea.tpl" field=$music}} - - {{include file="field_textarea.tpl" field=$book}} - - {{include file="field_textarea.tpl" field=$tv}} - - {{include file="field_textarea.tpl" field=$film}} - - {{include file="field_textarea.tpl" field=$romance}} - - {{include file="field_textarea.tpl" field=$work}} - - {{include file="field_textarea.tpl" field=$education}} + {{* The miscellanous other settings *}} +
    + +
    +
    + {{foreach $custom_fields as $custom_field}} + {{include file="settings/profile/field/edit.tpl" profile_field=$custom_field}} + {{/foreach}}
    @@ -229,84 +169,6 @@
    - - {{else}} - {{* if $detailed_profile not available a short version of the setting page is displayed *}} - {{include file="field_input.tpl" field=$name}} - - {{if $personal_account}} -
    - - {{$gender nofilter}} -
    -
    - - {{$dob nofilter}} - - {{/if}} - - {{include file="field_input.tpl" field=$homepage}} - - {{include file="field_input.tpl" field=$xmpp}} - - {{$hide_friends nofilter}} - - {{include file="field_input.tpl" field=$address}} - - {{include file="field_input.tpl" field=$locality}} - - {{include file="field_input.tpl" field=$postal_code}} - -
    - - -
    -
    - -
    - - -
    -
    - - {{include file="field_input.tpl" field=$pub_keywords}} - - {{include file="field_input.tpl" field=$prv_keywords}} - - {{include file="field_textarea.tpl" field=$about}} - -
    - -
    -
    - - - - - - - - - - - - - - - - - - - - - - {{/if}}
    diff --git a/view/theme/vier/style.css b/view/theme/vier/style.css index 1655e783bd..914d23fcc3 100644 --- a/view/theme/vier/style.css +++ b/view/theme/vier/style.css @@ -3240,7 +3240,6 @@ img.photo-album-photo { } #profile-edit-wrapper .toggle-section-content { background:#ededed; - max-width:599px; padding:5px; } diff --git a/view/theme/vier/templates/settings/profile/index.tpl b/view/theme/vier/templates/settings/profile/index.tpl index 841c6d17e8..5d7a94c0a1 100644 --- a/view/theme/vier/templates/settings/profile/index.tpl +++ b/view/theme/vier/templates/settings/profile/index.tpl @@ -1,450 +1,168 @@

    {{$banner}}

    -{{$default nofilter}} +
    +
    + -
    + +
    + {{$lbl_picture_section}} » + -
    -{{/if}} - + +
    + {{$lbl_personal_section}} » + +
    -
    - -
    - - -
    -
    - -{{if $personal_account}} -
    - -{{$gender nofilter}} -
    -
    - -
    -{{$dob nofilter}} -
    -
    -{{/if}} - -
    - - -
    -
    {{$xmpp.3}}
    -
    - -
    - - -
    -
    - -{{$hide_friends nofilter}} - -
    - - -
    -
    - -
    - - -
    -
    - - -
    - - -
    -
    - -
    - - -
    -
    -
    - - -
    -
    - -
    - - -
    {{$pub_keywords.3}}
    -
    - -
    - - -
    {{$prv_keywords.3}}
    -
    - -
    -

    -{{$about.1}} -

    - - - -
    -
    - -
    - -
    -
    - - - - - - - - - - - - - - - - - - - - - -{{/if}} - - -
    - + From 9bc78efe68f1e9475d42f40c736f37ed721ddf2b Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 18 Jan 2020 10:41:56 -0500 Subject: [PATCH 09/19] [Composer] Add npm-asset/es-jquery-sortable dependency --- composer.json | 1 + composer.lock | 45 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e372547aac..915c2b08cc 100644 --- a/composer.json +++ b/composer.json @@ -52,6 +52,7 @@ "bower-asset/dompurify": "^1.0", "bower-asset/perfect-scrollbar": "^0.6", "bower-asset/vue": "^2.6", + "npm-asset/es-jquery-sortable": "^0.9.13", "npm-asset/jquery": "^2.0", "npm-asset/jquery-colorbox": "^1.6", "npm-asset/jquery-datetimepicker": "^2.5", diff --git a/composer.lock b/composer.lock index 3a4670b20a..c8fa900ac0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "34ad225ce21474eb84ce78047d9f2c01", + "content-hash": "6659cc3edcbdb9d706019810788d8dc3", "packages": [ { "name": "asika/simple-console", @@ -1215,6 +1215,49 @@ ], "time": "2018-01-03T13:39:39+00:00" }, + { + "name": "npm-asset/es-jquery-sortable", + "version": "0.9.13-patch2", + "dist": { + "type": "tar", + "url": "https://registry.npmjs.org/es-jquery-sortable/-/es-jquery-sortable-0.9.13-patch2.tgz", + "shasum": "a4db16d133fbce1bcd1543c98279902a6b0812a3" + }, + "require": { + "npm-asset/jquery": ">=2.1.2,<3.0.0" + }, + "type": "npm-asset-library", + "extra": { + "npm-asset-bugs": { + "url": "https://github.com/johnny/jquery-sortable/issues" + }, + "npm-asset-main": "./source/js/jquery-sortable.js", + "npm-asset-directories": [], + "npm-asset-repository": { + "type": "git", + "url": "git+https://github.com/johnny/jquery-sortable.git" + }, + "npm-asset-scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + } + }, + "license": [ + "BSD-3" + ], + "authors": [ + "" + ], + "description": "jquery plugin for sortable, nestable lists", + "homepage": "https://github.com/johnny/jquery-sortable", + "keywords": [ + "drag", + "dragging", + "sort", + "sortable", + "sorting" + ], + "time": "2019-11-20T03:55:51+00:00" + }, { "name": "npm-asset/ev-emitter", "version": "1.1.1", From cc007f715d8ee7b25feae428d16823abe1850c2b Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 18 Jan 2020 10:43:28 -0500 Subject: [PATCH 10/19] Add sortability to custom profile fields form --- src/Module/Settings/Profile/Index.php | 4 +++ view/global.css | 34 +++++++++++++++++++ view/js/module/settings/profile/index.js | 13 +++++++ .../templates/settings/profile/field/edit.tpl | 4 +-- view/templates/settings/profile/index.tpl | 2 ++ .../templates/settings/profile/field/edit.tpl | 4 +-- .../frio/templates/settings/profile/index.tpl | 2 ++ .../vier/templates/settings/profile/index.tpl | 2 ++ 8 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 view/js/module/settings/profile/index.js diff --git a/src/Module/Settings/Profile/Index.php b/src/Module/Settings/Profile/Index.php index 778f7c09c7..d719afeacf 100644 --- a/src/Module/Settings/Profile/Index.php +++ b/src/Module/Settings/Profile/Index.php @@ -7,6 +7,7 @@ use Friendica\Core\Hook; use Friendica\Core\Protocol; use Friendica\Core\Renderer; use Friendica\Core\Session; +use Friendica\Core\Theme; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\DI; @@ -162,6 +163,9 @@ class Index extends BaseSettingsModule $a = DI::app(); + DI::page()->registerFooterScript('view/asset/es-jquery-sortable/source/js/jquery-sortable-min.js'); + DI::page()->registerFooterScript(Theme::getPathForFile('js/module/settings/profile/index.js')); + $custom_fields = []; $profileFields = DI::profileField()->selectByUserId(local_user()); diff --git a/view/global.css b/view/global.css index 0eaf4482dc..bf4c21314d 100644 --- a/view/global.css +++ b/view/global.css @@ -639,3 +639,37 @@ span.emoji.mastodon img { display: none; } } + +/* Profile Settings Custom Fields */ +body.dragging, body.dragging * { + cursor: ns-resize !important; +} + +.dragged { + position: absolute; + opacity: 0.5; + z-index: 2000; +} + +#profile-custom-fields > fieldset > legend { + cursor: ns-resize; +} + +#profile-custom-fields div.placeholder { + position: relative; + margin: 0; + padding: 0; + border-top: 1px dotted black; +} +#profile-custom-fields div.placeholder:before { + position: absolute; + content: ""; + width: 0; + height: 0; + margin-top: -7px; + left: -7px; + top: -1px; + border: 7px solid transparent; + border-left-color: black; + border-right: none; +} diff --git a/view/js/module/settings/profile/index.js b/view/js/module/settings/profile/index.js new file mode 100644 index 0000000000..1177e51ae7 --- /dev/null +++ b/view/js/module/settings/profile/index.js @@ -0,0 +1,13 @@ +$(function () { + $("#profile-custom-fields").sortable({ + containerSelector: 'div#profile-custom-fields', + handle: 'legend', + itemSelector: 'fieldset', + placeholder: '
    ', + onDrag: function($item, position, _super, event) { + delete position['left']; + $item.css(position); + event.preventDefault(); + } + }); +}); diff --git a/view/templates/settings/profile/field/edit.tpl b/view/templates/settings/profile/field/edit.tpl index 6254119f32..cff432709e 100644 --- a/view/templates/settings/profile/field/edit.tpl +++ b/view/templates/settings/profile/field/edit.tpl @@ -1,5 +1,5 @@ -
    - {{$profile_field.legend}} +
    + ≡ {{$profile_field.legend}} diff --git a/view/templates/settings/profile/index.tpl b/view/templates/settings/profile/index.tpl index 979dfcc9ef..70db8a3d4b 100644 --- a/view/templates/settings/profile/index.tpl +++ b/view/templates/settings/profile/index.tpl @@ -99,9 +99,11 @@

    {{$lbl_custom_fields_section}}

    +
    {{foreach $custom_fields as $custom_field}} {{include file="settings/profile/field/edit.tpl" profile_field=$custom_field}} {{/foreach}} +
    diff --git a/view/theme/frio/templates/settings/profile/field/edit.tpl b/view/theme/frio/templates/settings/profile/field/edit.tpl index cbfb55d3be..f28e559f5e 100644 --- a/view/theme/frio/templates/settings/profile/field/edit.tpl +++ b/view/theme/frio/templates/settings/profile/field/edit.tpl @@ -1,5 +1,5 @@ -
    - {{$profile_field.legend}} +
    + ≡ {{$profile_field.legend}} diff --git a/view/theme/frio/templates/settings/profile/index.tpl b/view/theme/frio/templates/settings/profile/index.tpl index 57f8845b66..7afe11996e 100644 --- a/view/theme/frio/templates/settings/profile/index.tpl +++ b/view/theme/frio/templates/settings/profile/index.tpl @@ -157,9 +157,11 @@
    +
    {{foreach $custom_fields as $custom_field}} {{include file="settings/profile/field/edit.tpl" profile_field=$custom_field}} {{/foreach}} +
    diff --git a/view/theme/vier/templates/settings/profile/index.tpl b/view/theme/vier/templates/settings/profile/index.tpl index 5d7a94c0a1..8ca6e0f885 100644 --- a/view/theme/vier/templates/settings/profile/index.tpl +++ b/view/theme/vier/templates/settings/profile/index.tpl @@ -150,9 +150,11 @@
    {{$lbl_custom_fields_section}} »