Merge pull request #8156 from MrPetovan/task/7817-custom-fields-part-2

New custom profile fields feature part 2: Feature switcheroo
This commit is contained in:
Philipp 2020-01-24 20:17:52 +01:00 committed by GitHub
commit 09de4a5b47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
86 changed files with 2352 additions and 3855 deletions

View File

@ -355,7 +355,7 @@ function feed_birthday($uid, $tz)
$tz = 'UTC';
}
$profile = DBA::selectFirst('profile', ['dob'], ['is-default' => true, 'uid' => $uid]);
$profile = DBA::selectFirst('profile', ['dob'], ['uid' => $uid]);
if (DBA::isResult($profile)) {
$tmp_dob = substr($profile['dob'], 5);
if (intval($tmp_dob)) {

View File

@ -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",

45
composer.lock generated
View File

@ -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",

View File

@ -1,6 +1,6 @@
-- ------------------------------------------
-- Friendica 2020.03-dev (Dalmatian Bellflower)
-- DB_UPDATE_VERSION 1330
-- DB_UPDATE_VERSION 1332
-- ------------------------------------------
@ -233,7 +233,7 @@ CREATE TABLE IF NOT EXISTS `contact` (
`reason` text COMMENT '',
`closeness` tinyint unsigned NOT NULL DEFAULT 99 COMMENT '',
`info` mediumtext COMMENT '',
`profile-id` int unsigned NOT NULL DEFAULT 0 COMMENT '',
`profile-id` int unsigned COMMENT 'Deprecated',
`bdyear` varchar(4) NOT NULL DEFAULT '' COMMENT '',
`bd` date NOT NULL DEFAULT '0001-01-01' COMMENT '',
`notify_new_posts` boolean NOT NULL DEFAULT '0' COMMENT '',
@ -995,8 +995,8 @@ CREATE TABLE IF NOT EXISTS `process` (
CREATE TABLE IF NOT EXISTS `profile` (
`id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID',
`uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id',
`profile-name` varchar(255) NOT NULL DEFAULT '' COMMENT 'Name of the profile',
`is-default` boolean NOT NULL DEFAULT '0' COMMENT 'Mark this profile as default profile',
`profile-name` varchar(255) COMMENT 'Deprecated',
`is-default` boolean COMMENT 'Deprecated',
`hide-friends` boolean NOT NULL DEFAULT '0' COMMENT 'Hide friend list from viewers of this profile',
`name` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`pdesc` varchar(255) NOT NULL DEFAULT '' COMMENT 'Title or description',
@ -1006,29 +1006,29 @@ CREATE TABLE IF NOT EXISTS `profile` (
`region` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`postal-code` varchar(32) NOT NULL DEFAULT '' COMMENT '',
`country-name` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`hometown` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`gender` varchar(32) NOT NULL DEFAULT '' COMMENT '',
`marital` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`with` text COMMENT '',
`howlong` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
`sexual` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`politic` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`religion` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`hometown` varchar(255) COMMENT 'Deprecated',
`gender` varchar(32) COMMENT 'Deprecated',
`marital` varchar(255) COMMENT 'Deprecated',
`with` text COMMENT 'Deprecated',
`howlong` datetime COMMENT 'Deprecated',
`sexual` varchar(255) COMMENT 'Deprecated',
`politic` varchar(255) COMMENT 'Deprecated',
`religion` varchar(255) COMMENT 'Deprecated',
`pub_keywords` text COMMENT '',
`prv_keywords` text COMMENT '',
`likes` text COMMENT '',
`dislikes` text COMMENT '',
`about` text COMMENT '',
`summary` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`music` text COMMENT '',
`book` text COMMENT '',
`tv` text COMMENT '',
`film` text COMMENT '',
`interest` text COMMENT '',
`romance` text COMMENT '',
`work` text COMMENT '',
`education` text COMMENT '',
`contact` text COMMENT '',
`likes` text COMMENT 'Deprecated',
`dislikes` text COMMENT 'Deprecated',
`about` text COMMENT 'Deprecated',
`summary` varchar(255) COMMENT 'Deprecated',
`music` text COMMENT 'Deprecated',
`book` text COMMENT 'Deprecated',
`tv` text COMMENT 'Deprecated',
`film` text COMMENT 'Deprecated',
`interest` text COMMENT 'Deprecated',
`romance` text COMMENT 'Deprecated',
`work` text COMMENT 'Deprecated',
`education` text COMMENT 'Deprecated',
`contact` text COMMENT 'Deprecated',
`homepage` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`xmpp` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`photo` varchar(255) NOT NULL DEFAULT '' COMMENT '',
@ -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
--

View File

@ -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

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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.

View File

@ -102,7 +102,7 @@ function display_init(App $a)
if ($nickname != $a->user["nickname"]) {
$profile = DBA::fetchFirst("SELECT `profile`.* , `contact`.`avatar-date` AS picdate, `user`.* FROM `profile`
INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` INNER JOIN `user` ON `profile`.`uid` = `user`.`uid`
WHERE `user`.`nickname` = ? AND `profile`.`is-default` AND `contact`.`self` LIMIT 1",
WHERE `user`.`nickname` = ? AND `contact`.`self` LIMIT 1",
$nickname
);
if (DBA::isResult($profile)) {

View File

@ -26,8 +26,7 @@ function msearch_post(App $a)
"SELECT COUNT(*) AS `total`
FROM `profile`
JOIN `user` ON `user`.`uid` = `profile`.`uid`
WHERE `is-default` = 1
AND `user`.`hidewall` = 0
WHERE `user`.`hidewall` = 0
AND MATCH(`pub_keywords`) AGAINST (?)",
$search
);
@ -42,8 +41,7 @@ function msearch_post(App $a)
"SELECT `pub_keywords`, `username`, `nickname`, `user`.`uid`
FROM `user`
JOIN `profile` ON `user`.`uid` = `profile`.`uid`
WHERE `is-default` = 1
AND `user`.`hidewall` = 0
WHERE `user`.`hidewall` = 0
AND MATCH(`pub_keywords`) AGAINST (?)
LIMIT ?, ?",
$search,

View File

@ -879,7 +879,7 @@ function network_tabs(App $a)
{
// item filter tabs
/// @TODO fix this logic, reduce duplication
/// $a->page['content'] .= '<div class="tabs-wrapper">';
/// DI::page()['content'] .= '<div class="tabs-wrapper">';
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

View File

@ -67,7 +67,7 @@ function poco_init(App $a) {
if (! $system_mode && ! $global) {
$users = q("SELECT `user`.*,`profile`.`hide-friends` from user left join profile on `user`.`uid` = `profile`.`uid`
where `user`.`nickname` = '%s' and `profile`.`is-default` = 1 limit 1",
where `user`.`nickname` = '%s' limit 1",
DBA::escape($nickname)
);
if (! DBA::isResult($users) || $users[0]['hidewall'] || $users[0]['hide-friends']) {
@ -140,7 +140,7 @@ function poco_init(App $a) {
`profile`.`postal-code` AS `ppostalcode`, `profile`.`country-name` AS `pcountry`, `user`.`account-type`
FROM `contact` INNER JOIN `profile` ON `profile`.`uid` = `contact`.`uid`
INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
WHERE `self` = 1 AND `profile`.`is-default`
WHERE `self` = 1
AND `contact`.`uid` IN (SELECT `uid` FROM `pconfig` WHERE `cat` = 'system' AND `k` = 'suggestme' AND `v` = 1) LIMIT %d, %d",
intval($startIndex),
intval($itemsPerPage)

View File

@ -1,675 +0,0 @@
<?php
/**
* @file mod/profiles.php
*/
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Content\ContactSelector;
use Friendica\Content\Feature;
use Friendica\Content\Nav;
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Contact;
use Friendica\Model\GContact;
use Friendica\Model\Profile;
use Friendica\Model\User;
use Friendica\Module\Security\Login;
use Friendica\Network\Probe;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Strings;
use Friendica\Util\Temporal;
function profiles_init(App $a) {
Nav::setSelected('profiles');
if (! local_user()) {
return;
}
if (($a->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, '<a href="' . $prf . '">' . $newname . '</a>', $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]&hearts;[/color] ' . DI::l10n()->t('Marital Status');
}
if ($withchanged) {
$changes[] = '[color=#ff0000]&hearts;[/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('<span class="heart">&hearts;</span> 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) ? '<p id="profile-edit-default-desc">' . DI::l10n()->t('This is your <strong>public</strong> profile.<br />It <strong>may</strong> be visible to anybody using the internet.') . '</p>' : ""),
'$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']) ? '<strong>' . DI::l10n()->t('visible to everybody') . '</strong>'
: '<a href="'.'profperm/'.$rr['id'].'" />' . DI::l10n()->t('Edit visibility') . '</a>')
]);
}
$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;
}
}

View File

@ -1,171 +0,0 @@
<?php
/**
* @file mod/profperm.php
*/
use Friendica\App;
use Friendica\Core\Protocol;
use Friendica\Content\Text\HTML;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Profile;
function profperm_init(App $a)
{
if (!local_user()) {
return;
}
$which = $a->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 .= '<h2>' . DI::l10n()->t('Profile Visibility Editor') . '</h2>';
$o .= '<h3>' . DI::l10n()->t('Profile') . ' \'' . $profile['profile-name'] . '\'</h3>';
$o .= '<div id="prof-edit-desc">' . DI::l10n()->t('Click on a contact to add or remove.') . '</div>';
}
$o .= '<div id="prof-update-wrapper">';
if (!empty($change))
$o = '';
$o .= '<div id="prof-members-title">';
$o .= '<h3>' . DI::l10n()->t('Visible To') . '</h3>';
$o .= '</div>';
$o .= '<div id="prof-members">';
$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 .= '</div><div id="prof-members-end"></div>';
$o .= '<hr id="prof-separator" />';
$o .= '<div id="prof-all-contcts-title">';
$o .= '<h3>' . DI::l10n()->t("All Contacts \x28with secure profile access\x29") . '</h3>';
$o .= '</div>';
$o .= '<div id="prof-all-contacts">';
$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 .= '</div><div id="prof-all-contacts-end"></div>';
if (!empty($change)) {
echo $o;
exit();
}
$o .= '</div>';
return $o;
}

View File

@ -27,7 +27,7 @@ function user_allow($hash)
DBA::update('user', ['blocked' => false, 'verified' => true], ['uid' => $register['uid']]);
$profile = DBA::selectFirst('profile', ['net-publish'], ['uid' => $register['uid'], 'is-default' => true]);
$profile = DBA::selectFirst('profile', ['net-publish'], ['uid' => $register['uid']]);
if (DBA::isResult($profile) && $profile['net-publish'] && DI::config()->get('system', 'directory')) {
$url = DI::baseUrl() . '/profile/' . $user['nickname'];

View File

@ -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',
];
@ -611,7 +611,7 @@ function settings_post(App $a)
`name` = '%s',
`net-publish` = %d,
`hide-friends` = %d
WHERE `is-default` = 1 AND `uid` = %d",
WHERE `uid` = %d",
intval($publish),
DBA::escape($username),
intval($net_publish),
@ -978,7 +978,7 @@ function settings_content(App $a)
* ACCOUNT SETTINGS
*/
$profile = DBA::selectFirst('profile', [], ['is-default' => true, 'uid' => local_user()]);
$profile = DBA::selectFirst('profile', [], ['uid' => local_user()]);
if (!DBA::isResult($profile)) {
notice(DI::l10n()->t('Unable to find your profile. Please contact your admin.') . EOL);
return;

View File

@ -1,49 +0,0 @@
<?php
/**
* Module: update_profile
* Purpose: AJAX synchronisation of profile page
*/
use Friendica\App;
use Friendica\DI;
use Friendica\Module\Profile;
function update_profile_content(App $a) {
$profile_uid = intval($_GET["p"]);
header("Content-type: text/html");
echo "<!DOCTYPE html><html><body>\r\n";
// We can remove this hack once Internet Explorer recognises HTML5 natively
echo "<section>";
/**
* 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 = "<br />" . DI::l10n()->t("[Embedded content - reload page to view]") . "<br />";
$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 "</section>";
echo "</body></html>\r\n";
exit();
}

View File

@ -24,7 +24,6 @@ abstract class BaseCollection extends \ArrayIterator
{
parent::__construct($models);
$this->models = $models;
$this->totalCount = $totalCount ?? count($models);
}

View File

@ -0,0 +1,27 @@
<?php
namespace Friendica\Collection;
use Friendica\BaseCollection;
class ProfileFields extends BaseCollection
{
/**
* @param callable $callback
* @return ProfileFields
*/
public function map(callable $callback)
{
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);
}
}

View File

@ -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 .= "<select id=\"contact-profile-selector\" class=\"form-control\" $disabled name=\"profile-assign\" >\r\n";
$s = DBA::select('profile', ['id', 'profile-name', 'is-default'], ['uid' => $_SESSION['uid']]);
$r = DBA::toArray($s);
if (DBA::isResult($r)) {
foreach ($r as $rr) {
$selected = (($rr['id'] == $current || ($current == 0 && $rr['is-default'] == 1)) ? " selected=\"selected\" " : "");
$o .= "<option value=\"{$rr['id']}\" $selected >{$rr['profile-name']}</option>\r\n";
}
}
$o .= "</select>\r\n";
return $o;
}
/**
* @param string $current current
* @param boolean $disabled optional, default false

View File

@ -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)],

View File

@ -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')];
}

View File

@ -8,8 +8,10 @@ use Friendica\App;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
use Friendica\DI;
use Friendica\Model\Contact;
use Friendica\Model\Photo;
use Friendica\Object\Image;
use Friendica\Repository\PermissionSet;
use Friendica\Util\Strings;
use Friendica\Worker\Delivery;
@ -161,23 +163,6 @@ class UserImport
DI::pConfig()->set($newuid, 'system', 'previous_addr', $old_handle);
foreach ($account['profile'] as &$profile) {
foreach ($profile as $k => &$v) {
$v = str_replace([$oldbaseurl, $oldaddr], [$newbaseurl, $newaddr], $v);
foreach (["profile", "avatar"] as $k) {
$v = str_replace($oldbaseurl . "/photo/" . $k . "/" . $olduid . ".jpg", $newbaseurl . "/photo/" . $k . "/" . $newuid . ".jpg", $v);
}
}
$profile['uid'] = $newuid;
$r = self::dbImportAssoc('profile', $profile);
if ($r === false) {
Logger::log("uimport:insert profile " . $profile['profile-name'] . " : ERROR : " . DBA::errorMessage(), Logger::INFO);
info(DI::l10n()->t("User profile creation error"));
DBA::delete('user', ['uid' => $newuid]);
return;
}
}
$errorcount = 0;
foreach ($account['contact'] as &$contact) {
if ($contact['uid'] == $olduid && $contact['self'] == '1') {
@ -253,6 +238,50 @@ class UserImport
}
}
foreach ($account['profile'] as &$profile) {
unset($profile['id']);
$profile['uid'] = $newuid;
foreach ($profile as $k => &$v) {
$v = str_replace([$oldbaseurl, $oldaddr], [$newbaseurl, $newaddr], $v);
foreach (["profile", "avatar"] as $k) {
$v = str_replace($oldbaseurl . "/photo/" . $k . "/" . $olduid . ".jpg", $newbaseurl . "/photo/" . $k . "/" . $newuid . ".jpg", $v);
}
}
if (count($account['profile']) === 1 || $profile['is-default']) {
$r = self::dbImportAssoc('profile', $profile);
if ($r === false) {
Logger::log("uimport:insert profile: ERROR : " . DBA::errorMessage(), Logger::INFO);
info(DI::l10n()->t("User profile creation error"));
DBA::delete('user', ['uid' => $newuid]);
DBA::delete('profile_field', ['uid' => $newuid]);
return;
}
$profile['id'] = DBA::lastInsertId();
}
DI::profileField()->migrateFromLegacyProfile($profile);
}
///@TODO Replace with permissionset import
$self_contact = Contact::selectFirst(['id'], ['uid' => $newuid, 'self' => true]);
$allow_cid = DI::aclFormatter()->toString($self_contact['id']);
$self_psid = DI::permissionSet()->getIdFromACL($newuid, $allow_cid);
foreach ($account['profile_fields'] ?? [] as $profile_field) {
$profile_field['uid'] = $newuid;
///@TODO Replace with permissionset import
$profile_field['psid'] = $profile_field['psid'] ? $self_psid : PermissionSet::PUBLIC;
if (self::dbImportAssoc('profile_field', $profile_field) === false) {
Logger::info("uimport:insert profile field " . $profile_field['id'] . " : ERROR : " . DBA::errorMessage());
}
}
foreach ($account['photo'] as &$photo) {
$photo['uid'] = $newuid;
$photo['data'] = hex2bin($photo['data']);

View File

@ -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
//

View File

@ -723,7 +723,7 @@ class Contact
$fields = ['name', 'photo', 'thumb', 'about', 'address', 'locality', 'region',
'country-name', 'gender', 'pub_keywords', 'xmpp', 'net-publish'];
$profile = DBA::selectFirst('profile', $fields, ['uid' => $uid, 'is-default' => true]);
$profile = DBA::selectFirst('profile', $fields, ['uid' => $uid]);
if (!DBA::isResult($profile)) {
return;
}
@ -800,7 +800,7 @@ class Contact
// Update the profile
$fields = ['photo' => DI::baseUrl() . '/photo/profile/' .$uid . '.' . $file_suffix,
'thumb' => DI::baseUrl() . '/photo/avatar/' . $uid .'.' . $file_suffix];
DBA::update('profile', $fields, ['uid' => $uid, 'is-default' => true]);
DBA::update('profile', $fields, ['uid' => $uid]);
}
}

View File

@ -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
{
@ -39,8 +35,7 @@ class Profile
*/
public static function getByUID($uid)
{
$profile = DBA::selectFirst('profile', [], ['uid' => $uid, 'is-default' => true]);
return $profile;
return DBA::selectFirst('profile', [], ['uid' => $uid]);
}
/**
@ -155,7 +150,7 @@ class Profile
}
}
$profile = self::getByNickname($nickname, $user['uid'], $profile_id);
$profile = self::getByNickname($nickname, $user['uid']);
if (empty($profile) && empty($profiledata)) {
Logger::log('profile error: ' . DI::args()->getQueryString(), Logger::DEBUG);
@ -163,17 +158,7 @@ class Profile
}
if (empty($profile)) {
$profile = ['uid' => 0, 'is-default' => false,'name' => $nickname];
}
// fetch user tags if this isn't the default profile
if (!$profile['is-default']) {
$condition = ['uid' => $profile['uid'], 'is-default' => true];
$profile_id = DBA::selectFirst('profile', ['pub_keywords'], $condition);
if (DBA::isResult($profile_id)) {
$profile['pub_keywords'] = $profile_id['pub_keywords'];
}
$profile = ['uid' => 0, 'name' => $nickname];
}
$a->profile = $profile;
@ -202,7 +187,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']
@ -240,44 +225,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;
}
@ -388,40 +349,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
@ -742,149 +675,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() . '/profiles/' . $a->profile['id'], 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
@ -902,22 +692,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 +760,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 +771,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');
@ -1229,7 +1020,7 @@ class Profile
*/
public static function searchProfiles($start = 0, $count = 100, $search = null)
{
$publish = (DI::config()->get('system', 'publish_all') ? '' : " AND `publish` = 1 ");
$publish = (DI::config()->get('system', 'publish_all') ? '' : "`publish` = 1");
$total = 0;
if (!empty($search)) {
@ -1237,7 +1028,7 @@ class Profile
$cnt = DBA::fetchFirst("SELECT COUNT(*) AS `total`
FROM `profile`
LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed`
WHERE $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed`
AND ((`profile`.`name` LIKE ?) OR
(`user`.`nickname` LIKE ?) OR
(`profile`.`pdesc` LIKE ?) OR
@ -1259,7 +1050,7 @@ class Profile
$cnt = DBA::fetchFirst("SELECT COUNT(*) AS `total`
FROM `profile`
LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed`");
WHERE $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed`");
}
if (DBA::isResult($cnt)) {
@ -1279,7 +1070,7 @@ class Profile
FROM `profile`
LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
LEFT JOIN `contact` ON `contact`.`uid` = `user`.`uid`
WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed` AND `contact`.`self`
WHERE $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed` AND `contact`.`self`
AND ((`profile`.`name` LIKE ?) OR
(`user`.`nickname` LIKE ?) OR
(`profile`.`pdesc` LIKE ?) OR
@ -1306,7 +1097,7 @@ class Profile
FROM `profile`
LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
LEFT JOIN `contact` ON `contact`.`uid` = `user`.`uid`
WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed` AND `contact`.`self`
WHERE $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed` AND `contact`.`self`
$order LIMIT ?,?",
$start, $count
);

View File

@ -0,0 +1,59 @@
<?php
namespace Friendica\Model;
use Friendica\BaseModel;
use Friendica\Database\Database;
use Friendica\Network\HTTPException;
use Psr\Log\LoggerInterface;
/**
* Custom profile field model class.
*
* Custom profile fields are user-created arbitrary profile fields that can be assigned a permission set to restrict its
* display to specific Friendica contacts as it requires magic authentication to work.
*
* @property int uid
* @property int order
* @property int psid
* @property string label
* @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;
}
}

View File

@ -782,9 +782,7 @@ class User
'photo' => DI::baseUrl() . "/photo/profile/{$uid}.jpg",
'thumb' => DI::baseUrl() . "/photo/avatar/{$uid}.jpg",
'publish' => $publish,
'is-default' => 1,
'net-publish' => $netpublish,
'profile-name' => DI::l10n()->t('default')
]);
if (!$insert_result) {
DBA::delete('user', ['uid' => $uid]);
@ -1113,7 +1111,7 @@ class User
$userStmt = DBA::p("SELECT `user`.`uid`, `user`.`login_date`, `contact`.`last-item`
FROM `user`
INNER JOIN `profile` ON `profile`.`uid` = `user`.`uid` AND `profile`.`is-default`
INNER JOIN `profile` ON `profile`.`uid` = `user`.`uid`
INNER JOIN `contact` ON `contact`.`uid` = `user`.`uid` AND `contact`.`self`
WHERE (`profile`.`publish` OR `profile`.`net-publish`) AND `user`.`verified`
AND NOT `user`.`blocked` AND NOT `user`.`account_removed`

View File

@ -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',
];

View File

@ -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,
@ -555,20 +546,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;
}
@ -578,8 +562,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'])),
@ -600,7 +582,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')),

View File

@ -1,361 +0,0 @@
<?php
namespace Friendica\Module;
use Friendica\BaseModule;
use Friendica\Content\Nav;
use Friendica\Content\Pager;
use Friendica\Content\Widget;
use Friendica\Core\ACL;
use Friendica\Core\Hook;
use Friendica\Core\Session;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Item;
use Friendica\Model\Profile as ProfileModel;
use Friendica\Model\User;
use Friendica\Module\Security\Login;
use Friendica\Protocol\ActivityPub;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Security;
use Friendica\Util\Strings;
use Friendica\Util\XML;
require_once 'boot.php';
class Profile extends BaseModule
{
public static $which = '';
public static $profile = 0;
public static function init(array $parameters = [])
{
$a = DI::app();
// @TODO: Replace with parameter from router
if ($a->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'] .= '<meta name="friendica.community" content="true" />' . "\n";
}
if (!empty($a->profile['openidserver'])) {
$page['htmlhead'] .= '<link rel="openid.server" href="' . $a->profile['openidserver'] . '" />' . "\n";
}
if (!empty($a->profile['openid'])) {
$delegate = strstr($a->profile['openid'], '://') ? $a->profile['openid'] : 'https://' . $a->profile['openid'];
$page['htmlhead'] .= '<link rel="openid.delegate" href="' . $delegate . '" />' . "\n";
}
// site block
if (!$blocked && !$userblock) {
$keywords = str_replace(['#', ',', ' ', ',,'], ['', ' ', ',', ','], $a->profile['pub_keywords'] ?? '');
if (strlen($keywords)) {
$page['htmlhead'] .= '<meta name="keywords" content="' . $keywords . '" />' . "\n";
}
}
$page['htmlhead'] .= '<meta name="dfrn-global-visibility" content="' . ($a->profile['net-publish'] ? 'true' : 'false') . '" />' . "\n";
if (!$a->profile['net-publish'] || $a->profile['hidewall']) {
$page['htmlhead'] .= '<meta content="noindex, noarchive" name="robots" />' . "\n";
}
$page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . DI::baseUrl() . '/dfrn_poll/' . self::$which . '" title="DFRN: ' . DI::l10n()->t('%s\'s timeline', $a->profile['username']) . '"/>' . "\n";
$page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . DI::baseUrl() . '/feed/' . self::$which . '/" title="' . DI::l10n()->t('%s\'s posts', $a->profile['username']) . '"/>' . "\n";
$page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . DI::baseUrl() . '/feed/' . self::$which . '/comments" title="' . DI::l10n()->t('%s\'s comments', $a->profile['username']) . '"/>' . "\n";
$page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . DI::baseUrl() . '/feed/' . self::$which . '/activity" title="' . DI::l10n()->t('%s\'s timeline', $a->profile['username']) . '"/>' . "\n";
$uri = urlencode('acct:' . $a->profile['nickname'] . '@' . DI::baseUrl()->getHostname() . (DI::baseUrl()->getUrlPath() ? '/' . DI::baseUrl()->getUrlPath() : ''));
$page['htmlhead'] .= '<link rel="lrdd" type="application/xrd+xml" href="' . DI::baseUrl() . '/xrd/?uri=' . $uri . '" />' . "\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'] .= '<link rel="dfrn-' . $dfrn . '" href="' . DI::baseUrl() . '/dfrn_' . $dfrn . '/' . self::$which . '" />' . "\n";
}
$page['htmlhead'] .= '<link rel="dfrn-poco" href="' . DI::baseUrl() . '/poco/' . self::$which . '" />' . "\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;
}
}

View File

@ -0,0 +1,298 @@
<?php
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\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;
class Index extends BaseModule
{
public static function rawContent(array $parameters = [])
{
if (ActivityPub::isRequest()) {
$user = DBA::selectFirst('user', ['uid'], ['nickname' => $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();
Profile::load($a, $parameters['nickname']);
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();
}
$is_owner = local_user() == $a->profile_uid;
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'] .= '<meta name="friendica.community" content="true" />' . "\n";
}
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 '';
}
$view_as_contacts = [];
$view_as_contact_id = 0;
if ($is_owner) {
$view_as_contact_id = intval($_GET['viewas'] ?? 0);
$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 .= '<meta name="friendica.community" content="true" />' . "\n";
}
if (!empty($profile['openidserver'])) {
$htmlhead .= '<link rel="openid.server" href="' . $profile['openidserver'] . '" />' . "\n";
}
if (!empty($profile['openid'])) {
$delegate = strstr($profile['openid'], '://') ? $profile['openid'] : 'https://' . $profile['openid'];
$htmlhead .= '<link rel="openid.delegate" href="' . $delegate . '" />' . "\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 .= '<meta name="keywords" content="' . $keywords . '" />' . "\n";
}
}
$htmlhead .= '<meta name="dfrn-global-visibility" content="' . ($profile['net-publish'] ? 'true' : 'false') . '" />' . "\n";
if (!$profile['net-publish'] || $profile['hidewall']) {
$htmlhead .= '<meta content="noindex, noarchive" name="robots" />' . "\n";
}
$htmlhead .= '<link rel="alternate" type="application/atom+xml" href="' . $baseUrl . '/dfrn_poll/' . $nickname . '" title="DFRN: ' . DI::l10n()->t('%s\'s timeline', $profile['username']) . '"/>' . "\n";
$htmlhead .= '<link rel="alternate" type="application/atom+xml" href="' . $baseUrl . '/feed/' . $nickname . '/" title="' . DI::l10n()->t('%s\'s posts', $profile['username']) . '"/>' . "\n";
$htmlhead .= '<link rel="alternate" type="application/atom+xml" href="' . $baseUrl . '/feed/' . $nickname . '/comments" title="' . DI::l10n()->t('%s\'s comments', $profile['username']) . '"/>' . "\n";
$htmlhead .= '<link rel="alternate" type="application/atom+xml" href="' . $baseUrl . '/feed/' . $nickname . '/activity" title="' . DI::l10n()->t('%s\'s timeline', $profile['username']) . '"/>' . "\n";
$uri = urlencode('acct:' . $profile['nickname'] . '@' . $baseUrl->getHostname() . ($baseUrl->getUrlPath() ? '/' . $baseUrl->getUrlPath() : ''));
$htmlhead .= '<link rel="lrdd" type="application/xrd+xml" href="' . $baseUrl . '/xrd/?uri=' . $uri . '" />' . "\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 .= '<link rel="dfrn-' . $dfrn . '" href="' . $baseUrl . '/dfrn_' . $dfrn . '/' . $nickname . '" />' . "\n";
}
$htmlhead .= '<link rel="dfrn-poco" href="' . $baseUrl . '/poco/' . $nickname . '" />' . "\n";
return $htmlhead;
}
}

View File

@ -0,0 +1,215 @@
<?php
namespace Friendica\Module\Profile;
use Friendica\BaseModule;
use Friendica\Content\Nav;
use Friendica\Content\Pager;
use Friendica\Content\Widget;
use Friendica\Core\ACL;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Item;
use Friendica\Model\Profile as ProfileModel;
use Friendica\Model\User;
use Friendica\Module\Security\Login;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Security;
use Friendica\Util\Strings;
use Friendica\Util\XML;
class Status extends BaseModule
{
public static function content(array $parameters = [])
{
$args = DI::args();
$a = DI::app();
ProfileModel::load($a, $parameters['nickname']);
if (!$a->profile['net-publish'] || $a->profile['hidewall']) {
DI::page()['htmlhead'] .= '<meta content="noindex, noarchive" name="robots" />' . "\n";
}
DI::page()['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . DI::baseUrl() . '/dfrn_poll/' . $parameters['nickname'] . '" title="DFRN: ' . DI::l10n()->t('%s\'s timeline', $a->profile['username']) . '"/>' . "\n";
DI::page()['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . DI::baseUrl() . '/feed/' . $parameters['nickname'] . '/" title="' . DI::l10n()->t('%s\'s posts', $a->profile['username']) . '"/>' . "\n";
DI::page()['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . DI::baseUrl() . '/feed/' . $parameters['nickname'] . '/comments" title="' . DI::l10n()->t('%s\'s comments', $a->profile['username']) . '"/>' . "\n";
DI::page()['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . DI::baseUrl() . '/feed/' . $parameters['nickname'] . '/activity" title="' . DI::l10n()->t('%s\'s timeline', $a->profile['username']) . '"/>' . "\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['uid'])) {
return Login::form();
}
$o = '';
if ($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 '';
}
$o .= ProfileModel::getTabs($a, 'status', $is_owner, $a->profile['nickname']);
$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() . '/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['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', []);
$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($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 && !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['uid']);
$o .= $pager->renderMinimal(count($items));
return $o;
}
}

View File

@ -0,0 +1,306 @@
<?php
namespace Friendica\Module\Settings\Profile;
use Friendica\Core\ACL;
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;
use Friendica\Model\Contact;
use Friendica\Model\GContact;
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\Util\DateTimeFormat;
use Friendica\Util\Strings;
use Friendica\Util\Temporal;
class Index extends BaseSettingsModule
{
public static function post(array $parameters = [])
{
if (!local_user()) {
return;
}
$profile = Profile::getByUID(local_user());
if (!DBA::isResult($profile)) {
return;
}
self::checkFormSecurityTokenRedirectOnError('/settings/profile', 'settings_profile');
Hook::callAll('profile_post', $_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)) {
notice(DI::l10n()->t('Profile Name is required.'));
return;
}
$namechanged = $profile['name'] != $name;
$pdesc = Strings::escapeTags(trim($_POST['pdesc']));
$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'])));
$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;
}
$hide_friends = intval(!empty($_POST['hide-friends']));
$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,
'dob' => $dob,
'address' => $address,
'locality' => $locality,
'region' => $region,
'postal-code' => $postal_code,
'country-name' => $country_name,
'xmpp' => $xmpp,
'homepage' => $homepage,
'pub_keywords' => $pub_keywords,
'prv_keywords' => $prv_keywords,
'hide-friends' => $hide_friends,
],
['uid' => local_user()]
);
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 = Profile::getByUID(local_user());
if (!DBA::isResult($profile)) {
throw new HTTPException\NotFoundException();
}
$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());
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],
'value' => ['profile_field[' . $profileField->id . '][value]', DI::l10n()->t('Value:'), $profileField->value],
'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:')],
'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),
]);
$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]);
$tpl = Renderer::getMarkupTemplate('settings/profile/index.tpl');
$o .= Renderer::replaceMacros($tpl, [
'$personal_account' => $personal_account,
'$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'),
'$lbl_personal_section' => DI::l10n()->t('Personal'),
'$lbl_picture_section' => DI::l10n()->t('Profile picture'),
'$lbl_location_section' => DI::l10n()->t('Location'),
'$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'),
'$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: ') . DI::l10n()->tt('%d year old', '%d years old', Temporal::getAgeByTimezone($profile['dob'], $a->user['timezone'])) . ')' : ''),
'$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']],
'$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)')],
'$custom_fields_description' => DI::l10n()->t("<p>Custom fields appear on <a href=\"%s\">your profile page</a>.</p>
<p>You can use BBCodes in the field values.</p>
<p>Reorder by dragging the field title.</p>
<p>Empty the label field to remove a custom field.</p>
<p>Non-public fields can only be seen by the selected Friendica contacts or the Friendica contacts in the selected groups.</p>",
'profile/' . $a->user['nickname']
),
'$custom_fields' => $custom_fields,
]);
$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;
}
}

View File

@ -167,7 +167,11 @@ class UserExport extends BaseSettingsModule
$profile = self::exportMultiRow(
sprintf("SELECT * FROM `profile` WHERE `uid` = %d ", intval(local_user()))
sprintf("SELECT *, 'default' AS `profile_name`, 1 AS `is-default` FROM `profile` WHERE `uid` = %d ", intval(local_user()))
);
$profile_fields = self::exportMultiRow(
sprintf("SELECT * FROM `profile_field` WHERE `uid` = %d ", intval(local_user()))
);
$photo = self::exportMultiRow(
@ -196,6 +200,7 @@ class UserExport extends BaseSettingsModule
'user' => $user,
'contact' => $contact,
'profile' => $profile,
'profile_fields' => $profile_fields,
'photo' => $photo,
'pconfig' => $pconfig,
'group' => $group,

View File

@ -0,0 +1,125 @@
<?php
namespace Friendica\Module\Update;
use Friendica\BaseModule;
use Friendica\Content\Pager;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Item;
use Friendica\Model\Profile as ProfileModel;
use Friendica\Network\HTTPException\ForbiddenException;
use Friendica\Util\DateTimeFormat;
class Profile extends BaseModule
{
public static function rawContent(array $parameters = [])
{
$a = DI::app();
if (DI::config()->get('system', 'block_public') && !local_user() && !Session::getRemoteContactID($a->profile['uid'])) {
throw new ForbiddenException();
}
$o = '';
$profile_uid = intval($_GET['p'] ?? 0);
// Ensure we've got a profile owner if updating.
$a->profile['uid'] = $profile_uid;
$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['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['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['uid']);
header("Content-type: text/html");
echo "<!DOCTYPE html><html><body>\r\n";
// We can remove this hack once Internet Explorer recognises HTML5 natively
echo "<section>";
echo $o;
if (DI::pConfig()->get(local_user(), "system", "bandwidth_saver")) {
$replace = "<br />".DI::l10n()->t("[Embedded content - reload page to view]")."<br />";
$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 "</section>";
echo "</body></html>\r\n";
exit();
}
}

View File

@ -224,7 +224,7 @@ class Transmitter
}
$fields = ['locality', 'region', 'country-name'];
$profile = DBA::selectFirst('profile', $fields, ['uid' => $uid, 'is-default' => true]);
$profile = DBA::selectFirst('profile', $fields, ['uid' => $uid]);
if (!DBA::isResult($profile)) {
return [];
}

View File

@ -687,7 +687,7 @@ class DFRN
`profile`.`pub_keywords`, `profile`.`xmpp`, `profile`.`dob`
FROM `profile`
INNER JOIN `user` ON `user`.`uid` = `profile`.`uid`
WHERE `profile`.`is-default` AND NOT `user`.`hidewall` AND `user`.`uid` = %d",
WHERE NOT `user`.`hidewall` AND `user`.`uid` = %d",
intval($owner['uid'])
);
if (DBA::isResult($r)) {

View File

@ -4092,7 +4092,7 @@ class Diaspora
FROM `profile`
INNER JOIN `user` ON `profile`.`uid` = `user`.`uid`
INNER JOIN `contact` ON `profile`.`uid` = `contact`.`uid`
WHERE `user`.`uid` = %d AND `profile`.`is-default` AND `contact`.`self` LIMIT 1",
WHERE `user`.`uid` = %d AND `contact`.`self` LIMIT 1",
intval($uid)
);

View File

@ -1428,7 +1428,7 @@ class OStatus
*/
private static function addAuthor(DOMDocument $doc, array $owner, $show_profile = true)
{
$profile = DBA::selectFirst('profile', ['homepage', 'publish'], ['uid' => $owner['uid'], 'is-default' => true]);
$profile = DBA::selectFirst('profile', ['homepage', 'publish'], ['uid' => $owner['uid']]);
$author = $doc->createElement("author");
XML::addElement($doc, $author, "id", $owner["url"]);
if ($owner['account-type'] == User::ACCOUNT_TYPE_COMMUNITY) {

View File

@ -13,6 +13,9 @@ use Psr\Log\LoggerInterface;
class PermissionSet extends BaseRepository
{
/** @var int Virtual permission set id for public permission */
const PUBLIC = 0;
protected static $table_name = 'permissionset';
protected static $model_class = Model\PermissionSet::class;
@ -47,7 +50,7 @@ class PermissionSet extends BaseRepository
{
if (isset($condition['id']) && !$condition['id']) {
return $this->create([
'id' => 0,
'id' => self::PUBLIC,
'uid' => $condition['uid'] ?? 0,
'allow_cid' => '',
'allow_gid' => '',
@ -109,7 +112,7 @@ class PermissionSet extends BaseRepository
// Public permission
if (!$allow_cid && !$allow_gid && !$deny_cid && !$deny_gid) {
return 0;
return self::PUBLIC;
}
$condition = [

View File

@ -0,0 +1,301 @@
<?php
namespace Friendica\Repository;
use Friendica\BaseModel;
use Friendica\BaseRepository;
use Friendica\Collection;
use Friendica\Core\L10n;
use Friendica\Database\Database;
use Friendica\Database\DBA;
use Friendica\Model;
use Friendica\Util\ACLFormatter;
use Friendica\Util\DateTimeFormat;
use Psr\Log\LoggerInterface;
class ProfileField extends BaseRepository
{
protected static $table_name = 'profile_field';
protected static $model_class = Model\ProfileField::class;
protected static $collection_class = Collection\ProfileFields::class;
/** @var PermissionSet */
private $permissionSet;
/** @var ACLFormatter */
private $aclFormatter;
/** @var L10n */
private $l10n;
public function __construct(Database $dba, LoggerInterface $logger, PermissionSet $permissionSet, ACLFormatter $aclFormatter, L10n $l10n)
{
parent::__construct($dba, $logger);
$this->permissionSet = $permissionSet;
$this->aclFormatter = $aclFormatter;
$this->l10n = $l10n;
}
/**
* @param array $data
* @return Model\ProfileField
*/
protected function create(array $data)
{
return new Model\ProfileField($this->dba, $this->logger, $this->permissionSet, $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)
{
$permissionSets = $this->permissionSet->selectByContactId($cid, $uid);
$psids = $permissionSets->column('id');
// 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);
}
/**
* @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)
{
// 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,
$this->aclFormatter->toString($profileFieldInputs['new']['contact_allow'] ?? ''),
$this->aclFormatter->toString($profileFieldInputs['new']['group_allow'] ?? ''),
$this->aclFormatter->toString($profileFieldInputs['new']['contact_deny'] ?? ''),
$this->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, &$profileFieldInputs, &$profileFieldOrder) {
if (isset($profileFieldInputs[$profileField->id]) && isset($profileFieldOrder[$profileField->id])) {
$psid = $this->permissionSet->getIdFromACL(
$uid,
$this->aclFormatter->toString($profileFieldInputs[$profileField->id]['contact_allow'] ?? ''),
$this->aclFormatter->toString($profileFieldInputs[$profileField->id]['group_allow'] ?? ''),
$this->aclFormatter->toString($profileFieldInputs[$profileField->id]['contact_deny'] ?? ''),
$this->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;
}
/**
* Migrates a legacy profile to the new slimmer profile with extra custom fields.
* Multi profiles are converted to ACl-protected custom fields and deleted.
*
* @param array $profile Profile table row
* @throws \Exception
*/
public function migrateFromLegacyProfile(array $profile)
{
// Already processed, aborting
if ($profile['is-default'] === null) {
return;
}
if (!$profile['is-default']) {
$contacts = Model\Contact::selectToArray(['id'], ['uid' => $profile['uid'], 'profile-id' => $profile['id']]);
if (!count($contacts)) {
// No contact visibility selected defaults to user-only permission
$contacts = Model\Contact::selectToArray(['id'], ['uid' => $profile['uid'], 'self' => true]);
}
$allow_cid = $this->aclFormatter->toString(array_column($contacts, 'id'));
}
$psid = $this->permissionSet->getIdFromACL($profile['uid'], $allow_cid ?? '');
$order = 1;
$custom_fields = [
'hometown' => $this->l10n->t('Hometown:'),
'gender' => $this->l10n->t('Gender:'),
'marital' => $this->l10n->t('Marital Status:'),
'with' => $this->l10n->t('With:'),
'howlong' => $this->l10n->t('Since:'),
'sexual' => $this->l10n->t('Sexual Preference:'),
'politic' => $this->l10n->t('Political Views:'),
'religion' => $this->l10n->t('Religious Views:'),
'likes' => $this->l10n->t('Likes:'),
'dislikes' => $this->l10n->t('Dislikes:'),
'about' => $this->l10n->t('About:'),
'summary' => $this->l10n->t('Summary'),
'music' => $this->l10n->t('Musical interests'),
'book' => $this->l10n->t('Books, literature'),
'tv' => $this->l10n->t('Television'),
'film' => $this->l10n->t('Film/dance/culture/entertainment'),
'interest' => $this->l10n->t('Hobbies/Interests'),
'romance' => $this->l10n->t('Love/romance'),
'work' => $this->l10n->t('Work/employment'),
'education' => $this->l10n->t('School/education'),
'contact' => $this->l10n->t('Contact information and Social Networks'),
];
foreach ($custom_fields as $field => $label) {
if (!empty($profile[$field]) && $profile[$field] > DBA::NULL_DATE && $profile[$field] > DBA::NULL_DATETIME) {
$this->insert([
'uid' => $profile['uid'],
'psid' => $psid,
'order' => $order++,
'label' => trim($label, ':'),
'value' => $profile[$field],
]);
}
$profile[$field] = null;
}
if ($profile['is-default']) {
$profile['profile-name'] = null;
$profile['is-default'] = null;
$this->dba->update('profile', $profile, ['id' => $profile['id']]);
} elseif (!empty($profile['id'])) {
$this->dba->delete('profile', ['id' => $profile['id']]);
}
}
}

View File

@ -46,7 +46,7 @@ class Directory
$r = q("SELECT `url` FROM `contact`
INNER JOIN `profile` ON `profile`.`uid` = `contact`.`uid`
INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
WHERE `contact`.`self` AND `profile`.`net-publish` AND `profile`.`is-default` AND
WHERE `contact`.`self` AND `profile`.`net-publish` AND
NOT `user`.`account_expired` AND `user`.`verified`");
if (DBA::isResult($r)) {

View File

@ -34,7 +34,7 @@
use Friendica\Database\DBA;
if (!defined('DB_UPDATE_VERSION')) {
define('DB_UPDATE_VERSION', 1330);
define('DB_UPDATE_VERSION', 1332);
}
return [
@ -277,7 +277,7 @@ return [
"reason" => ["type" => "text", "comment" => ""],
"closeness" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "99", "comment" => ""],
"info" => ["type" => "mediumtext", "comment" => ""],
"profile-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => ""],
"profile-id" => ["type" => "int unsigned", "comment" => "Deprecated"],
"bdyear" => ["type" => "varchar(4)", "not null" => "1", "default" => "", "comment" => ""],
"bd" => ["type" => "date", "not null" => "1", "default" => DBA::NULL_DATE, "comment" => ""],
"notify_new_posts" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
@ -1084,8 +1084,8 @@ return [
"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"],
"profile-name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Name of the profile"],
"is-default" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Mark this profile as default profile"],
"profile-name" => ["type" => "varchar(255)", "comment" => "Deprecated"],
"is-default" => ["type" => "boolean", "comment" => "Deprecated"],
"hide-friends" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Hide friend list from viewers of this profile"],
"name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"pdesc" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Title or description"],
@ -1095,29 +1095,29 @@ return [
"region" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"postal-code" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => ""],
"country-name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"hometown" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"gender" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => ""],
"marital" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"with" => ["type" => "text", "comment" => ""],
"howlong" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""],
"sexual" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"politic" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"religion" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"hometown" => ["type" => "varchar(255)", "comment" => "Deprecated"],
"gender" => ["type" => "varchar(32)", "comment" => "Deprecated"],
"marital" => ["type" => "varchar(255)", "comment" => "Deprecated"],
"with" => ["type" => "text", "comment" => "Deprecated"],
"howlong" => ["type" => "datetime", "comment" => "Deprecated"],
"sexual" => ["type" => "varchar(255)", "comment" => "Deprecated"],
"politic" => ["type" => "varchar(255)", "comment" => "Deprecated"],
"religion" => ["type" => "varchar(255)", "comment" => "Deprecated"],
"pub_keywords" => ["type" => "text", "comment" => ""],
"prv_keywords" => ["type" => "text", "comment" => ""],
"likes" => ["type" => "text", "comment" => ""],
"dislikes" => ["type" => "text", "comment" => ""],
"about" => ["type" => "text", "comment" => ""],
"summary" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"music" => ["type" => "text", "comment" => ""],
"book" => ["type" => "text", "comment" => ""],
"tv" => ["type" => "text", "comment" => ""],
"film" => ["type" => "text", "comment" => ""],
"interest" => ["type" => "text", "comment" => ""],
"romance" => ["type" => "text", "comment" => ""],
"work" => ["type" => "text", "comment" => ""],
"education" => ["type" => "text", "comment" => ""],
"contact" => ["type" => "text", "comment" => ""],
"likes" => ["type" => "text", "comment" => "Deprecated"],
"dislikes" => ["type" => "text", "comment" => "Deprecated"],
"about" => ["type" => "text", "comment" => "Deprecated"],
"summary" => ["type" => "varchar(255)", "comment" => "Deprecated"],
"music" => ["type" => "text", "comment" => "Deprecated"],
"book" => ["type" => "text", "comment" => "Deprecated"],
"tv" => ["type" => "text", "comment" => "Deprecated"],
"film" => ["type" => "text", "comment" => "Deprecated"],
"interest" => ["type" => "text", "comment" => "Deprecated"],
"romance" => ["type" => "text", "comment" => "Deprecated"],
"work" => ["type" => "text", "comment" => "Deprecated"],
"education" => ["type" => "text", "comment" => "Deprecated"],
"contact" => ["type" => "text", "comment" => "Deprecated"],
"homepage" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"xmpp" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"photo" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
@ -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" => [

View File

@ -205,10 +205,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' => [
@ -239,6 +238,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]],
],
@ -254,6 +254,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]],

View File

@ -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'));
}
}

View File

@ -430,3 +430,18 @@ function update_1330()
return Update::SUCCESS;
}
function update_1332()
{
$condition = ["`is-default` IS NOT NULL"];
$profiles = DBA::select('profile', [], $condition);
while ($profile = DBA::fetch($profiles)) {
DI::profileField()->migrateFromLegacyProfile($profile);
}
DBA::close($profiles);
DBA::update('contact', ['profile-id' => null], ['`profile-id` IS NOT NULL']);
return Update::SUCCESS;
}

View File

@ -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;
}

View File

@ -0,0 +1,13 @@
$(function () {
$("#profile-custom-fields").sortable({
containerSelector: 'div#profile-custom-fields',
handle: 'legend',
itemSelector: 'fieldset',
placeholder: '<div class="placeholder"></div>',
onDrag: function($item, position, _super, event) {
delete position['left'];
$item.css(position);
event.preventDefault();
}
});
});

View File

@ -84,15 +84,6 @@
</div>
<div id="contact-info-end"></div>
{{/if}}
{{if $profile_select}}
<div id="contact-edit-profile-select-text">
<h4>{{$lbl_vis1}}</h4>
<p>{{$lbl_vis2}}</p>
</div>
{{$profile_select nofilter}}
<div id="contact-edit-profile-select-end"></div>
{{/if}}
</div>
<input class="contact-edit-submit" type="submit" name="submit" value="{{$submit}}" />

View File

@ -1,17 +0,0 @@
<p id="hide-wall-text">
{{$desc nofilter}}
</p>
<div id="hide-wall-yes-wrapper">
<label id="hide-wall-yes-label" for="hide-wall-yes">{{$yes_str}}</label>
<input type="radio" name="hidewall" id="hide-wall-yes" {{$yes_selected}} value="1" />
<div id="hide-wall-break" ></div>
</div>
<div id="hide-wall-no-wrapper">
<label id="hide-wall-no-label" for="hide-wall-no">{{$no_str}}</label>
<input type="radio" name="hidewall" id="hide-wall-no" {{$no_selected}} value="0" />
<div id="hide-wall-end"></div>
</div>

View File

@ -1,17 +0,0 @@
<p id="profile-in-directory">
{{$desc nofilter}}
</p>
<div id="profile-in-dir-yes-wrapper">
<label id="profile-in-dir-yes-label" for="profile-in-dir-yes">{{$yes_str}}</label>
<input type="radio" name="profile_in_directory" id="profile-in-dir-yes" {{$yes_selected}} value="1" />
<div id="profile-in-dir-break" ></div>
</div>
<div id="profile-in-dir-no-wrapper">
<label id="profile-in-dir-no-label" for="profile-in-dir-no">{{$no_str}}</label>
<input type="radio" name="profile_in_directory" id="profile-in-dir-no" {{$no_selected}} value="0" />
<div id="profile-in-dir-end"></div>
</div>

View File

@ -1,17 +0,0 @@
<p id="profile-in-directory">
{{$desc nofilter}}
</p>
<div id="profile-in-netdir-yes-wrapper">
<label id="profile-in-netdir-yes-label" for="profile-in-netdir-yes">{{$yes_str}}</label>
<input type="radio" name="profile_in_netdirectory" id="profile-in-netdir-yes" {{$yes_selected}} value="1" />
<div id="profile-in-netdir-break" ></div>
</div>
<div id="profile-in-netdir-no-wrapper">
<label id="profile-in-netdir-no-label" for="profile-in-netdir-no">{{$no_str}}</label>
<input type="radio" name="profile_in_netdirectory" id="profile-in-netdir-no" {{$no_selected}} value="0" />
<div id="profile-in-netdir-end"></div>
</div>

View File

@ -1,184 +0,0 @@
{{include file="section_title.tpl"}}
<dl id="aprofile-fullname" class="aprofile">
<dt>{{$profile.fullname.0}}</dt>
<dd>{{$profile.fullname.1}}</dd>
</dl>
{{if $profile.membersince}}
<dl id="aprofile-membersince" class="aprofile">
<dt>{{$profile.membersince.0}}</dt>
<dd>{{$profile.membersince.1}}</dd>
</dl>
{{/if}}
{{if $profile.gender}}
<dl id="aprofile-gender" class="aprofile">
<dt>{{$profile.gender.0}}</dt>
<dd>{{$profile.gender.1}}</dd>
</dl>
{{/if}}
{{if $profile.birthday}}
<dl id="aprofile-birthday" class="aprofile">
<dt>{{$profile.birthday.0}}</dt>
<dd>{{$profile.birthday.1}}</dd>
</dl>
{{/if}}
{{if $profile.age}}
<dl id="aprofile-age" class="aprofile">
<dt>{{$profile.age.0}}</dt>
<dd>{{$profile.age.1}}</dd>
</dl>
{{/if}}
{{if $profile.marital}}
<dl id="aprofile-marital" class="aprofile">
<dt><span class="heart">&hearts;</span> {{$profile.marital.0}}</dt>
<dd>{{$profile.marital.1}}{{if $profile.marital.with}} ({{$profile.marital.with nofilter}}){{/if}}{{if $profile.howlong}} {{$profile.howlong}}{{/if}}</dd>
</dl>
{{/if}}
{{if $profile.sexual}}
<dl id="aprofile-sexual" class="aprofile">
<dt>{{$profile.sexual.0}}</dt>
<dd>{{$profile.sexual.1}}</dd>
</dl>
{{/if}}
{{if $profile.pub_keywords}}
<dl id="aprofile-tags" class="aprofile">
<dt>{{$profile.pub_keywords.0}}</dt>
<dd>{{$profile.pub_keywords.1}}</dd>
</dl>
{{/if}}
{{if $profile.homepage}}
<dl id="aprofile-homepage" class="aprofile">
<dt>{{$profile.homepage.0}}</dt>
<dd>{{$profile.homepage.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.hometown}}
<dl id="aprofile-hometown" class="aprofile">
<dt>{{$profile.hometown.0}}</dt>
<dd>{{$profile.hometown.1}}</dd>
</dl>
{{/if}}
{{if $profile.politic}}
<dl id="aprofile-politic" class="aprofile">
<dt>{{$profile.politic.0}}</dt>
<dd>{{$profile.politic.1}}</dd>
</dl>
{{/if}}
{{if $profile.religion}}
<dl id="aprofile-religion" class="aprofile">
<dt>{{$profile.religion.0}}</dt>
<dd>{{$profile.religion.1}}</dd>
</dl>
{{/if}}
{{if $profile.about}}
<dl id="aprofile-about" class="aprofile">
<dt>{{$profile.about.0}}</dt>
<dd>{{$profile.about.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.interest}}
<dl id="aprofile-interest" class="aprofile">
<dt>{{$profile.interest.0}}</dt>
<dd>{{$profile.interest.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.likes}}
<dl id="aprofile-likes" class="aprofile">
<dt>{{$profile.likes.0}}</dt>
<dd>{{$profile.likes.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.dislikes}}
<dl id="aprofile-dislikes" class="aprofile">
<dt>{{$profile.dislikes.0}}</dt>
<dd>{{$profile.dislikes.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.contact}}
<dl id="aprofile-contact" class="aprofile">
<dt>{{$profile.contact.0}}</dt>
<dd>{{$profile.contact.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.music}}
<dl id="aprofile-music" class="aprofile">
<dt>{{$profile.music.0}}</dt>
<dd>{{$profile.music.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.book}}
<dl id="aprofile-book" class="aprofile">
<dt>{{$profile.book.0}}</dt>
<dd>{{$profile.book.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.tv}}
<dl id="aprofile-tv" class="aprofile">
<dt>{{$profile.tv.0}}</dt>
<dd>{{$profile.tv.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.film}}
<dl id="aprofile-film" class="aprofile">
<dt>{{$profile.film.0}}</dt>
<dd>{{$profile.film.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.romance}}
<dl id="aprofile-romance" class="aprofile">
<dt>{{$profile.romance.0}}</dt>
<dd>{{$profile.romance.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.work}}
<dl id="aprofile-work" class="aprofile">
<dt>{{$profile.work.0}}</dt>
<dd>{{$profile.work.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.education}}
<dl id="aprofile-education" class="aprofile">
<dt>{{$profile.education.0}}</dt>
<dd>{{$profile.education.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.forumlist}}
<dl id="aprofile-forumlist" class="aprofile">
<dt>{{$profile.forumlist.0}}</dt>
<dd>{{$profile.forumlist.1 nofilter}}</dd>
</dl>
{{/if}}

View File

@ -0,0 +1,124 @@
<div id="profile-page" class="generic-page-wrapper">
{{include file="section_title.tpl"}}
{{* The link to edit the profile*}}
{{if $is_owner}}
<div id="profile-edit-links">
<ul class="nav nav-pills preferences">
<li class="pull-right">
<a class="btn btn-link btn-sm" type="button" id="profile-edit-link" href="{{$edit_link.url}}" title="{{$edit_link.title}}">
<i class="fa fa-pencil-square-o" aria-hidden="true"></i>&nbsp;{{$edit_link.label}}
</a>
</li>
{{if count($view_as_contacts)}}
<li class="pull-right">
<form action="{{$query_string}}" method="get">
<button type="submit" class="btn btn-sm">{{$view_as}}</button>
<select name="viewas" class="input-sm">
<option value="0">Yourself</option>
{{foreach $view_as_contacts as $contact}}
<option value="{{$contact.id}}"{{if $contact.id == $view_as_contact_id}} selected{{/if}}>{{$contact.name}}</option>
{{/foreach}}
</select>
</form>
</li>
{{/if}}
</ul>
<div class="clear"></div>
</div>
{{/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)}}
<ul id="profile-menu" class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
<a href="{{$query_string}}#profile-content-standard" aria-controls="profile-content-standard" role="tab" data-toggle="tab">{{$basic}}</a>
</li>
<li role="presentation">
<a href="{{$query_string}}#profile-content-advanced" aria-controls="profile-content-advanced" role="tab" data-toggle="tab">{{$advanced}}</a>
</li>
</ul>
{{/if}}
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="profile-content-standard">
<dl id="{{$basic_fields.fullname.id}}" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 {{$basic_fields.fullname.class|default:'aprofile'}}">
<dt class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$basic_fields.fullname.label}}</dt>
<dd class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$basic_fields.fullname.value}}</dd>
</dl>
{{if $basic_fields.membersince}}
<dl id="aprofile-membersince" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 {{$basic_fields.membersince.class|default:'aprofile'}}">
<hr class="profile-separator">
<dt class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$basic_fields.membersince.label}}</dt>
<dd class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$basic_fields.membersince.value}}</dd>
</dl>
{{/if}}
{{if $basic_fields.birthday}}
<dl id="aprofile-birthday" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 {{$basic_fields.birthday.class|default:'aprofile'}}">
<hr class="profile-separator">
<dt class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$basic_fields.birthday.label}}</dt>
<dd class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$basic_fields.birthday.value}}</dd>
</dl>
{{/if}}
{{if $basic_fields.age}}
<dl id="aprofile-age" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 {{$basic_fields.age.class|default:'aprofile'}}">
<hr class="profile-separator">
<dt class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$basic_fields.age.label}}</dt>
<dd class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$basic_fields.age.value}}</dd>
</dl>
{{/if}}
{{if $basic_fields.location}}
<dl id="aprofile-location" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 {{$basic_fields.location.class|default:'aprofile'}}">
<hr class="profile-separator">
<dt class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$basic_fields.location.label}}</dt>
<dd class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$basic_fields.location.value}}</dd>
</dl>
{{/if}}
{{if $basic_fields.homepage}}
<dl id="aprofile-homepage" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 {{$basic_fields.homepage.class|default:'aprofile'}}">
<hr class="profile-separator">
<dt class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$basic_fields.homepage.label}}</dt>
<dd class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$basic_fields.homepage.value nofilter}}</dd>
</dl>
{{/if}}
{{if $basic_fields.xmpp}}
<dl id="aprofile-xmpp" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 {{$basic_fields.xmpp.class|default:'aprofile'}}">
<hr class="profile-separator">
<dt class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$basic_fields.xmpp.label}}</dt>
<dd class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$basic_fields.xmpp.value nofilter}}</dd>
</dl>
{{/if}}
{{if $basic_fields.pub_keywords}}
<dl id="aprofile-tags" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 {{$basic_fields.pub_keywords.class|default:'aprofile'}}">
<hr class="profile-separator">
<dt class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$basic_fields.pub_keywords.label}}</dt>
<dd class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">
{{foreach $basic_fields.pub_keywords.value as $tag}}
<a href="{{$tag.url}}" class="tag label btn-info sm">{{$tag.label}} <i class="fa fa-bolt" aria-hidden="true"></i></a>
{{/foreach}}
</dd>
</dl>
{{/if}}
</div>
{{if count($custom_fields)}}
<div role="tabpanel" class="tab-pane advanced" id="profile-content-advanced">
{{foreach $custom_fields as $custom_field}}
<dl id="{{$custom_field.id}}" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 {{$custom_field.class|default:'aprofile'}}">
<hr class="profile-separator">
<dt class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$custom_field.label}}</dt>
<dd class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$custom_field.value nofilter}}</dd>
</dl>
{{/foreach}}
</div>
{{/if}}
</div>
</div>

View File

@ -1,458 +0,0 @@
{{$default nofilter}}
<h1>{{$banner}}</h1>
<div id="profile-edit-links">
<ul>
<li><a href="profile_photo" id="profile-photo_upload-link" title="{{$profpic}}">{{$profpic}}</a></li>
<li><a href="profile/{{$profile_id}}/view?tab=profile" id="profile-edit-view-link" title="{{$viewprof}}">{{$viewprof}}</a></li>
<li><a href="{{$profile_clone_link}}" id="profile-edit-clone-link" title="{{$cr_prof}}">{{$cl_prof}}</a></li>
<li></li>
<li><a href="{{$profile_drop_link}}" id="profile-edit-drop-link" title="{{$del_prof}}" {{$disabled}} >{{$del_prof}}</a></li>
</ul>
</div>
<div id="profile-edit-links-end"></div>
<div id="profile-edit-wrapper" >
<form id="profile-edit-form" name="form1" action="profiles/{{$profile_id}}" method="post" >
<input type='hidden' name='form_security_token' value='{{$form_security_token}}'>
{{if $detailled_profile}}
{{include file="field_yesno.tpl" field=$details}}
<div id="profile-edit-profile-name-wrapper" >
<label id="profile-edit-profile-name-label" for="profile-edit-profile-name" >{{$profile_name.1}} </label>
<input type="text" size="32" name="profile_name" id="profile-edit-profile-name" value="{{$profile_name.2}}" /><div class="required">*</div>
</div>
<div id="profile-edit-profile-name-end"></div>
<div id="profile-edit-name-wrapper" >
<label id="profile-edit-name-label" for="profile-edit-name" >{{$name.1}} </label>
<input type="text" size="32" name="name" id="profile-edit-name" value="{{$name.2}}" />
</div>
<div id="profile-edit-name-end"></div>
<div id="profile-edit-pdesc-wrapper" >
<label id="profile-edit-pdesc-label" for="profile-edit-pdesc" >{{$pdesc.1}} </label>
<input type="text" size="32" name="pdesc" id="profile-edit-pdesc" value="{{$pdesc.1}}" />
</div>
<div id="profile-edit-pdesc-end"></div>
<div id="profile-edit-gender-wrapper" >
<label id="profile-edit-gender-label" for="gender-select" >{{$lbl_gender}} </label>
{{$gender nofilter}}
</div>
<div id="profile-edit-gender-end"></div>
<div id="profile-edit-dob-wrapper" >
{{$dob nofilter}}
</div>
<div id="profile-edit-dob-end"></div>
{{$hide_friends nofilter}}
<div class="profile-edit-submit-wrapper" >
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}" />
</div>
<div class="profile-edit-submit-end"></div>
<div id="profile-edit-address-wrapper" >
<label id="profile-edit-address-label" for="profile-edit-address" >{{$address.1}} </label>
<input type="text" size="32" name="address" id="profile-edit-address" value="{{$address.2}}" />
</div>
<div id="profile-edit-address-end"></div>
<div id="profile-edit-locality-wrapper" >
<label id="profile-edit-locality-label" for="profile-edit-locality" >{{$locality.1}} </label>
<input type="text" size="32" name="locality" id="profile-edit-locality" value="{{$locality.2}}" />
</div>
<div id="profile-edit-locality-end"></div>
<div id="profile-edit-postal-code-wrapper" >
<label id="profile-edit-postal-code-label" for="profile-edit-postal-code" >{{$postal_code.1}} </label>
<input type="text" size="32" name="postal_code" id="profile-edit-postal-code" value="{{$postal_code.2}}" />
</div>
<div id="profile-edit-postal-code-end"></div>
<div id="profile-edit-country-name-wrapper" >
<label id="profile-edit-country-name-label" for="profile-edit-country-name" >{{$country_name.1}} </label>
<select name="country_name" id="profile-edit-country-name" onChange="Fill_States('{{$region.2}}');">
<option selected="selected" >{{$country_name.2}}</option>
<option>temp</option>
</select>
</div>
<div id="profile-edit-country-name-end"></div>
<div id="profile-edit-region-wrapper" >
<label id="profile-edit-region-label" for="profile-edit-region" >{{$region.1}} </label>
<select name="region" id="profile-edit-region" onChange="Update_Globals();" >
<option selected="selected" >{{$region.2}}</option>
<option>temp</option>
</select>
</div>
<div id="profile-edit-region-end"></div>
<div id="profile-edit-hometown-wrapper" >
<label id="profile-edit-hometown-label" for="profile-edit-hometown" >{{$hometown.1}} </label>
<input type="text" size="32" name="hometown" id="profile-edit-hometown" value="{{$hometown.2}}" />
</div>
<div id="profile-edit-hometown-end"></div>
<div class="profile-edit-submit-wrapper" >
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}" />
</div>
<div class="profile-edit-submit-end"></div>
<div id="profile-edit-marital-wrapper" >
<label id="profile-edit-marital-label" for="profile-edit-marital" >{{$lbl_marital nofilter}} </label>
{{$marital nofilter}}
</div>
<label id="profile-edit-with-label" for="profile-edit-with" > {{$with.1}} </label>
<input type="text" size="32" name="with" id="profile-edit-with" title="{{$with.3}}" value="{{$with.2}}" />
<label id="profile-edit-howlong-label" for="profile-edit-howlong" > {{$howlong.1}} </label>
<input type="text" size="32" name="howlong" id="profile-edit-howlong" title="{{$howlong.1}}" value="{{$howlong.1}}" />
<div id="profile-edit-marital-end"></div>
<div id="profile-edit-sexual-wrapper" >
<label id="profile-edit-sexual-label" for="sexual-select" >{{$lbl_sexual}} </label>
{{$sexual nofilter}}
</div>
<div id="profile-edit-sexual-end"></div>
<div id="profile-edit-homepage-wrapper" >
<label id="profile-edit-homepage-label" for="profile-edit-homepage" >{{$homepage.1}} </label>
<input type="url" size="32" name="homepage" id="profile-edit-homepage" value="{{$homepage.2}}" />
</div>
<div id="profile-edit-homepage-end"></div>
<div id="profile-edit-xmpp-wrapper" >
<label id="profile-edit-xmpp-label" for="profile-edit-xmpp" >{{$xmpp.1}} </label>
<input type="text" size="32" name="xmpp" id="profile-edit-xmpp" title="{{$lbl_ex2}}" value="{{$xmpp.2}}" />
</div><div id="profile-edit-xmpp-desc">{{$xmpp.3}}</div>
<div id="profile-edit-xmpp-end"></div>
<div id="profile-edit-politic-wrapper" >
<label id="profile-edit-politic-label" for="profile-edit-politic" >{{$politic.1}} </label>
<input type="text" size="32" name="politic" id="profile-edit-politic" value="{{$politic.2}}" />
</div>
<div id="profile-edit-politic-end"></div>
<div id="profile-edit-religion-wrapper" >
<label id="profile-edit-religion-label" for="profile-edit-religion" >{{$religion.1}} </label>
<input type="text" size="32" name="religion" id="profile-edit-religion" value="{{$religion.2}}" />
</div>
<div id="profile-edit-religion-end"></div>
<div id="profile-edit-pubkeywords-wrapper" >
<label id="profile-edit-pubkeywords-label" for="profile-edit-pubkeywords" >{{$pub_keywords.1}} </label>
<input type="text" size="32" name="pub_keywords" id="profile-edit-pubkeywords" title="{{$lbl_ex2}}" value="{{$pub_keywords.2}}" />
</div><div id="profile-edit-pubkeywords-desc">{{$pub_keywords.3}}</div>
<div id="profile-edit-pubkeywords-end"></div>
<div id="profile-edit-prvkeywords-wrapper" >
<label id="profile-edit-prvkeywords-label" for="profile-edit-prvkeywords" >{{$prv_keywords.1}} </label>
<input type="text" size="32" name="prv_keywords" id="profile-edit-prvkeywords" title="{{$lbl_ex2}}" value="{{$prv_keywords.2}}" />
</div><div id="profile-edit-prvkeywords-desc">{{$prv_keywords.3}}</div>
<div id="profile-edit-prvkeywords-end"></div>
<div class="profile-edit-submit-wrapper" >
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}" />
</div>
<div class="profile-edit-submit-end"></div>
<div id="about-jot-wrapper" >
<p id="about-jot-desc" >
{{$about.1}}
</p>
<textarea rows="10" cols="72" id="profile-about-text" name="about" >{{$about.2}}</textarea>
</div>
<div id="about-jot-end"></div>
<div id="interest-jot-wrapper" >
<p id="interest-jot-desc" >
{{$interest.1}}
</p>
<textarea rows="10" cols="72" id="interest-jot-text" name="interest" >{{$interest.2}}</textarea>
</div>
<div id="interest-jot-end"></div>
<div id="likes-jot-wrapper" >
<p id="likes-jot-desc" >
{{$likes.1}}
</p>
<textarea rows="10" cols="72" id="likes-jot-text" name="likes" >{{$likes.2}}</textarea>
</div>
<div id="likes-jot-end"></div>
<div id="dislikes-jot-wrapper" >
<p id="dislikes-jot-desc" >
{{$dislikes.1}}
</p>
<textarea rows="10" cols="72" id="dislikes-jot-text" name="dislikes" >{{$dislikes.2}}</textarea>
</div>
<div id="dislikes-jot-end"></div>
<div id="contact-jot-wrapper" >
<p id="contact-jot-desc" >
{{$contact.1}}
</p>
<textarea rows="10" cols="72" id="contact-jot-text" name="contact" >{{$contact.2}}</textarea>
</div>
<div id="contact-jot-end"></div>
<div class="profile-edit-submit-wrapper" >
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}" />
</div>
<div class="profile-edit-submit-end"></div>
<div id="music-jot-wrapper" >
<p id="music-jot-desc" >
{{$music.1}}
</p>
<textarea rows="10" cols="72" id="music-jot-text" name="music" >{{$music.2}}</textarea>
</div>
<div id="music-jot-end"></div>
<div id="book-jot-wrapper" >
<p id="book-jot-desc" >
{{$book.1}}
</p>
<textarea rows="10" cols="72" id="book-jot-text" name="book" >{{$book.2}}</textarea>
</div>
<div id="book-jot-end"></div>
<div id="tv-jot-wrapper" >
<p id="tv-jot-desc" >
{{$tv.1}}
</p>
<textarea rows="10" cols="72" id="tv-jot-text" name="tv" >{{$tv.2}}</textarea>
</div>
<div id="tv-jot-end"></div>
<div id="film-jot-wrapper" >
<p id="film-jot-desc" >
{{$film.1}}
</p>
<textarea rows="10" cols="72" id="film-jot-text" name="film" >{{$film.2}}</textarea>
</div>
<div id="film-jot-end"></div>
<div class="profile-edit-submit-wrapper" >
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}" />
</div>
<div class="profile-edit-submit-end"></div>
<div id="romance-jot-wrapper" >
<p id="romance-jot-desc" >
{{$romance.1}}
</p>
<textarea rows="10" cols="72" id="romance-jot-text" name="romance" >{{$romance.2}}</textarea>
</div>
<div id="romance-jot-end"></div>
<div id="work-jot-wrapper" >
<p id="work-jot-desc" >
{{$work.1}}
</p>
<textarea rows="10" cols="72" id="work-jot-text" name="work" >{{$work.2}}</textarea>
</div>
<div id="work-jot-end"></div>
<div id="education-jot-wrapper" >
<p id="education-jot-desc" >
{{$education.1}}
</p>
<textarea rows="10" cols="72" id="education-jot-text" name="education" >{{$education.2}}</textarea>
</div>
<div id="education-jot-end"></div>
<div class="profile-edit-submit-wrapper" >
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}" />
</div>
<div class="profile-edit-submit-end"></div>
{{else}}
{{if $personal_account}}
{{include file="field_yesno.tpl" field=$details}}
{{/if}}
<div id="profile-edit-profile-name-wrapper" >
<label id="profile-edit-profile-name-label" for="profile-edit-profile-name" >{{$profile_name.1}} </label>
<input type="text" size="32" name="profile_name" id="profile-edit-profile-name" value="{{$profile_name.2}}" /><div class="required">*</div>
</div>
<div id="profile-edit-profile-name-end"></div>
<div id="profile-edit-name-wrapper" >
<label id="profile-edit-name-label" for="profile-edit-name" >{{$name.1}} </label>
<input type="text" size="32" name="name" id="profile-edit-name" value="{{$name.2}}" />
</div>
<div id="profile-edit-name-end"></div>
{{if $personal_account}}
<div id="profile-edit-gender-wrapper" >
<label id="profile-edit-gender-label" for="gender-select" >{{$lbl_gender}} </label>
{{$gender nofilter}}
</div>
<div id="profile-edit-gender-end"></div>
<div id="profile-edit-dob-wrapper" >
{{$dob nofilter}}
</div>
<div id="profile-edit-dob-end"></div>
{{/if}}
<div id="profile-edit-homepage-wrapper" >
<label id="profile-edit-homepage-label" for="profile-edit-homepage" >{{$homepage.1}} </label>
<input type="url" size="32" name="homepage" id="profile-edit-homepage" value="{{$homepage.2}}" />
</div>
<div id="profile-edit-homepage-end"></div>
<div id="profile-edit-xmpp-wrapper" >
<label id="profile-edit-xmpp-label" for="profile-edit-xmpp" >{{$xmpp.1}} </label>
<input type="text" size="32" name="xmpp" id="profile-edit-xmpp" title="{{$lbl_ex2}}" value="{{$xmpp.2}}" />
</div><div id="profile-edit-xmpp-desc">{{$xmpp.3}}</div>
<div id="profile-edit-xmpp-end"></div>
{{$hide_friends nofilter}}
<div id="profile-edit-address-wrapper" >
<label id="profile-edit-address-label" for="profile-edit-address" >{{$address.1}} </label>
<input type="text" size="32" name="address" id="profile-edit-address" value="{{$address.2}}" />
</div>
<div id="profile-edit-address-end"></div>
<div id="profile-edit-locality-wrapper" >
<label id="profile-edit-locality-label" for="profile-edit-locality" >{{$locality.1}} </label>
<input type="text" size="32" name="locality" id="profile-edit-locality" value="{{$locality.2}}" />
</div>
<div id="profile-edit-locality-end"></div>
<div id="profile-edit-postal-code-wrapper" >
<label id="profile-edit-postal-code-label" for="profile-edit-postal-code" >{{$postal_code.1}} </label>
<input type="text" size="32" name="postal_code" id="profile-edit-postal-code" value="{{$postal_code.2}}" />
</div>
<div id="profile-edit-postal-code-end"></div>
<div id="profile-edit-country-name-wrapper" >
<label id="profile-edit-country-name-label" for="profile-edit-country-name" >{{$country_name.1}} </label>
<select name="country_name" id="profile-edit-country-name" onChange="Fill_States('{{$region.2}}');">
<option selected="selected" >{{$country_name.1}}</option>
<option>temp</option>
</select>
</div>
<div id="profile-edit-country-name-end"></div>
<div id="profile-edit-region-wrapper" >
<label id="profile-edit-region-label" for="profile-edit-region" >{{$region.1}} </label>
<select name="region" id="profile-edit-region" onChange="Update_Globals();" >
<option selected="selected" >{{$region.2}}</option>
<option>temp</option>
</select>
</div>
<div id="profile-edit-region-end"></div>
<div id="profile-edit-pubkeywords-wrapper" >
<label id="profile-edit-pubkeywords-label" for="profile-edit-pubkeywords" >{{$pub_keywords.1}} </label>
<input type="text" size="32" name="pub_keywords" id="profile-edit-pubkeywords" title="{{$lbl_ex2}}" value="{{$pub_keywords.2}}" />
</div><div id="profile-edit-pubkeywords-desc">{{$pub_keywords.3}}</div>
<div id="profile-edit-pubkeywords-end"></div>
<div id="profile-edit-prvkeywords-wrapper" >
<label id="profile-edit-prvkeywords-label" for="profile-edit-prvkeywords" >{{$prv_keywords.1}} </label>
<input type="text" size="32" name="prv_keywords" id="profile-edit-prvkeywords" title="{{$lbl_ex2}}" value="{{$prv_keywords.2}}" />
</div><div id="profile-edit-prvkeywords-desc">{{$prv_keywords.3}}</div>
<div id="profile-edit-prvkeywords-end"></div>
<div id="about-jot-wrapper" >
<p id="about-jot-desc" >
{{$about.1}}
</p>
<textarea rows="10" cols="72" id="profile-about-text" name="about" >{{$about.2}}</textarea>
</div>
<div id="about-jot-end"></div>
<div class="profile-edit-submit-wrapper" >
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}" />
</div>
<div class="profile-edit-submit-end"></div>
<input type="hidden" name="pdesc" id="profile-edit-pdesc" value="{{$pdesc.2}}" />
<input type="hidden" id="contact-jot-text" name="contact" value="{{$contact.2}}" />
<input type="hidden" name="hometown" id="profile-edit-hometown" value="{{$hometown.2}}" />
<input type="hidden" name="politic" id="profile-edit-politic" value="{{$politic.2}}" />
<input type="hidden" name="religion" id="profile-edit-religion" value="{{$religion.2}}" />
<input type="hidden" id="likes-jot-text" name="likes" value="{{$likes.2}}" />
<input type="hidden" id="dislikes-jot-text" name="dislikes" value="{{$dislikes.2}}" />
<input type="hidden" name="marital" id="profile-edit-marital" value="{{$marital.2}}" />
<input type="hidden" name="with" id="profile-edit-with" value="{{$with.2}}" />
<input type="hidden" name="howlong" id="profile-edit-howlong" value="{{$howlong.2}}" />
<input type="hidden" name="sexual" id="profile-edit-sexual" value="{{$sexual.2}}" />
<input type="hidden" id="romance-jot-text" name="romance" value="{{$romance.2}}" />
<input type="hidden" id="work-jot-text" name="work" value="{{$work.2}}" />
<input type="hidden" id="education-jot-text" name="education" value="{{$education.2}}" />
<input type="hidden" id="interest-jot-text" name="interest" value="{{$interest.2}}" />
<input type="hidden" id="music-jot-text" name="music" value="{{$music.2}}" />
<input type="hidden" id="book-jot-text" name="book" value="{{$book.2}}" />
<input type="hidden" id="tv-jot-text" name="tv" value="{{$tv.2}}" />
<input type="hidden" id="film-jot-text" name="film" value="{{$film.2}}" />
{{/if}}
</form>
</div>
<script type="text/javascript">Fill_Country('{{$country_name.2}}');Fill_States('{{$region.2}}');</script>

View File

@ -1,3 +0,0 @@
<div class="profile-edit-side-div"><a class="profile-edit-side-link icon edit" title="{{$editprofile}}" href="profiles/{{$profid}}" ></a></div>
<div class="clear"></div>

View File

@ -1,12 +0,0 @@
<div class="profile-listing" >
<div class="profile-listing-photo-wrapper" >
<a href="profiles/{{$id}}" class="profile-listing-edit-link"><img class="profile-listing-photo" id="profile-listing-photo-{{$id}}" src="{{$photo}}" alt="{{$alt}}" /></a>
</div>
<div class="profile-listing-photo-end"></div>
<div class="profile-listing-name" id="profile-listing-name-{{$id}}">
<a href="profiles/{{$id}}" class="profile-listing-edit-link" >{{$profile_name}}</a>
</div>
<div class="profile-listing-visible">{{$visible nofilter}}</div>
</div>
<div class="profile-listing-end"></div>

View File

@ -1,14 +0,0 @@
<h1>{{$header}}</h1>
<p id="profile-listing-desc" class="button" >
<a href="profile_photo" >{{$chg_photo}}</a>
</p>
<div id="profile-listing-new-link-wrapper" class="button" >
<a href="{{$cr_new_link}}" id="profile-listing-new-link" title="{{$cr_new}}" >{{$cr_new}}</a>
</div>
<div id="profile-listing-profiles">
{{$profiles nofilter}}
</div>

View File

@ -0,0 +1,13 @@
<fieldset data-id="{{$profile_field.id}}">
<legend>&#8801; {{$profile_field.legend}}</legend>
<input type="hidden" name="profile_field_order[]" value="{{$profile_field.id}}">
{{include file="field_input.tpl" field=$profile_field.fields.label}}
{{include file="field_textarea.tpl" field=$profile_field.fields.value}}
<details>
<summary>Permissions</summary>
{{$profile_field.fields.acl nofilter}}
</details>
</fieldset>

View File

@ -0,0 +1,117 @@
<h1>{{$banner}}</h1>
{{$default nofilter}}
<div id="profile-edit-links">
<ul>
<li><a href="settings/profile/photo" id="profile-photo_upload-link" title="{{$profpic}}">{{$profpic}}</a></li>
<li><a href="profile/{{$nickname}}" id="profile-edit-view-link" title="{{$viewprof}}">{{$viewprof}}</a></li>
</ul>
</div>
<div id="profile-edit-links-end"></div>
<div id="profile-edit-wrapper">
<form id="profile-edit-form" name="form1" action="settings/profiles" method="post">
<input type="hidden" name="form_security_token" value="{{$form_security_token}}">
<div id="profile-edit-name-wrapper">
<label id="profile-edit-name-label" for="profile-edit-name">{{$name.1}} </label>
<input type="text" size="32" name="name" id="profile-edit-name" value="{{$name.2}}"/>
</div>
<div id="profile-edit-name-end"></div>
<div id="profile-edit-pdesc-wrapper">
<label id="profile-edit-pdesc-label" for="profile-edit-pdesc">{{$pdesc.1}} </label>
<input type="text" size="32" name="pdesc" id="profile-edit-pdesc" value="{{$pdesc.1}}"/>
</div>
<div id="profile-edit-pdesc-end"></div>
<div id="profile-edit-dob-wrapper">
{{$dob nofilter}}
</div>
<div id="profile-edit-dob-end"></div>
{{$hide_friends nofilter}}
<div class="profile-edit-submit-wrapper">
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}"/>
</div>
<div class="profile-edit-submit-end"></div>
<div id="profile-edit-address-wrapper">
<label id="profile-edit-address-label" for="profile-edit-address">{{$address.1}} </label>
<input type="text" size="32" name="address" id="profile-edit-address" value="{{$address.2}}"/>
</div>
<div id="profile-edit-address-end"></div>
<div id="profile-edit-locality-wrapper">
<label id="profile-edit-locality-label" for="profile-edit-locality">{{$locality.1}} </label>
<input type="text" size="32" name="locality" id="profile-edit-locality" value="{{$locality.2}}"/>
</div>
<div id="profile-edit-locality-end"></div>
<div id="profile-edit-postal-code-wrapper">
<label id="profile-edit-postal-code-label" for="profile-edit-postal-code">{{$postal_code.1}} </label>
<input type="text" size="32" name="postal_code" id="profile-edit-postal-code" value="{{$postal_code.2}}"/>
</div>
<div id="profile-edit-postal-code-end"></div>
<div id="profile-edit-country-name-wrapper">
<label id="profile-edit-country-name-label" for="profile-edit-country-name">{{$country_name.1}} </label>
<select name="country_name" id="profile-edit-country-name" onChange="Fill_States('{{$region.2}}');">
<option selected="selected">{{$country_name.2}}</option>
<option>temp</option>
</select>
</div>
<div id="profile-edit-country-name-end"></div>
<div id="profile-edit-region-wrapper">
<label id="profile-edit-region-label" for="profile-edit-region">{{$region.1}} </label>
<select name="region" id="profile-edit-region" onChange="Update_Globals();">
<option selected="selected">{{$region.2}}</option>
<option>temp</option>
</select>
</div>
<div id="profile-edit-hometown-end"></div>
<div class="profile-edit-submit-wrapper">
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}"/>
</div>
<div class="profile-edit-submit-end"></div>
<div id="profile-edit-homepage-wrapper">
<label id="profile-edit-homepage-label" for="profile-edit-homepage">{{$homepage.1}} </label>
<input type="url" size="32" name="homepage" id="profile-edit-homepage" value="{{$homepage.2}}"/>
</div>
<div id="profile-edit-homepage-end"></div>
<div id="profile-edit-xmpp-wrapper">
<label id="profile-edit-xmpp-label" for="profile-edit-xmpp">{{$xmpp.1}} </label>
<input type="text" size="32" name="xmpp" id="profile-edit-xmpp" title="{{$lbl_ex2}}" value="{{$xmpp.2}}"/>
</div>
<div id="profile-edit-xmpp-desc">{{$xmpp.3}}</div>
<div id="profile-edit-xmpp-end"></div>
<div id="profile-edit-pubkeywords-wrapper">
<label id="profile-edit-pubkeywords-label" for="profile-edit-pubkeywords">{{$pub_keywords.1}} </label>
<input type="text" size="32" name="pub_keywords" id="profile-edit-pubkeywords" title="{{$lbl_ex2}}" value="{{$pub_keywords.2}}"/>
</div>
<div id="profile-edit-pubkeywords-desc">{{$pub_keywords.3}}</div>
<div id="profile-edit-pubkeywords-end"></div>
<div id="profile-edit-prvkeywords-wrapper">
<label id="profile-edit-prvkeywords-label" for="profile-edit-prvkeywords">{{$prv_keywords.1}} </label>
<input type="text" size="32" name="prv_keywords" id="profile-edit-prvkeywords" title="{{$lbl_ex2}}" value="{{$prv_keywords.2}}"/>
</div>
<div id="profile-edit-prvkeywords-desc">{{$prv_keywords.3}}</div>
<div id="profile-edit-prvkeywords-end"></div>
<div class="profile-edit-submit-wrapper">
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}"/>
</div>
<div class="profile-edit-submit-end"></div>
<h3>{{$lbl_custom_fields_section}}</h3>
{{$custom_fields_description nofilter}}
<div id="profile-custom-fields">
{{foreach $custom_fields as $custom_field}}
{{include file="settings/profile/field/edit.tpl" profile_field=$custom_field}}
{{/foreach}}
</div>
<div class="profile-edit-submit-wrapper">
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}"/>
</div>
<div class="profile-edit-submit-end"></div>
</form>
</div>
<script type="text/javascript">
Fill_Country('{{$country_name.2}}');
Fill_States('{{$region.2}}');
</script>

View File

@ -0,0 +1,2 @@
<div class="profile-edit-side-div"><a class="profile-edit-side-link icon edit" title="{{$editprofile}}" href="settings/profile"></a></div>
<div class="clear"></div>

View File

@ -26,11 +26,11 @@
{{$profile_photo_txt nofilter}}
</li>
<li>
<a target="newmember" href="profiles">{{$profiles_link}}</a><br />
<a target="newmember" href="settings/profile">{{$profiles_link}}</a><br />
{{$profiles_txt nofilter}}
</li>
<li>
<a target="newmember" href="profiles">{{$profiles_keywords_link}}</a><br />
<a target="newmember" href="settings/profile">{{$profiles_keywords_link}}</a><br />
{{$profiles_keywords_txt nofilter}}
</li>
</ul>

View File

@ -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;
}

View File

@ -172,35 +172,6 @@
</div>
</div>
{{/if}}
{{if $lbl_vis1}}
<div class="panel">
<div class="section-subtitle-wrapper" role="tab" id="contact-edit-profile-select">
<h4>
<a class="accordion-toggle collapsed" data-toggle="collapse" data-parent="#contact-edit-tools" href="#contact-edit-profile-select-collapse" aria-expanded="false" aria-controls="contact-edit-profile-select-collapse">
{{$lbl_vis1}}
</a>
</h4>
</div>
<div id="contact-edit-profile-select-collapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="contact-edit-profile-select">
<div class="section-content-tools-wrapper">
{{if $profile_select}}
<div id="contact-edit-profile-select-text">
<p>{{$lbl_vis2}}</p>
</div>
<div class="form-group">
{{$profile_select nofilter}}
</div>
<div class="clear"></div>
{{/if}}
<div class="form-group pull-right settings-submit-wrapper" >
<button type="submit" name="submit" class="btn btn-primary" value="{{$submit}}">{{$submit}}</button>
</div>
<div class="clear"></div>
</div>
</div>
</div>
{{/if}}
</div>
</form>{{* End of the form *}}

View File

@ -1,234 +0,0 @@
<div id="profile-page" class="generic-page-wrapper">
<h3 class="">{{$title}}</h3>
{{* The link to edit the profile*}}
{{if $profile.edit}}
<ul class="nav nav-pills preferences">
<li class="pull-right">
<a class="btn btn-link btn-sm" type="button" id="profile-edit-link" href="{{$profile.edit.0}}" title="{{$profile.edit.3}}">
<i class="fa fa-pencil-square-o" aria-hidden="true"></i>&nbsp;{{$profile.edit.1}}
</a>
</li>
</ul>
<div class="clear"></div>
{{/if}}
{{* Frio does split the profile information in "standard" and "advanced". This is the tab menu for swithching between this modes *}}
<ul id="profile-menu" class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
<a href="#profile-content-standard" aria-controls="profile-content-standard" role="tab" data-toggle="tab">{{$basic}}</a>
</li>
<li role="presentation">
<a href="#profile-content-advanced" aria-controls="profile-content-advanced" role="tab" data-toggle="tab">{{$advanced}}</a>
</li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="profile-content-standard">
<div id="aprofile-fullname" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.fullname.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.fullname.1}}</div>
</div>
{{if $profile.membersince}}
<div id="aprofile-membersince" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.membersince.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.membersince.1}}</div>
</div>
{{/if}}
{{if $profile.gender}}
<div id="aprofile-gender" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.gender.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.gender.1}}</div>
</div>
{{/if}}
{{if $profile.birthday}}
<div id="aprofile-birthday" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.birthday.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.birthday.1}}</div>
</div>
{{/if}}
{{if $profile.age}}
<div id="aprofile-age" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.age.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.age.1}}</div>
</div>
{{/if}}
{{if $profile.hometown}}
<div id="aprofile-hometown" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.hometown.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.hometown.1}}</div>
</div>
{{/if}}
{{if $profile.marital}}
<div id="aprofile-marital" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted"><span class="heart">&hearts;</span> {{$profile.marital.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.marital.1}}{{if $profile.marital.with}} ({{$profile.marital.with nofilter}}){{/if}}{{if $profile.howlong}} {{$profile.howlong}}{{/if}}</div>
</div>
{{/if}}
{{if $profile.homepage}}
<div id="aprofile-homepage" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.homepage.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.homepage.1 nofilter}}</div>
</div>
{{/if}}
{{if $profile.about}}
<div id="aprofile-about" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.about.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.about.1 nofilter}}</div>
</div>
{{/if}}
{{if $profile.pub_keywords}}
<div id="aprofile-tags" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.pub_keywords.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.pub_keywords.1}}</div>
</div>
{{/if}}
</div>
<div role="tabpanel" class="tab-pane advanced" id="profile-content-advanced">
{{if $profile.sexual}}
<div id="aprofile-sexual" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.sexual.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.sexual.1}}</div>
</div>
{{/if}}
{{if $profile.politic}}
<div id="aprofile-politic" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.politic.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.politic.1}}</div>
</div>
{{/if}}
{{if $profile.religion}}
<div id="aprofile-religion" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.religion.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.religion.1}}</div>
</div>
{{/if}}
{{if $profile.interest}}
<div id="aprofile-interest" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.interest.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.interest.1 nofilter}}</div>
</div>
{{/if}}
{{if $profile.likes}}
<div id="aprofile-likes" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.likes.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.likes.1 nofilter}}</div>
</div>
{{/if}}
{{if $profile.dislikes}}
<div id="aprofile-dislikes" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.dislikes.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.dislikes.1 nofilter}}</div>
</div>
{{/if}}
{{if $profile.contact}}
<div id="aprofile-contact" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.contact.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.contact.1 nofilter}}</div>
</div>
{{/if}}
{{if $profile.music}}
<div id="aprofile-music" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.music.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.music.1 nofilter}}</div>
</div>
{{/if}}
{{if $profile.book}}
<div id="aprofile-book" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.book.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.book.1 nofilter}}</div>
</div>
{{/if}}
{{if $profile.tv}}
<div id="aprofile-tv" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.tv.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.tv.1 nofilter}}</div>
</div>
{{/if}}
{{if $profile.film}}
<div id="aprofile-film" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.film.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.film.1 nofilter}}</div>
</div>
{{/if}}
{{if $profile.romance}}
<div id="aprofile-romance" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.romance.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.romance.1 nofilter}}</div>
</div>
{{/if}}
{{if $profile.work}}
<div id="aprofile-work" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.work.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.work.1 nofilter}}</div>
</div>
{{/if}}
{{if $profile.education}}
<div id="aprofile-education" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.education.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.education.1 nofilter}}</div>
</div>
{{/if}}
{{if $profile.forumlist}}
<div id="aprofile-forumlist" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 aprofile">
<hr class="profile-separator">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted">{{$profile.forumlist.0}}</div>
<div class="col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry">{{$profile.forumlist.1 nofilter}}</div>
</div>
{{/if}}
</div>
</div>
</div>

View File

@ -1,343 +0,0 @@
<div class="generic-page-wrapper">
{{include file="section_title.tpl" title=$banner}}
{{* The actions dropdown which can performed to the current profile *}}
<div id="profile-edit-links">
<ul class="nav nav-pills preferences">
<li class="dropdown pull-right">
<button type="button" class="btn btn-link btn-sm dropdown-toggle" id="profile-edit-links-dropdown" data-toggle="dropdown" aria-expanded="false">
<i class="fa fa-angle-down" aria-hidden="true"></i>&nbsp;{{$profile_action}}
</button>
<ul class="dropdown-menu pull-right" role="menu" aria-labelledby="profile-edit-links-dropdown">
<li role="presentation"><a role="menuitem" href="{{$profpiclink}}" id="profile-photo_upload-link" title="{{$profpic}}"><i class="fa fa-user" aria-hidden="true"></i>&nbsp;{{$profpic}}</a></li>
<li role="presentation"><button role="menuitem" type="button" class="btn-link" id="profile-photo_upload-link-new" title="{{$lbl_profile_photo}}" onclick="openClose('profile-photo-upload-section');"><i class="fa fa-user" aria-hidden="true"></i>&nbsp;{{$lbl_profile_photo}}</button></li>
{{if ! $is_default}}
<li role="presentation" class="nav-item"><a role="menuitem" href="profperm/{{$profile_id}}" id="profile-edit-visibility-link" title="{{$editvis}}"><i class="fa fa-pencil" aria-hidden="true"></i>&nbsp;{{$editvis}}</a>
</li>
{{/if}}
<li role="presentation" class="divider"></li>
<li role="presentation"><a role="menuitem" href="profile/{{$profile_id}}/view?tab=profile" id="profile-edit-view-link" title="{{$viewprof}}">{{$viewprof}}</a></li>
<li role="presentation"><a role="menuitem" href="profiles" id="profile-edit-view-link" title="{{$viewallprof}}">{{$viewallprof}}</a></li>
{{if $profile_clone_link}}
<li role="presentation" class="divider"></li>
<li role="presentation"><a role="menuitem" href="{{$profile_clone_link}}" id="profile-edit-clone-link" title="{{$cr_prof}}">{{$cl_prof}}</a></li>
{{/if}}
{{if !$is_default}}
<li role="presentation" class="divider"></li>
<li role="presentation"><a role="menuitem" href="{{$profile_drop_link}}" id="profile-edit-drop-link" title="{{$del_prof}}"><i class="fa fa-trash" aria-hidden="true"></i>&nbsp;{{$del_prof}}</a></li>
{{/if}}
</ul>
</li>
</ul>
</div>
<div id="profile-edit-links-end"></div>
<form enctype="multipart/form-data" action="profile_photo" method="post">
<input type='hidden' name='form_security_token' value='{{$form_security_token_photo}}'>
<input type="hidden" name="profile" value="{{$profile_name.2}}" />
<div id="profile-photo-upload-section" class="panel">
<a id="profile-photo-upload-close" class="close pull-right" onclick="openClose('profile-photo-upload-section');"><i class="fa fa-times" aria-hidden="true"></i></a>
<div id="profile-photo-upload-wrapper">
<label id="profile-photo-upload-label" for="profile-photo-upload">{{$lbl_profile_photo}}:</label>
<input name="userfile" type="file" id="profile-photo-upload" size="48" />
</div>
<div class="profile-edit-submit-wrapper pull-right" >
<button type="submit" name="submit" class="profile-edit-submit-butto btn btn-primary" value="{{$submit}}">{{$submit}}</button>
</div>
<div class="clear"></div>
</div>
</form>
{{* Most of the Variables used below are arrays in the following style
0 => Some kind of identifier (e.g. for the ID)
1 => The label description
2 => The input values
3 => The additional help text (if available)
*}}
<form id="profile-edit-form" name="form1" action="profiles/{{$profile_id}}" method="post" >
<input type='hidden' name='form_security_token' value='{{$form_security_token}}'>
{{* Some hints to characteristics of the current profile (if available) *}}
{{if $is_default}}
<div class="section-content-info-wrapper">{{$default nofilter}}</div>
{{/if}}
{{* friendica differs in $detailled_profile (all fields available and a short Version if this is variable false *}}
{{if $detailled_profile}}
<div class="panel-group panel-group-settings" id="profile-edit-wrapper" role="tablist" aria-multiselectable="true">
{{* The personal settings *}}
<div class="panel">
<div class="section-subtitle-wrapper" role="tab" id="personal">
<h4>
<a class="accordion-toggle collapsed" data-toggle="collapse" data-parent="#profile-edit-wrapper" href="#personal-collapse" aria-expanded="true" aria-controls="personal-collapse">
{{$lbl_personal_section}}
</a>
</h4>
</div>
{{* for the $detailled_profile we use bootstraps collapsable panel-groups to have expandable groups *}}
<div id="personal-collapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="personal">
<div class="section-content-tools-wrapper">
{{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}}
<div id="profile-edit-gender-wrapper" class="form-group field select">
<label id="profile-edit-gender-label" for="gender-select" >{{$lbl_gender}} </label>
{{$gender nofilter}}
</div>
<div class="clear"></div>
{{$dob nofilter}}
{{$hide_friends nofilter}}
<div class="form-group pull-right" >
<button type="submit" name="submit" class="btn btn-primary" value="{{$submit}}">{{$submit}}</button>
</div>
<div class="clear"></div>
</div>
</div>
</div>
{{* The location settings *}}
<div class="panel">
<div class="section-subtitle-wrapper" role="tab" id="location">
<h4>
<a class="accordion-toggle collapsed" data-toggle="collapse" data-parent="#profile-edit-wrapper" href="#location-collapse" aria-expanded="false" aria-controls="location-collapse">
{{$lbl_location_section}}
</a>
</h4>
</div>
<div id="location-collapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="location">
<div class="section-content-tools-wrapper">
{{include file="field_input.tpl" field=$address}}
{{include file="field_input.tpl" field=$locality}}
{{include file="field_input.tpl" field=$postal_code}}
<div id="profile-edit-country-name-wrapper" class="form-group field select">
<label id="profile-edit-country-name-label" for="profile-edit-country-name" >{{$country_name.1}} </label>
<select name="country_name" id="profile-edit-country-name" class="form-control" onChange="Fill_States('{{$region.2}}');">
<option selected="selected" >{{$country_name.2}}</option>
<option>temp</option>
</select>
</div>
<div class="clear"></div>
<div id="profile-edit-region-wrapper" class="form-group field select">
<label id="profile-edit-region-label" for="profile-edit-region" >{{$region.1}} </label>
<select name="region" id="profile-edit-region" class="form-control" onChange="Update_Globals();" >
<option selected="selected" >{{$region.2}}</option>
<option>temp</option>
</select>
</div>
<div class="clear"></div>
{{include file="field_input.tpl" field=$hometown}}
<div class="form-group pull-right" >
<button type="submit" name="submit" class="btn btn-primary" value="{{$submit}}">{{$submit}}</button>
</div>
<div class="clear"></div>
</div>
</div>
</div>
{{* The settings for relations *}}
<div class="panel">
<div class="section-subtitle-wrapper" role="tab" id="relation">
<h4>
<a class="accordion-toggle collapsed" data-toggle="collapse" data-parent="#profile-edit-wrapper" href="#relation-collapse" aria-expanded="false" aria-controls="relation-collapse">
{{$lbl_relation_section}}
</a>
</h4>
</div>
<div id="relation-collapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="relation">
<div class="section-content-tools-wrapper">
<div id="profile-edit-marital-wrapper" class="form-group field select" >
<label id="profile-edit-marital-label" for="profile-edit-marital" >{{$lbl_marital nofilter}}</label>
{{$marital.selector nofilter}}
</div>
<div class="clear"></div>
{{include file="field_input.tpl" field=$with}}
{{include file="field_input.tpl" field=$howlong}}
<div id="profile-edit-sexual-wrapper" class="form-group field select" >
<label id="profile-edit-sexual-label" for="sexual-select" >{{$lbl_sexual}}</label>
{{$sexual.selector nofilter}}
</div>
<div class="clear"></div>
<div class="form-group pull-right" >
<button type="submit" name="submit" class="btn btn-primary" value="{{$submit}}">{{$submit}}</button>
</div>
<div class="clear"></div>
</div>
</div>
</div>
{{* The miscellanous other settings *}}
<div class="panel">
<div class="section-subtitle-wrapper" role="tab" id="miscellaneous">
<h4>
<a class="accordion-toggle collapsed" data-toggle="collapse" data-parent="#profile-edit-wrapper" href="#miscellaneous-collapse" aria-expanded="false" aria-controls="miscellaneous-collapse">
{{$lbl_miscellaneous_section}}
</a>
</h4>
</div>
<div id="miscellaneous-collapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="miscellaneous">
<div class="section-content-tools-wrapper">
{{include file="field_input.tpl" field=$homepage}}
{{include file="field_input.tpl" field=$xmpp}}
{{include file="field_input.tpl" field=$pub_keywords}}
{{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}}
<div class="form-group pull-right" >
<button type="submit" name="submit" class="btn btn-primary" value="{{$submit}}">{{$submit}}</button>
</div>
<div class="clear"></div>
</div>
</div>
</div>
</div>
{{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}}
{{include file="field_input.tpl" field=$name}}
{{if $personal_account}}
<div id="profile-edit-gender-wrapper" class="form-group field select">
<label id="profile-edit-gender-label" for="gender-select" >{{$lbl_gender}} </label>
{{$gender nofilter}}
</div>
<div class="clear"></div>
{{$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}}
<div id="profile-edit-country-name-wrapper" class="form-group field select">
<label id="profile-edit-country-name-label" for="profile-edit-country-name" >{{$country_name.1}} </label>
<select name="country_name" id="profile-edit-country-name" class="form-control" onChange="Fill_States('{{$region.2}}');">
<option selected="selected" >{{$country_name.2}}</option>
<option>temp</option>
</select>
</div>
<div class="clear"></div>
<div id="profile-edit-region-wrapper" class="form-group field select">
<label id="profile-edit-region-label" for="profile-edit-region" >{{$region.1}} </label>
<select name="region" id="profile-edit-region" class="form-control" onChange="Update_Globals();" >
<option selected="selected" >{{$region.2}}</option>
<option>temp</option>
</select>
</div>
<div class="clear"></div>
{{include file="field_input.tpl" field=$pub_keywords}}
{{include file="field_input.tpl" field=$prv_keywords}}
{{include file="field_textarea.tpl" field=$about}}
<div class="form-group pull-right" >
<button type="submit" name="submit" class="btn btn-primary" value="{{$submit}}">{{$submit}}</button>
</div>
<div class="clear"></div>
<input type="hidden" name="pdesc" id="profile-edit-pdesc" value="{{$pdesc.2}}" />
<input type="hidden" id="contact-jot-text" name="contact" value="{{$contact.2}}" />
<input type="hidden" name="hometown" id="profile-edit-hometown" value="{{$hometown.2}}" />
<input type="hidden" name="politic" id="profile-edit-politic" value="{{$politic.2}}" />
<input type="hidden" name="religion" id="profile-edit-religion" value="{{$religion.2}}" />
<input type="hidden" id="likes-jot-text" name="likes" value="{{$likes.2}}" />
<input type="hidden" id="dislikes-jot-text" name="dislikes" value="{{$dislikes.2}}" />
<input type="hidden" name="marital" id="profile-edit-marital" value="{{$marital.value}}" />
<input type="hidden" name="with" id="profile-edit-with" value="{{$with.2}}" />
<input type="hidden" name="howlong" id="profile-edit-howlong" value="{{$howlong.2}}" />
<input type="hidden" name="sexual" id="profile-edit-sexual" value="{{$sexual.value}}" />
<input type="hidden" id="romance-jot-text" name="romance" value="{{$romance.2}}" />
<input type="hidden" id="work-jot-text" name="work" value="{{$work.2}}" />
<input type="hidden" id="education-jot-text" name="education" value="{{$education.2}}" />
<input type="hidden" id="interest-jot-text" name="interest" value="{{$interest.2}}" />
<input type="hidden" id="music-jot-text" name="music" value="{{$music.2}}" />
<input type="hidden" id="book-jot-text" name="book" value="{{$book.2}}" />
<input type="hidden" id="tv-jot-text" name="tv" value="{{$tv.2}}" />
<input type="hidden" id="film-jot-text" name="film" value="{{$film.2}}" />
{{/if}}
</form>
</div>
<script type="text/javascript">
Fill_Country('{{$country_name.2}}');
Fill_States('{{$region.2}}');
// initiale autosize for the textareas
autosize($("textarea.text-autosize"));
</script>

View File

@ -1,15 +0,0 @@
<div class="profile-listing-row" >
<div class="profile-listing-cell" >
<a href="profiles/{{$id}}" class="profile-listing-edit-link"><img class="profile-listing-photo" id="profile-listing-photo-{{$id}}" src="{{$photo}}" alt="{{$alt}}" /></a>
</div>
<div class="profile-listing-photo-end"></div>
<div class="profile-listing-cell" id="profile-listing-name-{{$id}}">
<a href="profiles/{{$id}}" class="profile-listing-edit-link" >{{$profile_name}}</a>
</div>
<div class="profile-listing-cell">
{{$visible nofilter}}
</div>
</div>
<div class="profile-listing-end"></div>

View File

@ -1,16 +0,0 @@
<div class="generic-page-wrapper">
<div class="section-title-wrapper pull-left">
<h2>{{$header}}</h2>
</div>
<div id="profile-listing-new-link-wrapper" class="pull-right" >
<a href="{{$cr_new_link}}" id="profile-listing-new-link" class="page-action faded-icon" title="{{$cr_new}}" data-toggle="tooltip">
<i class="fa fa-plus"></i></a>
</div>
<div class="section-content-wrapper">
<div id="profile-listing-profiles" class="profile-listing-table">
{{$profiles nofilter}}
</div>
</div>
</div>

View File

@ -0,0 +1,29 @@
<fieldset data-id="{{$profile_field.id}}">
<legend>&#8801; {{$profile_field.legend}}</legend>
<input type="hidden" name="profile_field_order[]" value="{{$profile_field.id}}">
{{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 *}}
<p>
<a id="settings-default-perms-menu" class="settings-default-perms" data-toggle="modal" data-target="#profile-field-acl-{{$profile_field.id}}">{{$profile_field.permissions}} {{$profile_field.permdesc}}</a>
</p>
{{* We include the aclModal directly into the template since we cant use frio's default modal *}}
<div class="modal" id="profile-field-acl-{{$profile_field.id}}">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">{{$profile_field.permissions}}</h4>
</div>
<div class="modal-body">
{{$profile_field.fields.acl nofilter}}
</div>
</div>
</div>
</div>
</fieldset>

View File

@ -0,0 +1,184 @@
<div class="generic-page-wrapper">
{{include file="section_title.tpl" title=$banner}}
{{* The actions dropdown which can performed to the current profile *}}
<div id="profile-edit-links">
<ul class="nav nav-pills preferences">
<li class="dropdown pull-right">
<button type="button" class="btn btn-link btn-sm dropdown-toggle" id="profile-edit-links-dropdown" data-toggle="dropdown" aria-expanded="false">
<i class="fa fa-angle-down" aria-hidden="true"></i>&nbsp;{{$profile_action}}
</button>
<ul class="dropdown-menu pull-right" role="menu" aria-labelledby="profile-edit-links-dropdown">
<li role="presentation"><a role="menuitem" href="{{$profpiclink}}" id="profile-photo_upload-link" title="{{$profpic}}"><i class="fa fa-user" aria-hidden="true"></i>&nbsp;{{$profpic}}</a></li>
<li role="presentation"><button role="menuitem" type="button" class="btn-link" id="profile-photo_upload-link-new" title="{{$lbl_profile_photo}}" onclick="openClose('profile-photo-upload-section');"><i class="fa fa-user" aria-hidden="true"></i>&nbsp;{{$lbl_profile_photo}}</button></li>
<li role="presentation" class="divider"></li>
<li role="presentation"><a role="menuitem" href="profile/{{$nickname}}" id="profile-edit-view-link" title="{{$viewprof}}">{{$viewprof}}</a></li>
</ul>
</li>
</ul>
</div>
<div id="profile-edit-links-end"></div>
<form enctype="multipart/form-data" action="settings/profile/photo" method="post">
<input type="hidden" name="form_security_token" value="{{$form_security_token_photo}}">
<div id="profile-photo-upload-section" class="panel">
<a id="profile-photo-upload-close" class="close pull-right" onclick="openClose('profile-photo-upload-section');"><i class="fa fa-times" aria-hidden="true"></i></a>
<div id="profile-photo-upload-wrapper">
<label id="profile-photo-upload-label" for="profile-photo-upload">{{$lbl_profile_photo}}:</label>
<input name="userfile" type="file" id="profile-photo-upload" size="48" />
</div>
<div class="profile-edit-submit-wrapper pull-right">
<button type="submit" name="submit" class="profile-edit-submit-button btn btn-primary" value="{{$submit}}">{{$submit}}</button>
</div>
<div class="clear"></div>
</div>
</form>
{{* Most of the Variables used below are arrays in the following style
0 => Some kind of identifier (e.g. for the ID)
1 => The label description
2 => The input values
3 => The additional help text (if available)
*}}
<form id="profile-edit-form" name="form1" action="" method="post">
<input type="hidden" name="form_security_token" value="{{$form_security_token}}">
<div class="panel-group panel-group-settings" id="profile-edit-wrapper" role="tablist" aria-multiselectable="true">
{{* The personal settings *}}
<div class="panel">
<div class="section-subtitle-wrapper" role="tab" id="personal">
<h4>
<a class="accordion-toggle" data-toggle="collapse" data-parent="#profile-edit-wrapper" href="#personal-collapse" aria-expanded="true" aria-controls="personal-collapse">
{{$lbl_personal_section}}
</a>
</h4>
</div>
{{* for the $detailed_profile we use bootstraps collapsable panel-groups to have expandable groups *}}
<div id="personal-collapse" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="personal">
<div class="section-content-tools-wrapper">
{{include file="field_input.tpl" field=$name}}
{{include file="field_input.tpl" field=$pdesc}}
{{$dob nofilter}}
{{$hide_friends nofilter}}
<div class="form-group pull-right">
<button type="submit" name="submit" class="btn btn-primary" value="{{$submit}}">{{$submit}}</button>
</div>
<div class="clear"></div>
</div>
</div>
</div>
{{* The location settings *}}
<div class="panel">
<div class="section-subtitle-wrapper" role="tab" id="location">
<h4>
<a class="accordion-toggle collapsed" data-toggle="collapse" data-parent="#profile-edit-wrapper" href="#location-collapse" aria-expanded="false" aria-controls="location-collapse">
{{$lbl_location_section}}
</a>
</h4>
</div>
<div id="location-collapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="location">
<div class="section-content-tools-wrapper">
{{include file="field_input.tpl" field=$address}}
{{include file="field_input.tpl" field=$locality}}
{{include file="field_input.tpl" field=$postal_code}}
<div id="profile-edit-country-name-wrapper" class="form-group field select">
<label id="profile-edit-country-name-label" for="profile-edit-country-name">{{$country_name.1}} </label>
<select name="country_name" id="profile-edit-country-name" class="form-control" onChange="Fill_States('{{$region.2}}');">
<option selected="selected">{{$country_name.2}}</option>
<option>temp</option>
</select>
</div>
<div class="clear"></div>
<div id="profile-edit-region-wrapper" class="form-group field select">
<label id="profile-edit-region-label" for="profile-edit-region">{{$region.1}} </label>
<select name="region" id="profile-edit-region" class="form-control" onChange="Update_Globals();">
<option selected="selected">{{$region.2}}</option>
<option>temp</option>
</select>
</div>
<div class="clear"></div>
<div class="form-group pull-right">
<button type="submit" name="submit" class="btn btn-primary" value="{{$submit}}">{{$submit}}</button>
</div>
<div class="clear"></div>
</div>
</div>
</div>
{{* The miscellanous other settings *}}
<div class="panel">
<div class="section-subtitle-wrapper" role="tab" id="miscellaneous">
<h4>
<a class="accordion-toggle collapsed" data-toggle="collapse" data-parent="#profile-edit-wrapper" href="#miscellaneous-collapse" aria-expanded="false" aria-controls="miscellaneous-collapse">
{{$lbl_miscellaneous_section}}
</a>
</h4>
</div>
<div id="miscellaneous-collapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="miscellaneous">
<div class="section-content-tools-wrapper">
{{include file="field_input.tpl" field=$homepage}}
{{include file="field_input.tpl" field=$xmpp}}
{{include file="field_input.tpl" field=$pub_keywords}}
{{include file="field_input.tpl" field=$prv_keywords}}
<div class="form-group pull-right">
<button type="submit" name="submit" class="btn btn-primary" value="{{$submit}}">{{$submit}}</button>
</div>
<div class="clear"></div>
</div>
</div>
</div>
{{* The miscellanous other settings *}}
<div class="panel">
<div class="section-subtitle-wrapper" role="tab" id="custom-fields">
<h4>
<a class="accordion-toggle collapsed" data-toggle="collapse" data-parent="#profile-edit-wrapper" href="#custom-fields-collapse" aria-expanded="false" aria-controls="custom-fields-collapse">
{{$lbl_custom_fields_section}}
</a>
</h4>
</div>
<div id="custom-fields-collapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="custom-fields">
<div class="section-content-tools-wrapper">
{{$custom_fields_description nofilter}}
<div id="profile-custom-fields">
{{foreach $custom_fields as $custom_field}}
{{include file="settings/profile/field/edit.tpl" profile_field=$custom_field}}
{{/foreach}}
</div>
<div class="form-group pull-right">
<button type="submit" name="submit" class="btn btn-primary" value="{{$submit}}">{{$submit}}</button>
</div>
<div class="clear"></div>
</div>
</div>
</div>
</div>
</form>
</div>
<script type="text/javascript">
Fill_Country('{{$country_name.2}}');
Fill_States('{{$region.2}}');
// initiale autosize for the textareas
autosize($("textarea.text-autosize"));
</script>

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -1257,6 +1257,10 @@ ul.tabs {
margin-top: 10px;
}
#profile-menu {
display: none;
}
#profile-edit-default-desc {
color: #FF0000;
border: 1px solid #FF8888;

View File

@ -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;
}

View File

@ -2406,6 +2406,10 @@ aside #id_password {
list-style: none;
}
#profile-menu {
display: none;
}
.profile-edit-side-div {
/* display: none; */
float: right;
@ -3236,7 +3240,6 @@ img.photo-album-photo {
}
#profile-edit-wrapper .toggle-section-content {
background:#ededed;
max-width:599px;
padding:5px;
}

View File

@ -85,15 +85,6 @@
</div>
<div id="contact-info-end"></div>
{{/if}}
{{if $profile_select}}
<div id="contact-edit-profile-select-text">
<h4>{{$lbl_vis1}}</h4>
<p>{{$lbl_vis2}}</p>
</div>
{{$profile_select nofilter}}
<div id="contact-edit-profile-select-end"></div>
{{/if}}
</div>
<input class="contact-edit-submit" type="submit" name="submit" value="{{$submit}}" />
{{/if}}

View File

@ -1,186 +0,0 @@
{{if $profile.edit}}
<div class="profile-view-actions">
<a class="btn" href="{{$profile.edit.0}}" id="profile-view-edit-link" title="{{$profile.edit.3}}">{{$profile.edit.1}}</a>
</div>
{{/if}}
{{include file="section_title.tpl"}}
<dl id="aprofile-fullname" class="aprofile">
<dt>{{$profile.fullname.0}}</dt>
<dd>{{$profile.fullname.1}}</dd>
</dl>
{{if $profile.membersince}}
<dl id="aprofile-membersince" class="aprofile">
<dt>{{$profile.membersince.0}}</dt>
<dd>{{$profile.membersince.1}}</dd>
</dl>
{{/if}}
{{if $profile.gender}}
<dl id="aprofile-gender" class="aprofile">
<dt>{{$profile.gender.0}}</dt>
<dd>{{$profile.gender.1}}</dd>
</dl>
{{/if}}
{{if $profile.birthday}}
<dl id="aprofile-birthday" class="aprofile">
<dt>{{$profile.birthday.0}}</dt>
<dd>{{$profile.birthday.1}}</dd>
</dl>
{{/if}}
{{if $profile.age}}
<dl id="aprofile-age" class="aprofile">
<dt>{{$profile.age.0}}</dt>
<dd>{{$profile.age.1}}</dd>
</dl>
{{/if}}
{{if $profile.marital}}
<dl id="aprofile-marital" class="aprofile">
<dt><span class="heart">&hearts;</span> {{$profile.marital.0}}</dt>
<dd>{{$profile.marital.1}}{{if $profile.marital.with}} ({{$profile.marital.with}}){{/if}}{{if $profile.howlong}} {{$profile.howlong}}{{/if}}</dd>
</dl>
{{/if}}
{{if $profile.sexual}}
<dl id="aprofile-sexual" class="aprofile">
<dt>{{$profile.sexual.0}}</dt>
<dd>{{$profile.sexual.1}}</dd>
</dl>
{{/if}}
{{if $profile.pub_keywords}}
<dl id="aprofile-tags" class="aprofile">
<dt>{{$profile.pub_keywords.0}}</dt>
<dd>{{$profile.pub_keywords.1}}</dd>
</dl>
{{/if}}
{{if $profile.homepage}}
<dl id="aprofile-homepage" class="aprofile">
<dt>{{$profile.homepage.0}}</dt>
<dd>{{$profile.homepage.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.hometown}}
<dl id="aprofile-hometown" class="aprofile">
<dt>{{$profile.hometown.0}}</dt>
<dd>{{$profile.hometown.1}}</dd>
</dl>
{{/if}}
{{if $profile.politic}}
<dl id="aprofile-politic" class="aprofile">
<dt>{{$profile.politic.0}}</dt>
<dd>{{$profile.politic.1}}</dd>
</dl>
{{/if}}
{{if $profile.religion}}
<dl id="aprofile-religion" class="aprofile">
<dt>{{$profile.religion.0}}</dt>
<dd>{{$profile.religion.1}}</dd>
</dl>
{{/if}}
{{if $profile.about}}
<dl id="aprofile-about" class="aprofile">
<dt>{{$profile.about.0}}</dt>
<dd>{{$profile.about.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.interest}}
<dl id="aprofile-interest" class="aprofile">
<dt>{{$profile.interest.0}}</dt>
<dd>{{$profile.interest.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.likes}}
<dl id="aprofile-likes" class="aprofile">
<dt>{{$profile.likes.0}}</dt>
<dd>{{$profile.likes.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.dislikes}}
<dl id="aprofile-dislikes" class="aprofile">
<dt>{{$profile.dislikes.0}}</dt>
<dd>{{$profile.dislikes.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.contact}}
<dl id="aprofile-contact" class="aprofile">
<dt>{{$profile.contact.0}}</dt>
<dd>{{$profile.contact.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.music}}
<dl id="aprofile-music" class="aprofile">
<dt>{{$profile.music.0}}</dt>
<dd>{{$profile.music.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.book}}
<dl id="aprofile-book" class="aprofile">
<dt>{{$profile.book.0}}</dt>
<dd>{{$profile.book.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.tv}}
<dl id="aprofile-tv" class="aprofile">
<dt>{{$profile.tv.0}}</dt>
<dd>{{$profile.tv.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.film}}
<dl id="aprofile-film" class="aprofile">
<dt>{{$profile.film.0}}</dt>
<dd>{{$profile.film.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.romance}}
<dl id="aprofile-romance" class="aprofile">
<dt>{{$profile.romance.0}}</dt>
<dd>{{$profile.romance.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.work}}
<dl id="aprofile-work" class="aprofile">
<dt>{{$profile.work.0}}</dt>
<dd>{{$profile.work.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.education}}
<dl id="aprofile-education" class="aprofile">
<dt>{{$profile.education.0}}</dt>
<dd>{{$profile.education.1 nofilter}}</dd>
</dl>
{{/if}}
{{if $profile.forumlist}}
<dl id="aprofile-forumlist" class="aprofile">
<dt>{{$profile.forumlist.0}}</dt>
<dd>{{$profile.forumlist.1 nofilter}}</dd>
</dl>
{{/if}}

View File

@ -1,454 +0,0 @@
<script>
$(document).ready(function() {
$('.toggle-section-content').hide();
$('.js-section-toggler').click(function(){
$('.toggle-section-content').hide();
$(this).next('.toggle-section-content').toggle();
});
});
</script>
<h1>{{$banner}}</h1>
<div id="profile-edit-links">
<ul>
<li><a class="btn" href="profile/{{$profile_id}}/view?tab=profile" id="profile-edit-view-link" title="{{$viewprof}}">{{$viewprof}}</a></li>
{{if $multi_profiles}}
<li><a class="btn" href="{{$profile_clone_link}}" id="profile-edit-clone-link" title="{{$cr_prof}}">{{$cl_prof}}</a></li>
<li><a class="btn" href="{{$profile_drop_link}}" id="profile-edit-drop-link" title="{{$del_prof}}" {{$disabled}} >{{$del_prof}}</a></li>
{{/if}}
</ul>
</div>
<div id="profile-edit-links-end"></div>
{{$default nofilter}}
<div id="profile-edit-wrapper" >
<form enctype="multipart/form-data" action="profile_photo" method="post">
<input type='hidden' name='form_security_token' value='{{$form_security_token_photo}}'>
<input type="hidden" name="profile" value="{{$profile_name.2}}" />
<!-- Profile picture -->
{{if $detailled_profile}}
<div class="toggle-section js-toggle-section">
<a class="section-caption js-section-toggler" href="javascript:;">{{$lbl_picture_section}} &raquo;</a>
<div class="js-section toggle-section-content hidden">
{{/if}}
<div id="profile-photo-upload-wrapper">
<label id="profile-photo-upload-label" for="profile-photo-upload">{{$lbl_profile_photo}}:</label>
<input name="userfile" type="file" id="profile-photo-upload" size="48" />
</div>
<div class="profile-edit-submit-wrapper" >
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}" />
</div>
<div class="profile-edit-submit-end"></div>
{{if $detailled_profile}}
</div>
</div>
{{/if}}
</form>
<form id="profile-edit-form" name="form1" action="profiles/{{$profile_id}}" method="post" >
<input type='hidden' name='form_security_token' value='{{$form_security_token}}'>
{{if $detailled_profile}}
<!-- Basic information -->
<div class="toggle-section js-toggle-section">
<a class="section-caption js-section-toggler" href="javascript:;">{{$lbl_basic_section}} &raquo;</a>
<div class="js-section toggle-section-content hidden">
{{include file="field_yesno.tpl" field=$details}}
{{if $multi_profiles}}
<div id="profile-edit-profile-name-wrapper" >
<label id="profile-edit-profile-name-label" for="profile-edit-profile-name" >{{$profile_name.1}} </label>
<input type="text" size="32" name="profile_name" id="profile-edit-profile-name" value="{{$profile_name.2}}" /><div class="required">*</div>
</div>
<div id="profile-edit-profile-name-end"></div>
{{else}}
<input type="hidden" name="profile_name" id="profile-edit-profile-name" value="{{$profile_name.2}}" />
{{/if}}
<div id="profile-edit-name-wrapper" >
<label id="profile-edit-name-label" for="profile-edit-name" >{{$name.1}} </label>
<input type="text" size="32" name="name" id="profile-edit-name" value="{{$name.2}}" />
</div>
<div id="profile-edit-name-end"></div>
<div id="profile-edit-gender-wrapper" >
<label id="profile-edit-gender-label" for="gender-select" >{{$lbl_gender}} </label>
{{$gender nofilter}}
</div>
<div id="profile-edit-gender-end"></div>
<div id="profile-edit-pdesc-wrapper" >
<label id="profile-edit-pdesc-label" for="profile-edit-pdesc" >{{$pdesc.1}} </label>
<input type="text" size="32" name="pdesc" id="profile-edit-pdesc" value="{{$pdesc.2}}" />
</div>
<div id="profile-edit-pdesc-end"></div>
<div id="profile-edit-xmpp-wrapper" >
<label id="profile-edit-xmpp-label" for="profile-edit-xmpp" >{{$xmpp.1}} </label>
<input type="text" size="32" name="xmpp" id="profile-edit-xmpp" value="{{$xmpp.2}}" />
</div>
<div id="profile-edit-xmpp-desc">{{$xmpp.3}}</div>
<div id="profile-edit-xmpp-end"></div>
<div id="profile-edit-homepage-wrapper" >
<label id="profile-edit-homepage-label" for="profile-edit-homepage" >{{$homepage.1}} </label>
<input type="text" size="32" name="homepage" id="profile-edit-homepage" value="{{$homepage.2}}" />
</div>
<div id="profile-edit-homepage-end"></div>
<div id="profile-edit-dob-wrapper" >
{{$dob nofilter}}
</div>
<div id="profile-edit-dob-end"></div>
{{$hide_friends nofilter}}
<div id="about-jot-wrapper">
<div id="about-jot-desc">{{$about.1}}</div>
<textarea rows="10" cols="72" id="profile-about-text" name="about" style="width:599px;">{{$about.2}}</textarea>
</div>
<div id="about-jot-end"></div>
<div id="contact-jot-wrapper" >
<div id="contact-jot-desc">{{$contact.1}}</div>
<textarea rows="10" cols="72" id="contact-jot-text" name="contact" style="width:599px;">{{$contact.2}}</textarea>
</div>
<div id="contact-jot-end"></div>
<div id="profile-edit-pubkeywords-wrapper" >
<label id="profile-edit-pubkeywords-label" for="profile-edit-pubkeywords" >{{$pub_keywords.1}} </label>
<input type="text" size="32" name="pub_keywords" id="profile-edit-pubkeywords" title="{{$lbl_ex2}}" value="{{$pub_keywords.2}}" />
</div>
<div id="profile-edit-pubkeywords-desc">{{$pub_keywords.3}}</div>
<div id="profile-edit-pubkeywords-end"></div>
<div id="profile-edit-prvkeywords-wrapper" >
<label id="profile-edit-prvkeywords-label" for="profile-edit-prvkeywords" >{{$prv_keywords.1}} </label>
<input type="text" size="32" name="prv_keywords" id="profile-edit-prvkeywords" title="{{$lbl_ex2}}" value="{{$prv_keywords.2}}" />
</div>
<div id="profile-edit-prvkeywords-desc">{{$prv_keywords.3}}</div>
<div id="profile-edit-prvkeywords-end"></div>
<div class="profile-edit-submit-wrapper" >
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}" />
</div>
<div class="profile-edit-submit-end"></div>
</div>
</div>
<!-- About you -->
<div class="toggle-section js-toggle-section">
<a class="section-caption js-section-toggler" href="javascript:;">{{$lbl_about_section}} &raquo;</a>
<div class="js-section toggle-section-content hidden">
<div><b>{{$lbl_location_section}}</b></div>
<div id="profile-edit-address-wrapper" >
<label id="profile-edit-address-label" for="profile-edit-address" >{{$address.1}} </label>
<input type="text" size="32" name="address" id="profile-edit-address" value="{{$address.2}}" />
</div>
<div id="profile-edit-address-end"></div>
<div id="profile-edit-locality-wrapper" >
<label id="profile-edit-locality-label" for="profile-edit-locality" >{{$locality.1}} </label>
<input type="text" size="32" name="locality" id="profile-edit-locality" value="{{$locality.2}}" />
</div>
<div id="profile-edit-locality-end"></div>
<div id="profile-edit-postal-code-wrapper" >
<label id="profile-edit-postal-code-label" for="profile-edit-postal-code" >{{$postal_code.1}} </label>
<input type="text" size="32" name="postal_code" id="profile-edit-postal-code" value="{{$postal_code.2}}" />
</div>
<div id="profile-edit-postal-code-end"></div>
<div id="profile-edit-country-name-wrapper" >
<label id="profile-edit-country-name-label" for="profile-edit-country-name" >{{$country_name.1}} </label>
<select name="country_name" id="profile-edit-country-name" onChange="Fill_States('{{$region.2}}');">
<option selected="selected" >{{$country_name.2}}</option>
</select>
</div>
<div id="profile-edit-country-name-end"></div>
<div id="profile-edit-region-wrapper" >
<label id="profile-edit-region-label" for="profile-edit-region" >{{$region.2}} </label>
<select name="region" id="profile-edit-region" onChange="Update_Globals();" >
<option selected="selected" >{{$region.2}}</option>
</select>
</div>
<div id="profile-edit-region-end"></div>
<div id="profile-edit-hometown-wrapper" >
<label id="profile-edit-hometown-label" for="profile-edit-hometown" >{{$hometown.1}} </label>
<input type="text" size="32" name="hometown" id="profile-edit-hometown" value="{{$hometown.2}}" />
</div>
<div id="profile-edit-hometown-end"></div>
<br>
<div><b>{{$lbl_preferences_section}}</b></div>
<div id="profile-edit-sexual-wrapper" >
<label id="profile-edit-sexual-label" for="sexual-select" >{{$lbl_sexual}} </label>
{{$sexual nofilter}}
</div>
<div id="profile-edit-sexual-end"></div>
<div id="profile-edit-politic-wrapper" >
<label id="profile-edit-politic-label" for="profile-edit-politic" >{{$politic.1}} </label>
<input type="text" size="32" name="politic" id="profile-edit-politic" value="{{$politic.2}}" />
</div>
<div id="profile-edit-politic-end"></div>
<div id="profile-edit-religion-wrapper" >
<label id="profile-edit-religion-label" for="profile-edit-religion" >{{$religion.1}} </label>
<input type="text" size="32" name="religion" id="profile-edit-religion" value="{{$religion.2}}" />
</div>
<div id="profile-edit-religion-end"></div>
<div id="likes-jot-wrapper">
<div id="likes-jot-desc">{{$likes.1}}</div>
<textarea rows="10" cols="72" id="likes-jot-text" name="likes" style="width:599px;">{{$likes.2}}</textarea>
</div>
<div id="likes-jot-end"></div>
<div id="dislikes-jot-wrapper">
<div id="dislikes-jot-desc">{{$dislikes.1}}</div>
<textarea rows="10" cols="72" id="dislikes-jot-text" name="dislikes" style="width:599px;">{{$dislikes.2}}</textarea>
</div>
<div id="dislikes-jot-end"></div>
<div class="profile-edit-submit-wrapper" >
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}" />
</div>
<div class="profile-edit-submit-end"></div>
</div>
</div>
<!-- Status -->
<div class="toggle-section js-toggle-section">
<a class="section-caption js-section-toggler" href="javascript:;">{{$lbl_status_section}} &raquo;</a>
<div class="js-section toggle-section-content hidden">
<div id="profile-edit-marital-wrapper" >
<label id="profile-edit-marital-label" for="profile-edit-marital" >{{$lbl_marital nofilter}} </label>
{{$marital nofilter}}
</div>
<label id="profile-edit-with-label" for="profile-edit-with" > {{$with.1}} </label>
<input type="text" size="32" name="with" id="profile-edit-with" title="{{$with.3}}" value="{{$with.2}}" />
<label id="profile-edit-howlong-label" for="profile-edit-howlong" > {{$howlong.1}} </label>
<input type="text" size="32" name="howlong" id="profile-edit-howlong" title="{{$howlong.1}}" value="{{$howlong.2}}" />
<div id="profile-edit-marital-end"></div>
<div id="romance-jot-wrapper" >
<div id="romance-jot-desc">{{$romance.1}}</div>
<textarea rows="10" cols="72" id="romance-jot-text" name="romance" style="width:599px;">{{$romance.2}}</textarea>
</div>
<div id="romance-jot-end"></div>
<div id="work-jot-wrapper">
<div id="work-jot-desc">{{$work.1}}</div>
<textarea rows="10" cols="72" id="work-jot-text" name="work" style="width:599px;">{{$work.2}}</textarea>
</div>
<div id="work-jot-end"></div>
<div id="education-jot-wrapper" >
<div id="education-jot-desc">{{$education.1}}</div>
<textarea rows="10" cols="72" id="education-jot-text" name="education" style="width:599px;">{{$education.2}}</textarea>
</div>
<div id="education-jot-end"></div>
<div class="profile-edit-submit-wrapper" >
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}" />
</div>
<div class="profile-edit-submit-end"></div>
</div>
</div>
<!-- Interests -->
<div class="toggle-section js-toggle-section">
<a class="section-caption js-section-toggler" href="javascript:;">{{$lbl_interests_section}} &raquo;</a>
<div class="js-section toggle-section-content hidden">
<div id="interest-jot-wrapper">
<div id="interest-jot-desc">{{$interest.1}}</div>
<textarea rows="10" cols="72" id="interest-jot-text" name="interest" style="width:599px;">{{$interest.2}}</textarea>
</div>
<div id="interest-jot-end"></div>
<div id="music-jot-wrapper">
<div id="music-jot-desc">{{$music.1}}</div>
<textarea rows="10" cols="72" id="music-jot-text" name="music" style="width:599px;">{{$music.2}}</textarea>
</div>
<div id="music-jot-end"></div>
<div id="book-jot-wrapper">
<div id="book-jot-desc">{{$book.1}}</div>
<textarea rows="10" cols="72" id="book-jot-text" name="book" style="width:599px;">{{$book.2}}</textarea>
</div>
<div id="book-jot-end"></div>
<div id="tv-jot-wrapper">
<div id="tv-jot-desc">{{$tv.1}}</div>
<textarea rows="10" cols="72" id="tv-jot-text" name="tv" style="width:599px;">{{$tv.2}}</textarea>
</div>
<div id="tv-jot-end"></div>
<div id="film-jot-wrapper">
<div id="film-jot-desc">{{$film.1}}</div>
<textarea rows="10" cols="72" id="film-jot-text" name="film" style="width:599px;">{{$film.2}}</textarea>
</div>
<div id="film-jot-end"></div>
<div class="profile-edit-submit-wrapper" >
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}" />
</div>
<div class="profile-edit-submit-end"></div>
</div>
</div>
{{else}}
{{if $personal_account}}
{{include file="field_yesno.tpl" field=$details}}
{{/if}}
<div id="profile-edit-profile-name-wrapper" >
<label id="profile-edit-profile-name-label" for="profile-edit-profile-name" >{{$profile_name.1}} </label>
<input type="text" size="32" name="profile_name" id="profile-edit-profile-name" value="{{$profile_name.2}}" /><div class="required">*</div>
</div>
<div id="profile-edit-profile-name-end"></div>
<div id="profile-edit-name-wrapper" >
<label id="profile-edit-name-label" for="profile-edit-name" >{{$name.1}} </label>
<input type="text" size="32" name="name" id="profile-edit-name" value="{{$name.2}}" />
</div>
<div id="profile-edit-name-end"></div>
{{if $personal_account}}
<div id="profile-edit-gender-wrapper" >
<label id="profile-edit-gender-label" for="gender-select" >{{$lbl_gender}} </label>
{{$gender nofilter}}
</div>
<div id="profile-edit-gender-end"></div>
<div id="profile-edit-dob-wrapper" >
{{$dob nofilter}}
</div>
<div id="profile-edit-dob-end"></div>
{{/if}}
<div id="profile-edit-xmpp-wrapper" >
<label id="profile-edit-xmpp-label" for="profile-edit-xmpp" >{{$xmpp.1}} </label>
<input type="text" size="32" name="xmpp" id="profile-edit-xmpp" value="{{$xmpp.2}}" />
</div>
<div id="profile-edit-xmpp-desc">{{$xmpp.3}}</div>
<div id="profile-edit-xmpp-end"></div>
<div id="profile-edit-homepage-wrapper" >
<label id="profile-edit-homepage-label" for="profile-edit-homepage" >{{$homepage.1}} </label>
<input type="text" size="32" name="homepage" id="profile-edit-homepage" value="{{$homepage.2}}" />
</div>
<div id="profile-edit-homepage-end"></div>
{{$hide_friends nofilter}}
<div id="profile-edit-address-wrapper" >
<label id="profile-edit-address-label" for="profile-edit-address" >{{$address.1}} </label>
<input type="text" size="32" name="address" id="profile-edit-address" value="{{$address.2}}" />
</div>
<div id="profile-edit-address-end"></div>
<div id="profile-edit-locality-wrapper" >
<label id="profile-edit-locality-label" for="profile-edit-locality" >{{$locality.1}} </label>
<input type="text" size="32" name="locality" id="profile-edit-locality" value="{{$locality.2}}" />
</div>
<div id="profile-edit-locality-end"></div>
<div id="profile-edit-postal-code-wrapper" >
<label id="profile-edit-postal-code-label" for="profile-edit-postal-code" >{{$postal_code.1}} </label>
<input type="text" size="32" name="postal_code" id="profile-edit-postal-code" value="{{$postal_code.2}}" />
</div>
<div id="profile-edit-postal-code-end"></div>
<div id="profile-edit-country-name-wrapper" >
<label id="profile-edit-country-name-label" for="profile-edit-country-name" >{{$country_name.1}} </label>
<select name="country_name" id="profile-edit-country-name" onChange="Fill_States('{{$region.2}}');">
<option selected="selected" >{{$country_name.2}}</option>
<option>temp</option>
</select>
</div>
<div id="profile-edit-country-name-end"></div>
<div id="profile-edit-region-wrapper" >
<label id="profile-edit-region-label" for="profile-edit-region" >{{$region.1}} </label>
<select name="region" id="profile-edit-region" onChange="Update_Globals();" >
<option selected="selected" >{{$region.2}}</option>
<option>temp</option>
</select>
</div>
<div id="profile-edit-region-end"></div>
<div id="profile-edit-pubkeywords-wrapper" >
<label id="profile-edit-pubkeywords-label" for="profile-edit-pubkeywords" >{{$pub_keywords.1}} </label>
<input type="text" size="32" name="pub_keywords" id="profile-edit-pubkeywords" title="{{$lbl_ex2}}" value="{{$pub_keywords.2}}" />
</div><div id="profile-edit-pubkeywords-desc">{{$pub_keywords.3}}</div>
<div id="profile-edit-pubkeywords-end"></div>
<div id="profile-edit-prvkeywords-wrapper" >
<label id="profile-edit-prvkeywords-label" for="profile-edit-prvkeywords" >{{$prv_keywords.1}} </label>
<input type="text" size="32" name="prv_keywords" id="profile-edit-prvkeywords" title="{{$lbl_ex2}}" value="{{$prv_keywords.2}}" />
</div><div id="profile-edit-prvkeywords-desc">{{$prv_keywords.3}}</div>
<div id="profile-edit-prvkeywords-end"></div>
<div id="about-jot-wrapper" >
<p id="about-jot-desc" >
{{$about.1}}
</p>
<textarea rows="10" cols="72" id="profile-about-text" name="about" >{{$about.2}}</textarea>
</div>
<div id="about-jot-end"></div>
<div class="profile-edit-submit-wrapper" >
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}" />
</div>
<div class="profile-edit-submit-end"></div>
<input type="hidden" name="pdesc" id="profile-edit-pdesc" value="{{$pdesc.2}}" />
<input type="hidden" id="contact-jot-text" name="contact" value="{{$contact.2}}" />
<input type="hidden" name="hometown" id="profile-edit-hometown" value="{{$hometown.2}}" />
<input type="hidden" name="politic" id="profile-edit-politic" value="{{$politic.2}}" />
<input type="hidden" name="religion" id="profile-edit-religion" value="{{$religion.2}}" />
<input type="hidden" id="likes-jot-text" name="likes" value="{{$likes.2}}" />
<input type="hidden" id="dislikes-jot-text" name="dislikes" value="{{$dislikes.2}}" />
<input type="hidden" name="marital" id="profile-edit-marital" value="{{$marital.2}}" />
<input type="hidden" name="with" id="profile-edit-with" value="{{$with.2}}" />
<input type="hidden" name="howlong" id="profile-edit-howlong" value="{{$howlong.2}}" />
<input type="hidden" name="sexual" id="profile-edit-sexual" value="{{$sexual.2}}" />
<input type="hidden" id="romance-jot-text" name="romance" value="{{$romance.2}}" />
<input type="hidden" id="work-jot-text" name="work" value="{{$work.2}}" />
<input type="hidden" id="education-jot-text" name="education" value="{{$education.2}}" />
<input type="hidden" id="interest-jot-text" name="interest" value="{{$interest.2}}" />
<input type="hidden" id="music-jot-text" name="music" value="{{$music.2}}" />
<input type="hidden" id="book-jot-text" name="book" value="{{$book.2}}" />
<input type="hidden" id="tv-jot-text" name="tv" value="{{$tv.2}}" />
<input type="hidden" id="film-jot-text" name="film" value="{{$film.2}}" />
{{/if}}
</form>
</div>
<script type="text/javascript">Fill_Country('{{$country_name.2}}');Fill_States('{{$region.2}}');</script>

View File

@ -0,0 +1,171 @@
<script>
$(document).ready(function () {
//$('.toggle-section-content + .toggle-section-content').hide();
$('.js-section-toggler').click(function () {
$('.toggle-section-content').hide();
$(this).next('.toggle-section-content').toggle();
});
});
</script>
<h1>{{$banner}}</h1>
<div id="profile-edit-links">
<ul>
<li><a class="btn" href="profile/{{$nickname}}" id="profile-edit-view-link" title="{{$viewprof}}">{{$viewprof}}</a></li>
</ul>
</div>
<div id="profile-edit-links-end"></div>
<div id="profile-edit-wrapper">
<form enctype="multipart/form-data" action="settings/profile/photo" method="post">
<input type="hidden" name="form_security_token" value="{{$form_security_token_photo}}">
<!-- Profile picture -->
<div class="toggle-section js-toggle-section">
<a class="section-caption js-section-toggler" href="javascript:;">{{$lbl_picture_section}} &raquo;</a>
<div class="js-section toggle-section-content hidden">
<div id="profile-photo-upload-wrapper">
<label id="profile-photo-upload-label" for="profile-photo-upload">{{$lbl_profile_photo}}:</label>
<input name="userfile" type="file" id="profile-photo-upload" size="48"/>
</div>
<div class="profile-edit-submit-wrapper">
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}"/>
</div>
<div class="profile-edit-submit-end"></div>
</div>
</div>
</form>
<form id="profile-edit-form" name="form1" action="" method="post">
<input type="hidden" name="form_security_token" value="{{$form_security_token}}">
<!-- Basic information -->
<div class="toggle-section js-toggle-section">
<a class="section-caption js-section-toggler" href="javascript:;">{{$lbl_personal_section}} &raquo;</a>
<div class="js-section toggle-section-content hidden">
<div id="profile-edit-name-wrapper">
<label id="profile-edit-name-label" for="profile-edit-name">{{$name.1}} </label>
<input type="text" size="32" name="name" id="profile-edit-name" value="{{$name.2}}"/>
</div>
<div id="profile-edit-name-end"></div>
<div id="profile-edit-pdesc-wrapper">
<label id="profile-edit-pdesc-label" for="profile-edit-pdesc">{{$pdesc.1}} </label>
<input type="text" size="32" name="pdesc" id="profile-edit-pdesc" value="{{$pdesc.2}}"/>
</div>
<div id="profile-edit-pdesc-end"></div>
<div id="profile-edit-xmpp-wrapper">
<label id="profile-edit-xmpp-label" for="profile-edit-xmpp">{{$xmpp.1}} </label>
<input type="text" size="32" name="xmpp" id="profile-edit-xmpp" value="{{$xmpp.2}}"/>
</div>
<div id="profile-edit-xmpp-desc">{{$xmpp.3}}</div>
<div id="profile-edit-xmpp-end"></div>
<div id="profile-edit-homepage-wrapper">
<label id="profile-edit-homepage-label" for="profile-edit-homepage">{{$homepage.1}} </label>
<input type="text" size="32" name="homepage" id="profile-edit-homepage" value="{{$homepage.2}}"/>
</div>
<div id="profile-edit-homepage-end"></div>
<div id="profile-edit-dob-wrapper">
{{$dob nofilter}}
</div>
<div id="profile-edit-dob-end"></div>
{{$hide_friends nofilter}}
<div id="profile-edit-pubkeywords-wrapper">
<label id="profile-edit-pubkeywords-label" for="profile-edit-pubkeywords">{{$pub_keywords.1}} </label>
<input type="text" size="32" name="pub_keywords" id="profile-edit-pubkeywords" title="{{$lbl_ex2}}" value="{{$pub_keywords.2}}"/>
</div>
<div id="profile-edit-pubkeywords-desc">{{$pub_keywords.3}}</div>
<div id="profile-edit-pubkeywords-end"></div>
<div id="profile-edit-prvkeywords-wrapper">
<label id="profile-edit-prvkeywords-label" for="profile-edit-prvkeywords">{{$prv_keywords.1}} </label>
<input type="text" size="32" name="prv_keywords" id="profile-edit-prvkeywords" title="{{$lbl_ex2}}" value="{{$prv_keywords.2}}"/>
</div>
<div id="profile-edit-prvkeywords-desc">{{$prv_keywords.3}}</div>
<div id="profile-edit-prvkeywords-end"></div>
<div class="profile-edit-submit-wrapper">
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}"/>
</div>
<div class="profile-edit-submit-end"></div>
</div>
</div>
<!-- About you -->
<div class="toggle-section js-toggle-section">
<a class="section-caption js-section-toggler" href="javascript:;">{{$lbl_location_section}} &raquo;</a>
<div class="js-section toggle-section-content hidden">
<div id="profile-edit-address-wrapper">
<label id="profile-edit-address-label" for="profile-edit-address">{{$address.1}} </label>
<input type="text" size="32" name="address" id="profile-edit-address" value="{{$address.2}}"/>
</div>
<div id="profile-edit-address-end"></div>
<div id="profile-edit-locality-wrapper">
<label id="profile-edit-locality-label" for="profile-edit-locality">{{$locality.1}} </label>
<input type="text" size="32" name="locality" id="profile-edit-locality" value="{{$locality.2}}"/>
</div>
<div id="profile-edit-locality-end"></div>
<div id="profile-edit-postal-code-wrapper">
<label id="profile-edit-postal-code-label" for="profile-edit-postal-code">{{$postal_code.1}} </label>
<input type="text" size="32" name="postal_code" id="profile-edit-postal-code" value="{{$postal_code.2}}"/>
</div>
<div id="profile-edit-postal-code-end"></div>
<div id="profile-edit-country-name-wrapper">
<label id="profile-edit-country-name-label" for="profile-edit-country-name">{{$country_name.1}} </label>
<select name="country_name" id="profile-edit-country-name" onChange="Fill_States('{{$region.2}}');">
<option selected="selected">{{$country_name.2}}</option>
</select>
</div>
<div id="profile-edit-country-name-end"></div>
<div id="profile-edit-region-wrapper">
<label id="profile-edit-region-label" for="profile-edit-region">{{$region.1}} </label>
<select name="region" id="profile-edit-region" onChange="Update_Globals();">
<option selected="selected">{{$region.2}}</option>
</select>
</div>
<div id="profile-edit-region-end"></div>
<div class="profile-edit-submit-wrapper">
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}"/>
</div>
<div class="profile-edit-submit-end"></div>
</div>
</div>
<!-- Interests -->
<div class="toggle-section js-toggle-section">
<a class="section-caption js-section-toggler" href="javascript:;">{{$lbl_custom_fields_section}} &raquo;</a>
<div class="js-section toggle-section-content hidden">
{{$custom_fields_description nofilter}}
<div id="profile-custom-fields">
{{foreach $custom_fields as $custom_field}}
{{include file="settings/profile/field/edit.tpl" profile_field=$custom_field}}
{{/foreach}}
</div>
<div class="profile-edit-submit-wrapper">
<input type="submit" name="submit" class="profile-edit-submit-button" value="{{$submit}}"/>
</div>
<div class="profile-edit-submit-end"></div>
</div>
</div>
</form>
</div>
<script type="text/javascript">
Fill_Country('{{$country_name.2}}');
Fill_States('{{$region.2}}');
</script>

View File

@ -140,14 +140,14 @@ function vier_community_info()
// last 9 users
if ($show_lastusers) {
$publish = (DI::config()->get('system', 'publish_all') ? '' : " AND `publish` = 1 ");
$publish = (DI::config()->get('system', 'publish_all') ? '' : "`publish` = 1");
$order = " ORDER BY `register_date` DESC ";
$tpl = Renderer::getMarkupTemplate('ch_directory_item.tpl');
$r = q("SELECT `profile`.*, `user`.`nickname`
FROM `profile` LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
WHERE `is-default` = 1 $publish AND `user`.`blocked` = 0 $order LIMIT %d , %d ",
WHERE $publish AND `user`.`blocked` = 0 $order LIMIT %d , %d ",
0,
9
);