Merge pull request #8146 from MrPetovan/task/7817-custom-fields-part-1
New custom profile fields feature part 1: Everything but custom profile fields
This commit is contained in:
commit
0f0c58ddb3
56 changed files with 1016 additions and 719 deletions
|
@ -494,7 +494,7 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
|
||||||
}
|
}
|
||||||
} elseif ($mode === 'profile') {
|
} elseif ($mode === 'profile') {
|
||||||
$items = conversation_add_children($items, false, $order, $uid);
|
$items = conversation_add_children($items, false, $order, $uid);
|
||||||
$profile_owner = $a->profile['profile_uid'];
|
$profile_owner = $a->profile['uid'];
|
||||||
|
|
||||||
if (!$update) {
|
if (!$update) {
|
||||||
$tab = 'posts';
|
$tab = 'posts';
|
||||||
|
@ -508,7 +508,7 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$live_update_div = '<div id="live-profile"></div>' . "\r\n"
|
$live_update_div = '<div id="live-profile"></div>' . "\r\n"
|
||||||
. "<script> var profile_uid = " . $a->profile['profile_uid']
|
. "<script> var profile_uid = " . $a->profile['uid']
|
||||||
. "; var netargs = '?f='; var profile_page = " . $pager->getPage() . "; </script>\r\n";
|
. "; var netargs = '?f='; var profile_page = " . $pager->getPage() . "; </script>\r\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
mod/cal.php
19
mod/cal.php
|
@ -101,27 +101,14 @@ function cal_content(App $a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup permissions structures
|
// Setup permissions structures
|
||||||
$remote_contact = false;
|
|
||||||
$contact_id = 0;
|
|
||||||
|
|
||||||
$owner_uid = intval($a->data['user']['uid']);
|
$owner_uid = intval($a->data['user']['uid']);
|
||||||
$nick = $a->data['user']['nickname'];
|
$nick = $a->data['user']['nickname'];
|
||||||
|
|
||||||
if (!empty(Session::getRemoteContactID($a->profile['profile_uid']))) {
|
$contact_id = Session::getRemoteContactID($a->profile['uid']);
|
||||||
$contact_id = Session::getRemoteContactID($a->profile['profile_uid']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($contact_id) {
|
$remote_contact = $contact_id && DBA::exists('contact', ['id' => $contact_id, 'uid' => $a->profile['uid']]);
|
||||||
$r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
|
|
||||||
intval($contact_id),
|
|
||||||
intval($a->profile['profile_uid'])
|
|
||||||
);
|
|
||||||
if (DBA::isResult($r)) {
|
|
||||||
$remote_contact = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$is_owner = local_user() == $a->profile['profile_uid'];
|
$is_owner = local_user() == $a->profile['uid'];
|
||||||
|
|
||||||
if ($a->profile['hidewall'] && !$is_owner && !$remote_contact) {
|
if ($a->profile['hidewall'] && !$is_owner && !$remote_contact) {
|
||||||
notice(DI::l10n()->t('Access to this profile has been restricted.') . EOL);
|
notice(DI::l10n()->t('Access to this profile has been restricted.') . EOL);
|
||||||
|
|
|
@ -100,7 +100,7 @@ function display_init(App $a)
|
||||||
$nickname = str_replace(Strings::normaliseLink(DI::baseUrl())."/profile/", "", Strings::normaliseLink($profiledata["url"]));
|
$nickname = str_replace(Strings::normaliseLink(DI::baseUrl())."/profile/", "", Strings::normaliseLink($profiledata["url"]));
|
||||||
|
|
||||||
if ($nickname != $a->user["nickname"]) {
|
if ($nickname != $a->user["nickname"]) {
|
||||||
$profile = DBA::fetchFirst("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `user`.* FROM `profile`
|
$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`
|
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 `profile`.`is-default` AND `contact`.`self` LIMIT 1",
|
||||||
$nickname
|
$nickname
|
||||||
|
@ -175,9 +175,9 @@ function display_content(App $a, $update = false, $update_uid = 0)
|
||||||
$item_id = $_REQUEST['item_id'];
|
$item_id = $_REQUEST['item_id'];
|
||||||
$item = Item::selectFirst(['uid', 'parent', 'parent-uri'], ['id' => $item_id]);
|
$item = Item::selectFirst(['uid', 'parent', 'parent-uri'], ['id' => $item_id]);
|
||||||
if ($item['uid'] != 0) {
|
if ($item['uid'] != 0) {
|
||||||
$a->profile = ['uid' => intval($item['uid']), 'profile_uid' => intval($item['uid'])];
|
$a->profile = ['uid' => intval($item['uid'])];
|
||||||
} else {
|
} else {
|
||||||
$a->profile = ['uid' => intval($update_uid), 'profile_uid' => intval($update_uid)];
|
$a->profile = ['uid' => intval($update_uid)];
|
||||||
}
|
}
|
||||||
$item_parent = $item['parent'];
|
$item_parent = $item['parent'];
|
||||||
$item_parent_uri = $item['parent-uri'];
|
$item_parent_uri = $item['parent-uri'];
|
||||||
|
@ -249,13 +249,12 @@ function display_content(App $a, $update = false, $update_uid = 0)
|
||||||
|
|
||||||
if (DBA::isResult($parent)) {
|
if (DBA::isResult($parent)) {
|
||||||
$a->profile['uid'] = ($a->profile['uid'] ?? 0) ?: $parent['uid'];
|
$a->profile['uid'] = ($a->profile['uid'] ?? 0) ?: $parent['uid'];
|
||||||
$a->profile['profile_uid'] = ($a->profile['profile_uid'] ?? 0) ?: $parent['uid'];
|
$is_remote_contact = Session::getRemoteContactID($a->profile['uid']);
|
||||||
$is_remote_contact = Session::getRemoteContactID($a->profile['profile_uid']);
|
|
||||||
if ($is_remote_contact) {
|
if ($is_remote_contact) {
|
||||||
$item_uid = $parent['uid'];
|
$item_uid = $parent['uid'];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$a->profile = ['uid' => intval($item['uid']), 'profile_uid' => intval($item['uid'])];
|
$a->profile = ['uid' => intval($item['uid'])];
|
||||||
}
|
}
|
||||||
|
|
||||||
$page_contact = DBA::selectFirst('contact', [], ['self' => true, 'uid' => $a->profile['uid']]);
|
$page_contact = DBA::selectFirst('contact', [], ['self' => true, 'uid' => $a->profile['uid']]);
|
||||||
|
@ -263,7 +262,7 @@ function display_content(App $a, $update = false, $update_uid = 0)
|
||||||
$a->page_contact = $page_contact;
|
$a->page_contact = $page_contact;
|
||||||
}
|
}
|
||||||
|
|
||||||
$is_owner = (local_user() && (in_array($a->profile['profile_uid'], [local_user(), 0])) ? true : false);
|
$is_owner = (local_user() && (in_array($a->profile['uid'], [local_user(), 0])) ? true : false);
|
||||||
|
|
||||||
if (!empty($a->profile['hidewall']) && !$is_owner && !$is_remote_contact) {
|
if (!empty($a->profile['hidewall']) && !$is_owner && !$is_remote_contact) {
|
||||||
throw new HTTPException\ForbiddenException(DI::l10n()->t('Access to this profile has been restricted.'));
|
throw new HTTPException\ForbiddenException(DI::l10n()->t('Access to this profile has been restricted.'));
|
||||||
|
@ -284,9 +283,9 @@ function display_content(App $a, $update = false, $update_uid = 0)
|
||||||
];
|
];
|
||||||
$o .= status_editor($a, $x, 0, true);
|
$o .= status_editor($a, $x, 0, true);
|
||||||
}
|
}
|
||||||
$sql_extra = Item::getPermissionsSQLByUserId($a->profile['profile_uid']);
|
$sql_extra = Item::getPermissionsSQLByUserId($a->profile['uid']);
|
||||||
|
|
||||||
if (local_user() && (local_user() == $a->profile['profile_uid'])) {
|
if (local_user() && (local_user() == $a->profile['uid'])) {
|
||||||
$condition = ['parent-uri' => $item_parent_uri, 'uid' => local_user(), 'unseen' => true];
|
$condition = ['parent-uri' => $item_parent_uri, 'uid' => local_user(), 'unseen' => true];
|
||||||
$unseen = Item::exists($condition);
|
$unseen = Item::exists($condition);
|
||||||
} else {
|
} else {
|
||||||
|
@ -299,7 +298,7 @@ function display_content(App $a, $update = false, $update_uid = 0)
|
||||||
|
|
||||||
$condition = ["`id` = ? AND `item`.`uid` IN (0, ?) " . $sql_extra, $item_id, $item_uid];
|
$condition = ["`id` = ? AND `item`.`uid` IN (0, ?) " . $sql_extra, $item_id, $item_uid];
|
||||||
$fields = ['parent-uri', 'body', 'title', 'author-name', 'author-avatar', 'plink', 'author-id', 'owner-id', 'contact-id'];
|
$fields = ['parent-uri', 'body', 'title', 'author-name', 'author-avatar', 'plink', 'author-id', 'owner-id', 'contact-id'];
|
||||||
$item = Item::selectFirstForUser($a->profile['profile_uid'], $fields, $condition);
|
$item = Item::selectFirstForUser($a->profile['uid'], $fields, $condition);
|
||||||
|
|
||||||
if (!DBA::isResult($item)) {
|
if (!DBA::isResult($item)) {
|
||||||
throw new HTTPException\NotFoundException(DI::l10n()->t('The requested item doesn\'t exist or has been deleted.'));
|
throw new HTTPException\NotFoundException(DI::l10n()->t('The requested item doesn\'t exist or has been deleted.'));
|
||||||
|
|
|
@ -1236,7 +1236,7 @@ function photos_content(App $a)
|
||||||
} else {
|
} else {
|
||||||
$tools['edit'] = ['photos/' . $a->data['user']['nickname'] . '/image/' . $datum . '/edit', DI::l10n()->t('Edit photo')];
|
$tools['edit'] = ['photos/' . $a->data['user']['nickname'] . '/image/' . $datum . '/edit', DI::l10n()->t('Edit photo')];
|
||||||
$tools['delete'] = ['photos/' . $a->data['user']['nickname'] . '/image/' . $datum . '/drop', DI::l10n()->t('Delete photo')];
|
$tools['delete'] = ['photos/' . $a->data['user']['nickname'] . '/image/' . $datum . '/drop', DI::l10n()->t('Delete photo')];
|
||||||
$tools['profile'] = ['profile_photo/use/'.$ph[0]['resource-id'], DI::l10n()->t('Use as profile photo')];
|
$tools['profile'] = ['settings/profile/photo/crop/' . $ph[0]['resource-id'], DI::l10n()->t('Use as profile photo')];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -1,324 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* @file mod/profile_photo.php
|
|
||||||
*/
|
|
||||||
|
|
||||||
use Friendica\App;
|
|
||||||
use Friendica\BaseModule;
|
|
||||||
use Friendica\Core\Renderer;
|
|
||||||
use Friendica\Core\Worker;
|
|
||||||
use Friendica\Database\DBA;
|
|
||||||
use Friendica\DI;
|
|
||||||
use Friendica\Model\Contact;
|
|
||||||
use Friendica\Model\Photo;
|
|
||||||
use Friendica\Model\Profile;
|
|
||||||
use Friendica\Object\Image;
|
|
||||||
use Friendica\Util\Strings;
|
|
||||||
|
|
||||||
function profile_photo_init(App $a)
|
|
||||||
{
|
|
||||||
if (!local_user()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Profile::load($a, $a->user['nickname']);
|
|
||||||
}
|
|
||||||
|
|
||||||
function profile_photo_post(App $a)
|
|
||||||
{
|
|
||||||
if (!local_user()) {
|
|
||||||
notice(DI::l10n()->t('Permission denied.') . EOL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseModule::checkFormSecurityTokenRedirectOnError('/profile_photo', 'profile_photo');
|
|
||||||
|
|
||||||
if (!empty($_POST['cropfinal']) && $_POST['cropfinal'] == 1) {
|
|
||||||
|
|
||||||
// unless proven otherwise
|
|
||||||
$is_default_profile = 1;
|
|
||||||
|
|
||||||
if ($_REQUEST['profile']) {
|
|
||||||
$r = q("select id, `is-default` from profile where id = %d and uid = %d limit 1", intval($_REQUEST['profile']),
|
|
||||||
intval(local_user())
|
|
||||||
);
|
|
||||||
|
|
||||||
if (DBA::isResult($r) && (!intval($r[0]['is-default']))) {
|
|
||||||
$is_default_profile = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// phase 2 - we have finished cropping
|
|
||||||
|
|
||||||
if ($a->argc != 2) {
|
|
||||||
notice(DI::l10n()->t('Image uploaded but image cropping failed.') . EOL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$image_id = $a->argv[1];
|
|
||||||
|
|
||||||
if (substr($image_id, -2, 1) == '-') {
|
|
||||||
$scale = substr($image_id, -1, 1);
|
|
||||||
$image_id = substr($image_id, 0, -2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$srcX = $_POST['xstart'];
|
|
||||||
$srcY = $_POST['ystart'];
|
|
||||||
$srcW = $_POST['xfinal'] - $srcX;
|
|
||||||
$srcH = $_POST['yfinal'] - $srcY;
|
|
||||||
|
|
||||||
$base_image = Photo::selectFirst([], ['resource-id' => $image_id, 'uid' => local_user(), 'scale' => $scale]);
|
|
||||||
|
|
||||||
$path = 'profile/' . $a->user['nickname'];
|
|
||||||
if (DBA::isResult($base_image)) {
|
|
||||||
|
|
||||||
$Image = Photo::getImageForPhoto($base_image);
|
|
||||||
if ($Image->isValid()) {
|
|
||||||
$Image->crop(300, $srcX, $srcY, $srcW, $srcH);
|
|
||||||
|
|
||||||
$r = Photo::store($Image, local_user(), 0, $base_image['resource-id'], $base_image['filename'],
|
|
||||||
DI::l10n()->t('Profile Photos'), 4, $is_default_profile);
|
|
||||||
|
|
||||||
if ($r === false) {
|
|
||||||
notice(DI::l10n()->t('Image size reduction [%s] failed.', "300") . EOL);
|
|
||||||
}
|
|
||||||
|
|
||||||
$Image->scaleDown(80);
|
|
||||||
|
|
||||||
$r = Photo::store($Image, local_user(), 0, $base_image['resource-id'], $base_image['filename'],
|
|
||||||
DI::l10n()->t('Profile Photos'), 5, $is_default_profile);
|
|
||||||
|
|
||||||
if ($r === false) {
|
|
||||||
notice(DI::l10n()->t('Image size reduction [%s] failed.', "80") . EOL);
|
|
||||||
}
|
|
||||||
|
|
||||||
$Image->scaleDown(48);
|
|
||||||
|
|
||||||
$r = Photo::store($Image, local_user(), 0, $base_image['resource-id'], $base_image['filename'],
|
|
||||||
DI::l10n()->t('Profile Photos'), 6, $is_default_profile);
|
|
||||||
|
|
||||||
if ($r === false) {
|
|
||||||
notice(DI::l10n()->t('Image size reduction [%s] failed.', "48") . EOL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If setting for the default profile, unset the profile photo flag from any other photos I own
|
|
||||||
|
|
||||||
if ($is_default_profile) {
|
|
||||||
q("UPDATE `photo` SET `profile` = 0 WHERE `profile` = 1 AND `resource-id` != '%s' AND `uid` = %d",
|
|
||||||
DBA::escape($base_image['resource-id']), intval(local_user())
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d",
|
|
||||||
DBA::escape(DI::baseUrl() . '/photo/' . $base_image['resource-id'] . '-4.' . $Image->getExt()),
|
|
||||||
DBA::escape(DI::baseUrl() . '/photo/' . $base_image['resource-id'] . '-5.' . $Image->getExt()),
|
|
||||||
intval($_REQUEST['profile']), intval(local_user())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Contact::updateSelfFromUserID(local_user(), true);
|
|
||||||
|
|
||||||
info(DI::l10n()->t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL);
|
|
||||||
// Update global directory in background
|
|
||||||
if ($path && strlen(DI::config()->get('system', 'directory'))) {
|
|
||||||
Worker::add(PRIORITY_LOW, "Directory", DI::baseUrl()->get() . '/' . $path);
|
|
||||||
}
|
|
||||||
|
|
||||||
Worker::add(PRIORITY_LOW, 'ProfileUpdate', local_user());
|
|
||||||
} else {
|
|
||||||
notice(DI::l10n()->t('Unable to process image') . EOL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DI::baseUrl()->redirect($path);
|
|
||||||
return; // NOTREACHED
|
|
||||||
}
|
|
||||||
|
|
||||||
$src = $_FILES['userfile']['tmp_name'];
|
|
||||||
$filename = basename($_FILES['userfile']['name']);
|
|
||||||
$filesize = intval($_FILES['userfile']['size']);
|
|
||||||
$filetype = $_FILES['userfile']['type'];
|
|
||||||
if ($filetype == "") {
|
|
||||||
$filetype = Image::guessType($filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
$maximagesize = DI::config()->get('system', 'maximagesize');
|
|
||||||
|
|
||||||
if (($maximagesize) && ($filesize > $maximagesize)) {
|
|
||||||
notice(DI::l10n()->t('Image exceeds size limit of %s', Strings::formatBytes($maximagesize)) . EOL);
|
|
||||||
@unlink($src);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$imagedata = @file_get_contents($src);
|
|
||||||
$ph = new Image($imagedata, $filetype);
|
|
||||||
|
|
||||||
if (!$ph->isValid()) {
|
|
||||||
notice(DI::l10n()->t('Unable to process image.') . EOL);
|
|
||||||
@unlink($src);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$ph->orient($src);
|
|
||||||
@unlink($src);
|
|
||||||
|
|
||||||
$imagecrop = profile_photo_crop_ui_head($ph);
|
|
||||||
DI::baseUrl()->redirect('profile_photo/use/' . $imagecrop['hash']);
|
|
||||||
}
|
|
||||||
|
|
||||||
function profile_photo_content(App $a)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!local_user()) {
|
|
||||||
notice(DI::l10n()->t('Permission denied.') . EOL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$newuser = false;
|
|
||||||
|
|
||||||
if ($a->argc == 2 && $a->argv[1] === 'new') {
|
|
||||||
$newuser = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$imagecrop = [];
|
|
||||||
|
|
||||||
if (isset($a->argv[1]) && $a->argv[1] == 'use' && $a->argc >= 3) {
|
|
||||||
// BaseModule::checkFormSecurityTokenRedirectOnError('/profile_photo', 'profile_photo');
|
|
||||||
|
|
||||||
$resource_id = $a->argv[2];
|
|
||||||
//die(":".local_user());
|
|
||||||
|
|
||||||
$r = Photo::selectToArray([], ["resource-id" => $resource_id, "uid" => local_user()], ["order" => ["scale" => false]]);
|
|
||||||
if (!DBA::isResult($r)) {
|
|
||||||
notice(DI::l10n()->t('Permission denied.') . EOL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$havescale = false;
|
|
||||||
foreach ($r as $rr) {
|
|
||||||
if ($rr['scale'] == 5) {
|
|
||||||
$havescale = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set an already uloaded photo as profile photo
|
|
||||||
// if photo is in 'Profile Photos', change it in db
|
|
||||||
if (($r[0]['album'] == DI::l10n()->t('Profile Photos')) && ($havescale)) {
|
|
||||||
q("UPDATE `photo` SET `profile`=0 WHERE `profile`=1 AND `uid`=%d", intval(local_user()));
|
|
||||||
|
|
||||||
q("UPDATE `photo` SET `profile`=1 WHERE `uid` = %d AND `resource-id` = '%s'", intval(local_user()),
|
|
||||||
DBA::escape($resource_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
Contact::updateSelfFromUserID(local_user(), true);
|
|
||||||
|
|
||||||
// Update global directory in background
|
|
||||||
$url = $_SESSION['my_url'];
|
|
||||||
if ($url && strlen(DI::config()->get('system', 'directory'))) {
|
|
||||||
Worker::add(PRIORITY_LOW, "Directory", $url);
|
|
||||||
}
|
|
||||||
|
|
||||||
DI::baseUrl()->redirect('profile/' . $a->user['nickname']);
|
|
||||||
return; // NOTREACHED
|
|
||||||
}
|
|
||||||
$ph = Photo::getImageForPhoto($r[0]);
|
|
||||||
|
|
||||||
$imagecrop = profile_photo_crop_ui_head($ph);
|
|
||||||
// go ahead as we have jus uploaded a new photo to crop
|
|
||||||
}
|
|
||||||
|
|
||||||
$profiles = q("select `id`,`profile-name` as `name`,`is-default` as `default` from profile where uid = %d",
|
|
||||||
intval(local_user())
|
|
||||||
);
|
|
||||||
|
|
||||||
if (empty($imagecrop)) {
|
|
||||||
$tpl = Renderer::getMarkupTemplate('profile_photo.tpl');
|
|
||||||
|
|
||||||
$o = Renderer::replaceMacros($tpl,
|
|
||||||
[
|
|
||||||
'$user' => $a->user['nickname'],
|
|
||||||
'$lbl_upfile' => DI::l10n()->t('Upload File:'),
|
|
||||||
'$lbl_profiles' => DI::l10n()->t('Select a profile:'),
|
|
||||||
'$title' => DI::l10n()->t('Upload Profile Photo'),
|
|
||||||
'$submit' => DI::l10n()->t('Upload'),
|
|
||||||
'$profiles' => $profiles,
|
|
||||||
'$form_security_token' => BaseModule::getFormSecurityToken("profile_photo"),
|
|
||||||
'$select' => sprintf('%s %s', DI::l10n()->t('or'),
|
|
||||||
($newuser) ? '<a href="' . DI::baseUrl() . '">' . DI::l10n()->t('skip this step') . '</a>' : '<a href="' . DI::baseUrl() . '/photos/' . $a->user['nickname'] . '">' . DI::l10n()->t('select a photo from your photo albums') . '</a>')
|
|
||||||
]);
|
|
||||||
|
|
||||||
return $o;
|
|
||||||
} else {
|
|
||||||
$filename = $imagecrop['hash'] . '-' . $imagecrop['resolution'] . '.' . $imagecrop['ext'];
|
|
||||||
$tpl = Renderer::getMarkupTemplate("cropbody.tpl");
|
|
||||||
$o = Renderer::replaceMacros($tpl,
|
|
||||||
[
|
|
||||||
'$filename' => $filename,
|
|
||||||
'$profile' => (isset($_REQUEST['profile']) ? intval($_REQUEST['profile']) : 0),
|
|
||||||
'$resource' => $imagecrop['hash'] . '-' . $imagecrop['resolution'],
|
|
||||||
'$image_url' => DI::baseUrl() . '/photo/' . $filename,
|
|
||||||
'$title' => DI::l10n()->t('Crop Image'),
|
|
||||||
'$desc' => DI::l10n()->t('Please adjust the image cropping for optimum viewing.'),
|
|
||||||
'$form_security_token' => BaseModule::getFormSecurityToken("profile_photo"),
|
|
||||||
'$done' => DI::l10n()->t('Done Editing')
|
|
||||||
]);
|
|
||||||
return $o;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function profile_photo_crop_ui_head(Image $image)
|
|
||||||
{
|
|
||||||
$max_length = DI::config()->get('system', 'max_image_length');
|
|
||||||
if (!$max_length) {
|
|
||||||
$max_length = MAX_IMAGE_LENGTH;
|
|
||||||
}
|
|
||||||
if ($max_length > 0) {
|
|
||||||
$image->scaleDown($max_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
$width = $image->getWidth();
|
|
||||||
$height = $image->getHeight();
|
|
||||||
|
|
||||||
if ($width < 175 || $height < 175) {
|
|
||||||
$image->scaleUp(300);
|
|
||||||
$width = $image->getWidth();
|
|
||||||
$height = $image->getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
$hash = Photo::newResource();
|
|
||||||
|
|
||||||
|
|
||||||
$smallest = 0;
|
|
||||||
$filename = '';
|
|
||||||
|
|
||||||
$r = Photo::store($image, local_user(), 0, $hash, $filename, DI::l10n()->t('Profile Photos'), 0);
|
|
||||||
|
|
||||||
if ($r) {
|
|
||||||
info(DI::l10n()->t('Image uploaded successfully.') . EOL);
|
|
||||||
} else {
|
|
||||||
notice(DI::l10n()->t('Image upload failed.') . EOL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($width > 640 || $height > 640) {
|
|
||||||
$image->scaleDown(640);
|
|
||||||
$r = Photo::store($image, local_user(), 0, $hash, $filename, DI::l10n()->t('Profile Photos'), 1);
|
|
||||||
|
|
||||||
if ($r === false) {
|
|
||||||
notice(DI::l10n()->t('Image size reduction [%s] failed.', "640") . EOL);
|
|
||||||
} else {
|
|
||||||
$smallest = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DI::page()['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate("crophead.tpl"), []);
|
|
||||||
|
|
||||||
$imagecrop = [
|
|
||||||
'hash' => $hash,
|
|
||||||
'resolution' => $smallest,
|
|
||||||
'ext' => $image->getExt(),
|
|
||||||
];
|
|
||||||
|
|
||||||
return $imagecrop;
|
|
||||||
}
|
|
|
@ -598,7 +598,7 @@ function profiles_content(App $a) {
|
||||||
'$region' => ['region', DI::l10n()->t('Region/State:'), $r[0]['region']],
|
'$region' => ['region', DI::l10n()->t('Region/State:'), $r[0]['region']],
|
||||||
'$postal_code' => ['postal_code', DI::l10n()->t('Postal/Zip Code:'), $r[0]['postal-code']],
|
'$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']],
|
'$country_name' => ['country_name', DI::l10n()->t('Country:'), $r[0]['country-name']],
|
||||||
'$age' => ((intval($r[0]['dob'])) ? '(' . DI::l10n()->t('Age: ') . Temporal::getAgeByTimezone($r[0]['dob'],$a->user['timezone'],$a->user['timezone']) . ')' : ''),
|
'$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'])),
|
'$gender' => DI::l10n()->t(ContactSelector::gender($r[0]['gender'])),
|
||||||
'$marital' => ['selector' => ContactSelector::maritalStatus($r[0]['marital']), 'value' => DI::l10n()->t($r[0]['marital'])],
|
'$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')],
|
'$with' => ['with', DI::l10n()->t("Who: \x28if applicable\x29"), strip_tags($r[0]['with']), DI::l10n()->t('Examples: cathy123, Cathy Williams, cathy@example.com')],
|
||||||
|
|
|
@ -373,7 +373,7 @@ class Authentication
|
||||||
if ($user_record['login_date'] <= DBA::NULL_DATETIME) {
|
if ($user_record['login_date'] <= DBA::NULL_DATETIME) {
|
||||||
info($this->l10n->t('Welcome %s', $user_record['username']));
|
info($this->l10n->t('Welcome %s', $user_record['username']));
|
||||||
info($this->l10n->t('Please upload a profile photo.'));
|
info($this->l10n->t('Please upload a profile photo.'));
|
||||||
$this->baseUrl->redirect('profile_photo/new');
|
$this->baseUrl->redirect('settings/profile/photo/new');
|
||||||
} else {
|
} else {
|
||||||
info($this->l10n->t("Welcome back %s", $user_record['username']));
|
info($this->l10n->t("Welcome back %s", $user_record['username']));
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,30 @@ abstract class BaseCollection extends \ArrayIterator
|
||||||
$this->totalCount = $totalCount ?? count($models);
|
$this->totalCount = $totalCount ?? count($models);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function offsetSet($offset, $value)
|
||||||
|
{
|
||||||
|
if (is_null($offset)) {
|
||||||
|
$this->totalCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::offsetSet($offset, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function offsetUnset($offset)
|
||||||
|
{
|
||||||
|
if ($this->offsetExists($offset)) {
|
||||||
|
$this->totalCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::offsetUnset($offset);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
|
@ -35,4 +59,42 @@ abstract class BaseCollection extends \ArrayIterator
|
||||||
{
|
{
|
||||||
return $this->totalCount;
|
return $this->totalCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the values from a single field in the collection
|
||||||
|
*
|
||||||
|
* @param string $column
|
||||||
|
* @param int|null $index_key
|
||||||
|
* @return array
|
||||||
|
* @see array_column()
|
||||||
|
*/
|
||||||
|
public function column($column, $index_key = null)
|
||||||
|
{
|
||||||
|
return array_column($this->getArrayCopy(), $column, $index_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a callback function on all elements in the collection and returns a new collection with the updated elements
|
||||||
|
*
|
||||||
|
* @param callable $callback
|
||||||
|
* @return BaseCollection
|
||||||
|
* @see array_map()
|
||||||
|
*/
|
||||||
|
public function map(callable $callback)
|
||||||
|
{
|
||||||
|
return new static(array_map($callback, $this->getArrayCopy()), $this->getTotalCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the collection based on a callback that returns a boolean whether the current item should be kept.
|
||||||
|
*
|
||||||
|
* @param callable|null $callback
|
||||||
|
* @param int $flag
|
||||||
|
* @return BaseCollection
|
||||||
|
* @see array_filter()
|
||||||
|
*/
|
||||||
|
public function filter(callable $callback = null, int $flag = 0)
|
||||||
|
{
|
||||||
|
return new static(array_filter($this->getArrayCopy(), $callback, $flag));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,13 @@ abstract class BaseModel
|
||||||
*/
|
*/
|
||||||
private $data = [];
|
private $data = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to limit/avoid updates if no data was changed.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $originalData = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Database $dba
|
* @param Database $dba
|
||||||
* @param LoggerInterface $logger
|
* @param LoggerInterface $logger
|
||||||
|
@ -38,6 +45,12 @@ abstract class BaseModel
|
||||||
$this->dba = $dba;
|
$this->dba = $dba;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
$this->data = $data;
|
$this->data = $data;
|
||||||
|
$this->originalData = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOriginalData()
|
||||||
|
{
|
||||||
|
return $this->originalData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,10 +64,23 @@ abstract class BaseModel
|
||||||
{
|
{
|
||||||
$model = clone $prototype;
|
$model = clone $prototype;
|
||||||
$model->data = $data;
|
$model->data = $data;
|
||||||
|
$model->originalData = $data;
|
||||||
|
|
||||||
return $model;
|
return $model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magic isset method. Returns true if the field exists, either in the data prperty array or in any of the local properties.
|
||||||
|
* Used by array_column() on an array of objects.
|
||||||
|
*
|
||||||
|
* @param $name
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function __isset($name)
|
||||||
|
{
|
||||||
|
return in_array($name, array_merge(array_keys($this->data), array_keys(get_object_vars($this))));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Magic getter. This allows to retrieve model fields with the following syntax:
|
* Magic getter. This allows to retrieve model fields with the following syntax:
|
||||||
* - $model->field (outside of class)
|
* - $model->field (outside of class)
|
||||||
|
@ -66,9 +92,7 @@ abstract class BaseModel
|
||||||
*/
|
*/
|
||||||
public function __get($name)
|
public function __get($name)
|
||||||
{
|
{
|
||||||
if (empty($this->data['id'])) {
|
$this->checkValid();
|
||||||
throw new HTTPException\InternalServerErrorException(static::class . ' record uninitialized');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!array_key_exists($name, $this->data)) {
|
if (!array_key_exists($name, $this->data)) {
|
||||||
throw new HTTPException\InternalServerErrorException('Field ' . $name . ' not found in ' . static::class);
|
throw new HTTPException\InternalServerErrorException('Field ' . $name . ' not found in ' . static::class);
|
||||||
|
@ -90,4 +114,11 @@ abstract class BaseModel
|
||||||
{
|
{
|
||||||
return $this->data;
|
return $this->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function checkValid()
|
||||||
|
{
|
||||||
|
if (empty($this->data['id'])) {
|
||||||
|
throw new HTTPException\InternalServerErrorException(static::class . ' record uninitialized');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,8 +61,7 @@ abstract class BaseModule
|
||||||
*/
|
*/
|
||||||
public static function post(array $parameters = [])
|
public static function post(array $parameters = [])
|
||||||
{
|
{
|
||||||
// $a = self::getApp();
|
// DI::baseurl()->redirect('module');
|
||||||
// $a->internalRedirect('module');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -122,7 +122,7 @@ abstract class BaseRepository extends BaseFactory
|
||||||
*/
|
*/
|
||||||
public function update(BaseModel $model)
|
public function update(BaseModel $model)
|
||||||
{
|
{
|
||||||
return $this->dba->update(static::$table_name, $model->toArray(), ['id' => $model->id], true);
|
return $this->dba->update(static::$table_name, $model->toArray(), ['id' => $model->id], $model->getOriginalData());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -136,10 +136,12 @@ abstract class BaseRepository extends BaseFactory
|
||||||
{
|
{
|
||||||
$return = $this->dba->insert(static::$table_name, $fields);
|
$return = $this->dba->insert(static::$table_name, $fields);
|
||||||
|
|
||||||
if ($return) {
|
if (!$return) {
|
||||||
|
throw new HTTPException\InternalServerErrorException('Unable to insert new row in table "' . static::$table_name . '"');
|
||||||
|
}
|
||||||
|
|
||||||
$fields['id'] = $this->dba->lastInsertId();
|
$fields['id'] = $this->dba->lastInsertId();
|
||||||
$return = $this->create($fields);
|
$return = $this->create($fields);
|
||||||
}
|
|
||||||
|
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
@ -197,4 +199,12 @@ abstract class BaseRepository extends BaseFactory
|
||||||
|
|
||||||
return $models;
|
return $models;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BaseCollection $collection
|
||||||
|
*/
|
||||||
|
public function saveCollection(BaseCollection $collection)
|
||||||
|
{
|
||||||
|
$collection->map([$this, 'update']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
10
src/Collection/PermissionSets.php
Normal file
10
src/Collection/PermissionSets.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Collection;
|
||||||
|
|
||||||
|
use Friendica\BaseCollection;
|
||||||
|
|
||||||
|
class PermissionSets extends BaseCollection
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -5,8 +5,8 @@
|
||||||
*/
|
*/
|
||||||
namespace Friendica\Content;
|
namespace Friendica\Content;
|
||||||
|
|
||||||
use Friendica\Core\Protocol;
|
|
||||||
use Friendica\Content\Text\HTML;
|
use Friendica\Content\Text\HTML;
|
||||||
|
use Friendica\Core\Protocol;
|
||||||
use Friendica\Core\Renderer;
|
use Friendica\Core\Renderer;
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
|
@ -152,8 +152,8 @@ class ForumManager
|
||||||
public static function profileAdvanced($uid)
|
public static function profileAdvanced($uid)
|
||||||
{
|
{
|
||||||
$profile = intval(Feature::isEnabled($uid, 'forumlist_profile'));
|
$profile = intval(Feature::isEnabled($uid, 'forumlist_profile'));
|
||||||
if (! $profile) {
|
if (!$profile) {
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$o = '';
|
$o = '';
|
||||||
|
@ -167,20 +167,16 @@ class ForumManager
|
||||||
$contacts = self::getList($uid, $lastitem, false, false);
|
$contacts = self::getList($uid, $lastitem, false, false);
|
||||||
|
|
||||||
$total_shown = 0;
|
$total_shown = 0;
|
||||||
$forumlist = '';
|
|
||||||
foreach ($contacts as $contact) {
|
foreach ($contacts as $contact) {
|
||||||
$forumlist .= HTML::micropro($contact, true, 'forumlist-profile-advanced');
|
$o .= HTML::micropro($contact, true, 'forumlist-profile-advanced');
|
||||||
$total_shown ++;
|
$total_shown++;
|
||||||
if ($total_shown == $show_total) {
|
if ($total_shown == $show_total) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($contacts) > 0) {
|
|
||||||
$o .= $forumlist;
|
|
||||||
return $o;
|
return $o;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* count unread forum items
|
* count unread forum items
|
||||||
|
|
|
@ -301,7 +301,7 @@ class Widget
|
||||||
{
|
{
|
||||||
$a = DI::app();
|
$a = DI::app();
|
||||||
|
|
||||||
$uid = intval($a->profile['profile_uid']);
|
$uid = intval($a->profile['uid']);
|
||||||
|
|
||||||
if (!Feature::isEnabled($uid, 'categories')) {
|
if (!Feature::isEnabled($uid, 'categories')) {
|
||||||
return '';
|
return '';
|
||||||
|
@ -418,7 +418,7 @@ class Widget
|
||||||
{
|
{
|
||||||
$a = DI::app();
|
$a = DI::app();
|
||||||
|
|
||||||
$uid = intval($a->profile['profile_uid']);
|
$uid = intval($a->profile['uid']);
|
||||||
|
|
||||||
if (!$uid || !$a->profile['url']) {
|
if (!$uid || !$a->profile['url']) {
|
||||||
return '';
|
return '';
|
||||||
|
|
|
@ -229,18 +229,33 @@ class ACL
|
||||||
* Returns the ACL list of contacts for a given user id
|
* Returns the ACL list of contacts for a given user id
|
||||||
*
|
*
|
||||||
* @param int $user_id
|
* @param int $user_id
|
||||||
|
* @param array $condition Additional contact lookup table conditions
|
||||||
* @return array
|
* @return array
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function getContactListByUserId(int $user_id)
|
public static function getContactListByUserId(int $user_id, array $condition = [])
|
||||||
{
|
{
|
||||||
$fields = ['id', 'name', 'addr', 'micro'];
|
$fields = ['id', 'name', 'addr', 'micro'];
|
||||||
$params = ['order' => ['name']];
|
$params = ['order' => ['name']];
|
||||||
$acl_contacts = Contact::selectToArray($fields,
|
$acl_contacts = Contact::selectToArray(
|
||||||
['uid' => $user_id, 'self' => false, 'blocked' => false, 'archive' => false, 'deleted' => false,
|
$fields,
|
||||||
'pending' => false, 'rel' => [Contact::FOLLOWER, Contact::FRIEND]], $params
|
array_merge([
|
||||||
|
'uid' => $user_id,
|
||||||
|
'self' => false,
|
||||||
|
'blocked' => false,
|
||||||
|
'archive' => false,
|
||||||
|
'deleted' => false,
|
||||||
|
'pending' => false,
|
||||||
|
'rel' => [Contact::FOLLOWER, Contact::FRIEND]
|
||||||
|
], $condition),
|
||||||
|
$params
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$acl_yourself = Contact::selectFirst($fields, ['uid' => $user_id, 'self' => true]);
|
||||||
|
$acl_yourself['name'] = DI::l10n()->t('Yourself');
|
||||||
|
|
||||||
|
$acl_contacts[] = $acl_yourself;
|
||||||
|
|
||||||
$acl_forums = Contact::selectToArray($fields,
|
$acl_forums = Contact::selectToArray($fields,
|
||||||
['uid' => $user_id, 'self' => false, 'blocked' => false, 'archive' => false, 'deleted' => false,
|
['uid' => $user_id, 'self' => false, 'blocked' => false, 'archive' => false, 'deleted' => false,
|
||||||
'pending' => false, 'contact-type' => Contact::TYPE_COMMUNITY], $params
|
'pending' => false, 'contact-type' => Contact::TYPE_COMMUNITY], $params
|
||||||
|
@ -306,15 +321,27 @@ class ACL
|
||||||
* 'deny_gid' => [],
|
* 'deny_gid' => [],
|
||||||
* 'hidewall' => true/false
|
* 'hidewall' => true/false
|
||||||
* ]
|
* ]
|
||||||
|
* @param array $condition
|
||||||
|
* @param string $form_prefix
|
||||||
* @return string
|
* @return string
|
||||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||||
*/
|
*/
|
||||||
public static function getFullSelectorHTML(Page $page, array $user = null, bool $for_federation = false, array $default_permissions = [])
|
public static function getFullSelectorHTML(
|
||||||
{
|
Page $page,
|
||||||
|
array $user = null,
|
||||||
|
bool $for_federation = false,
|
||||||
|
array $default_permissions = [],
|
||||||
|
array $condition = [],
|
||||||
|
$form_prefix = ''
|
||||||
|
) {
|
||||||
if (empty($user['uid'])) {
|
if (empty($user['uid'])) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static $input_group_id = 0;
|
||||||
|
|
||||||
|
$input_group_id++;
|
||||||
|
|
||||||
$page->registerFooterScript(Theme::getPathForFile('asset/typeahead.js/dist/typeahead.bundle.js'));
|
$page->registerFooterScript(Theme::getPathForFile('asset/typeahead.js/dist/typeahead.bundle.js'));
|
||||||
$page->registerFooterScript(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.js'));
|
$page->registerFooterScript(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.js'));
|
||||||
$page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css'));
|
$page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css'));
|
||||||
|
@ -373,12 +400,21 @@ class ACL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$acl_contacts = self::getContactListByUserId($user['uid']);
|
$acl_contacts = self::getContactListByUserId($user['uid'], $condition);
|
||||||
|
|
||||||
$acl_groups = self::getGroupListByUserId($user['uid']);
|
$acl_groups = self::getGroupListByUserId($user['uid']);
|
||||||
|
|
||||||
$acl_list = array_merge($acl_groups, $acl_contacts);
|
$acl_list = array_merge($acl_groups, $acl_contacts);
|
||||||
|
|
||||||
|
$input_names = [
|
||||||
|
'visibility' => $form_prefix ? $form_prefix . '[visibility]' : 'visibility',
|
||||||
|
'group_allow' => $form_prefix ? $form_prefix . '[group_allow]' : 'group_allow',
|
||||||
|
'contact_allow' => $form_prefix ? $form_prefix . '[contact_allow]' : 'contact_allow',
|
||||||
|
'group_deny' => $form_prefix ? $form_prefix . '[group_deny]' : 'group_deny',
|
||||||
|
'contact_deny' => $form_prefix ? $form_prefix . '[contact_deny]' : 'contact_deny',
|
||||||
|
'emailcc' => $form_prefix ? $form_prefix . '[emailcc]' : 'emailcc',
|
||||||
|
];
|
||||||
|
|
||||||
$tpl = Renderer::getMarkupTemplate('acl_selector.tpl');
|
$tpl = Renderer::getMarkupTemplate('acl_selector.tpl');
|
||||||
$o = Renderer::replaceMacros($tpl, [
|
$o = Renderer::replaceMacros($tpl, [
|
||||||
'$public_title' => DI::l10n()->t('Public'),
|
'$public_title' => DI::l10n()->t('Public'),
|
||||||
|
@ -402,6 +438,8 @@ class ACL
|
||||||
'$for_federation' => $for_federation,
|
'$for_federation' => $for_federation,
|
||||||
'$jotnets_fields' => $jotnets_fields,
|
'$jotnets_fields' => $jotnets_fields,
|
||||||
'$user_hidewall' => $default_permissions['hidewall'],
|
'$user_hidewall' => $default_permissions['hidewall'],
|
||||||
|
'$input_names' => $input_names,
|
||||||
|
'$input_group_id' => $input_group_id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $o;
|
return $o;
|
||||||
|
|
|
@ -61,7 +61,7 @@ class Session
|
||||||
$session = DI::session();
|
$session = DI::session();
|
||||||
|
|
||||||
if (empty($session->get('remote')[$uid])) {
|
if (empty($session->get('remote')[$uid])) {
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $session->get('remote')[$uid];
|
return $session->get('remote')[$uid];
|
||||||
|
|
|
@ -284,6 +284,14 @@ abstract class DI
|
||||||
return self::$dice->create(Repository\Introduction::class);
|
return self::$dice->create(Repository\Introduction::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Repository\PermissionSet
|
||||||
|
*/
|
||||||
|
public static function permissionSet()
|
||||||
|
{
|
||||||
|
return self::$dice->create(Repository\PermissionSet::class);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// "Protocol" namespace instances
|
// "Protocol" namespace instances
|
||||||
//
|
//
|
||||||
|
|
|
@ -1342,19 +1342,13 @@ class Database
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$do_update = (count($old_fields) == 0);
|
|
||||||
|
|
||||||
foreach ($old_fields AS $fieldname => $content) {
|
foreach ($old_fields AS $fieldname => $content) {
|
||||||
if (isset($fields[$fieldname])) {
|
if (isset($fields[$fieldname]) && !is_null($content) && ($fields[$fieldname] == $content)) {
|
||||||
if (($fields[$fieldname] == $content) && !is_null($content)) {
|
|
||||||
unset($fields[$fieldname]);
|
unset($fields[$fieldname]);
|
||||||
} else {
|
|
||||||
$do_update = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$do_update || (count($fields) == 0)) {
|
if (count($fields) == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,14 @@ use Friendica\DI;
|
||||||
use Friendica\Model\Contact;
|
use Friendica\Model\Contact;
|
||||||
use Friendica\Model\Item;
|
use Friendica\Model\Item;
|
||||||
use Friendica\Model\ItemURI;
|
use Friendica\Model\ItemURI;
|
||||||
use Friendica\Model\UserItem;
|
|
||||||
use Friendica\Model\PermissionSet;
|
use Friendica\Model\PermissionSet;
|
||||||
|
use Friendica\Model\UserItem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Post update functions
|
* These database-intensive post update routines are meant to be executed in the background by the cronjob.
|
||||||
|
*
|
||||||
|
* If there is a need for a intensive migration after a database structure change, update this file
|
||||||
|
* by adding a new method at the end with the number of the new DB_UPDATE_VERSION.
|
||||||
*/
|
*/
|
||||||
class PostUpdate
|
class PostUpdate
|
||||||
{
|
{
|
||||||
|
@ -204,13 +207,19 @@ class PostUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($item['psid'])) {
|
if (empty($item['psid'])) {
|
||||||
$item['psid'] = PermissionSet::fetchIDForPost($item);
|
$item['psid'] = PermissionSet::getIdFromACL(
|
||||||
} else {
|
$item['uid'],
|
||||||
|
$item['allow_cid'],
|
||||||
|
$item['allow_gid'],
|
||||||
|
$item['deny_cid'],
|
||||||
|
$item['deny_gid']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$item['allow_cid'] = null;
|
$item['allow_cid'] = null;
|
||||||
$item['allow_gid'] = null;
|
$item['allow_gid'] = null;
|
||||||
$item['deny_cid'] = null;
|
$item['deny_cid'] = null;
|
||||||
$item['deny_gid'] = null;
|
$item['deny_gid'] = null;
|
||||||
}
|
|
||||||
|
|
||||||
if ($item['post-type'] == 0) {
|
if ($item['post-type'] == 0) {
|
||||||
if (!empty($item['type']) && ($item['type'] == 'note')) {
|
if (!empty($item['type']) && ($item['type'] == 'note')) {
|
||||||
|
|
|
@ -117,6 +117,16 @@ class Group
|
||||||
}
|
}
|
||||||
DBA::close($stmt);
|
DBA::close($stmt);
|
||||||
|
|
||||||
|
// Meta-groups
|
||||||
|
$contact = Contact::getById($cid, ['rel']);
|
||||||
|
if ($contact['rel'] == Contact::FOLLOWER || $contact['rel'] == Contact::FRIEND) {
|
||||||
|
$return[] = self::FOLLOWERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($contact['rel'] == Contact::FRIEND) {
|
||||||
|
$return[] = self::MUTUALS;
|
||||||
|
}
|
||||||
|
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1856,7 +1856,18 @@ class Item
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates or assigns the permission set
|
// Creates or assigns the permission set
|
||||||
$item['psid'] = PermissionSet::fetchIDForPost($item);
|
$item['psid'] = PermissionSet::getIdFromACL(
|
||||||
|
$item['uid'],
|
||||||
|
$item['allow_cid'],
|
||||||
|
$item['allow_gid'],
|
||||||
|
$item['deny_cid'],
|
||||||
|
$item['deny_gid']
|
||||||
|
);
|
||||||
|
|
||||||
|
$item['allow_cid'] = null;
|
||||||
|
$item['allow_gid'] = null;
|
||||||
|
$item['deny_cid'] = null;
|
||||||
|
$item['deny_gid'] = null;
|
||||||
|
|
||||||
// We are doing this outside of the transaction to avoid timing problems
|
// We are doing this outside of the transaction to avoid timing problems
|
||||||
if (!self::insertActivity($item)) {
|
if (!self::insertActivity($item)) {
|
||||||
|
@ -2729,7 +2740,13 @@ class Item
|
||||||
|
|
||||||
$private = ($user['allow_cid'] || $user['allow_gid'] || $user['deny_cid'] || $user['deny_gid']) ? 1 : 0;
|
$private = ($user['allow_cid'] || $user['allow_gid'] || $user['deny_cid'] || $user['deny_gid']) ? 1 : 0;
|
||||||
|
|
||||||
$psid = PermissionSet::fetchIDForPost($user);
|
$psid = PermissionSet::getIdFromACL(
|
||||||
|
$user['uid'],
|
||||||
|
$user['allow_cid'],
|
||||||
|
$user['allow_gid'],
|
||||||
|
$user['deny_cid'],
|
||||||
|
$user['deny_gid']
|
||||||
|
);
|
||||||
|
|
||||||
$forum_mode = ($prvgroup ? 2 : 1);
|
$forum_mode = ($prvgroup ? 2 : 1);
|
||||||
|
|
||||||
|
|
|
@ -2,63 +2,38 @@
|
||||||
/**
|
/**
|
||||||
* @file src/Model/PermissionSet.php
|
* @file src/Model/PermissionSet.php
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Friendica\Model;
|
namespace Friendica\Model;
|
||||||
|
|
||||||
use Friendica\Database\DBA;
|
use Friendica\BaseModel;
|
||||||
|
use Friendica\DI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* functions for interacting with the permission set of an object (item, photo, event, ...)
|
* functions for interacting with the permission set of an object (item, photo, event, ...)
|
||||||
*/
|
*/
|
||||||
class PermissionSet
|
class PermissionSet extends BaseModel
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Fetch the id of a given permission set. Generate a new one when needed
|
* Fetch the id of a given permission set. Generate a new one when needed
|
||||||
*
|
*
|
||||||
* @param array $postarray The array from an item, picture or event post
|
* @param int $uid
|
||||||
|
* @param string|null $allow_cid Allowed contact IDs - empty = everyone
|
||||||
|
* @param string|null $allow_gid Allowed group IDs - empty = everyone
|
||||||
|
* @param string|null $deny_cid Disallowed contact IDs - empty = no one
|
||||||
|
* @param string|null $deny_gid Disallowed group IDs - empty = no one
|
||||||
* @return int id
|
* @return int id
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
|
* @deprecated since 2020.03, use Repository\PermissionSet instead
|
||||||
|
* @see \Friendica\Repository\PermissionSet->getIdFromACL
|
||||||
*/
|
*/
|
||||||
public static function fetchIDForPost(&$postarray)
|
public static function getIdFromACL(
|
||||||
{
|
int $uid,
|
||||||
$condition = ['uid' => $postarray['uid'],
|
string $allow_cid = null,
|
||||||
'allow_cid' => self::sortPermissions($postarray['allow_cid'] ?? ''),
|
string $allow_gid = null,
|
||||||
'allow_gid' => self::sortPermissions($postarray['allow_gid'] ?? ''),
|
string $deny_cid = null,
|
||||||
'deny_cid' => self::sortPermissions($postarray['deny_cid'] ?? ''),
|
string $deny_gid = null
|
||||||
'deny_gid' => self::sortPermissions($postarray['deny_gid'] ?? '')];
|
) {
|
||||||
|
return DI::permissionSet()->getIdFromACL($uid, $allow_cid, $allow_gid, $deny_cid, $deny_gid);
|
||||||
$set = DBA::selectFirst('permissionset', ['id'], $condition);
|
|
||||||
|
|
||||||
if (!DBA::isResult($set)) {
|
|
||||||
DBA::insert('permissionset', $condition, true);
|
|
||||||
|
|
||||||
$set = DBA::selectFirst('permissionset', ['id'], $condition);
|
|
||||||
}
|
|
||||||
|
|
||||||
$postarray['allow_cid'] = null;
|
|
||||||
$postarray['allow_gid'] = null;
|
|
||||||
$postarray['deny_cid'] = null;
|
|
||||||
$postarray['deny_gid'] = null;
|
|
||||||
|
|
||||||
return $set['id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function sortPermissions($permissionlist)
|
|
||||||
{
|
|
||||||
$cleaned_list = trim($permissionlist, '<>');
|
|
||||||
|
|
||||||
if (empty($cleaned_list)) {
|
|
||||||
return $permissionlist;
|
|
||||||
}
|
|
||||||
|
|
||||||
$elements = explode('><', $cleaned_list);
|
|
||||||
|
|
||||||
if (count($elements) <= 1) {
|
|
||||||
return $permissionlist;
|
|
||||||
}
|
|
||||||
|
|
||||||
asort($elements);
|
|
||||||
|
|
||||||
return '<' . implode('><', $elements) . '>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -69,36 +44,13 @@ class PermissionSet
|
||||||
*
|
*
|
||||||
* @return array of permission set ids.
|
* @return array of permission set ids.
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
|
* @deprecated since 2020.03, use Repository\PermissionSet instead
|
||||||
|
* @see \Friendica\Repository\PermissionSet->selectByContactId
|
||||||
*/
|
*/
|
||||||
static public function get($uid, $contact_id)
|
public static function get($uid, $contact_id)
|
||||||
{
|
{
|
||||||
if (DBA::exists('contact', ['id' => $contact_id, 'uid' => $uid, 'blocked' => false])) {
|
$permissionSets = DI::permissionSet()->selectByContactId($contact_id, $uid);
|
||||||
$groups = Group::getIdsByContactId($contact_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($groups) || !is_array($groups)) {
|
return $permissionSets->column('id');
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$group_str = '<<>>'; // should be impossible to match
|
|
||||||
|
|
||||||
foreach ($groups as $g) {
|
|
||||||
$group_str .= '|<' . intval($g) . '>';
|
|
||||||
}
|
|
||||||
|
|
||||||
$contact_str = '<' . $contact_id . '>';
|
|
||||||
|
|
||||||
$condition = ["`uid` = ? AND (NOT (`deny_cid` REGEXP ? OR deny_gid REGEXP ?)
|
|
||||||
AND (allow_cid REGEXP ? OR allow_gid REGEXP ? OR (allow_cid = '' AND allow_gid = '')))",
|
|
||||||
$uid, $contact_str, $group_str, $contact_str, $group_str];
|
|
||||||
|
|
||||||
$ret = DBA::select('permissionset', ['id'], $condition);
|
|
||||||
$set = [];
|
|
||||||
while ($permission = DBA::fetch($ret)) {
|
|
||||||
$set[] = $permission['id'];
|
|
||||||
}
|
|
||||||
DBA::close($ret);
|
|
||||||
|
|
||||||
return $set;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,13 +126,13 @@ class Profile
|
||||||
*
|
*
|
||||||
* @param App $a
|
* @param App $a
|
||||||
* @param string $nickname string
|
* @param string $nickname string
|
||||||
* @param int $profile int
|
* @param int $profile_id int
|
||||||
* @param array $profiledata array
|
* @param array $profiledata array
|
||||||
* @param boolean $show_connect Show connect link
|
* @param boolean $show_connect Show connect link
|
||||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||||
* @throws \ImagickException
|
* @throws \ImagickException
|
||||||
*/
|
*/
|
||||||
public static function load(App $a, $nickname, $profile = 0, array $profiledata = [], $show_connect = true)
|
public static function load(App $a, $nickname, $profile_id = 0, array $profiledata = [], $show_connect = true)
|
||||||
{
|
{
|
||||||
$user = DBA::selectFirst('user', ['uid'], ['nickname' => $nickname, 'account_removed' => false]);
|
$user = DBA::selectFirst('user', ['uid'], ['nickname' => $nickname, 'account_removed' => false]);
|
||||||
|
|
||||||
|
@ -155,31 +155,31 @@ class Profile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$pdata = self::getByNickname($nickname, $user['uid'], $profile);
|
$profile = self::getByNickname($nickname, $user['uid'], $profile_id);
|
||||||
|
|
||||||
if (empty($pdata) && empty($profiledata)) {
|
if (empty($profile) && empty($profiledata)) {
|
||||||
Logger::log('profile error: ' . DI::args()->getQueryString(), Logger::DEBUG);
|
Logger::log('profile error: ' . DI::args()->getQueryString(), Logger::DEBUG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($pdata)) {
|
if (empty($profile)) {
|
||||||
$pdata = ['uid' => 0, 'profile_uid' => 0, 'is-default' => false,'name' => $nickname];
|
$profile = ['uid' => 0, 'is-default' => false,'name' => $nickname];
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch user tags if this isn't the default profile
|
// fetch user tags if this isn't the default profile
|
||||||
|
|
||||||
if (!$pdata['is-default']) {
|
if (!$profile['is-default']) {
|
||||||
$condition = ['uid' => $pdata['profile_uid'], 'is-default' => true];
|
$condition = ['uid' => $profile['uid'], 'is-default' => true];
|
||||||
$profile = DBA::selectFirst('profile', ['pub_keywords'], $condition);
|
$profile_id = DBA::selectFirst('profile', ['pub_keywords'], $condition);
|
||||||
if (DBA::isResult($profile)) {
|
if (DBA::isResult($profile_id)) {
|
||||||
$pdata['pub_keywords'] = $profile['pub_keywords'];
|
$profile['pub_keywords'] = $profile_id['pub_keywords'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$a->profile = $pdata;
|
$a->profile = $profile;
|
||||||
$a->profile_uid = $pdata['profile_uid'];
|
$a->profile_uid = $profile['uid'];
|
||||||
|
|
||||||
$a->profile['mobile-theme'] = DI::pConfig()->get($a->profile['profile_uid'], 'system', 'mobile_theme');
|
$a->profile['mobile-theme'] = DI::pConfig()->get($a->profile['uid'], 'system', 'mobile_theme');
|
||||||
$a->profile['network'] = Protocol::DFRN;
|
$a->profile['network'] = Protocol::DFRN;
|
||||||
|
|
||||||
DI::page()['title'] = $a->profile['name'] . ' @ ' . DI::config()->get('config', 'sitename');
|
DI::page()['title'] = $a->profile['name'] . ' @ ' . DI::config()->get('config', 'sitename');
|
||||||
|
@ -255,7 +255,7 @@ class Profile
|
||||||
$profile = DBA::fetchFirst(
|
$profile = DBA::fetchFirst(
|
||||||
"SELECT `contact`.`id` AS `contact_id`, `contact`.`photo` AS `contact_photo`,
|
"SELECT `contact`.`id` AS `contact_id`, `contact`.`photo` AS `contact_photo`,
|
||||||
`contact`.`thumb` AS `contact_thumb`, `contact`.`micro` AS `contact_micro`,
|
`contact`.`thumb` AS `contact_thumb`, `contact`.`micro` AS `contact_micro`,
|
||||||
`profile`.`uid` AS `profile_uid`, `profile`.*,
|
`profile`.*,
|
||||||
`contact`.`avatar-date` AS picdate, `contact`.`addr`, `contact`.`url`, `user`.*
|
`contact`.`avatar-date` AS picdate, `contact`.`addr`, `contact`.`url`, `user`.*
|
||||||
FROM `profile`
|
FROM `profile`
|
||||||
INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` AND `contact`.`self`
|
INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` AND `contact`.`self`
|
||||||
|
@ -269,7 +269,7 @@ class Profile
|
||||||
$profile = DBA::fetchFirst(
|
$profile = DBA::fetchFirst(
|
||||||
"SELECT `contact`.`id` AS `contact_id`, `contact`.`photo` as `contact_photo`,
|
"SELECT `contact`.`id` AS `contact_id`, `contact`.`photo` as `contact_photo`,
|
||||||
`contact`.`thumb` AS `contact_thumb`, `contact`.`micro` AS `contact_micro`,
|
`contact`.`thumb` AS `contact_thumb`, `contact`.`micro` AS `contact_micro`,
|
||||||
`profile`.`uid` AS `profile_uid`, `profile`.*,
|
`profile`.*,
|
||||||
`contact`.`avatar-date` AS picdate, `contact`.`addr`, `contact`.`url`, `user`.*
|
`contact`.`avatar-date` AS picdate, `contact`.`addr`, `contact`.`url`, `user`.*
|
||||||
FROM `profile`
|
FROM `profile`
|
||||||
INNER JOIN `contact` ON `contact`.`uid` = `profile`.`uid` AND `contact`.`self`
|
INNER JOIN `contact` ON `contact`.`uid` = `profile`.`uid` AND `contact`.`self`
|
||||||
|
@ -350,7 +350,7 @@ class Profile
|
||||||
|
|
||||||
$profile_is_dfrn = $profile['network'] == Protocol::DFRN;
|
$profile_is_dfrn = $profile['network'] == Protocol::DFRN;
|
||||||
$profile_is_native = in_array($profile['network'], Protocol::NATIVE_SUPPORT);
|
$profile_is_native = in_array($profile['network'], Protocol::NATIVE_SUPPORT);
|
||||||
$local_user_is_self = local_user() && local_user() == ($profile['profile_uid'] ?? 0);
|
$local_user_is_self = local_user() && local_user() == ($profile['uid'] ?? 0);
|
||||||
$visitor_is_authenticated = (bool)self::getMyURL();
|
$visitor_is_authenticated = (bool)self::getMyURL();
|
||||||
$visitor_is_following =
|
$visitor_is_following =
|
||||||
in_array($visitor_contact['rel'] ?? 0, [Contact::FOLLOWER, Contact::FRIEND])
|
in_array($visitor_contact['rel'] ?? 0, [Contact::FOLLOWER, Contact::FRIEND])
|
||||||
|
@ -527,7 +527,7 @@ class Profile
|
||||||
|
|
||||||
$p['url'] = Contact::magicLink(($p['url'] ?? '') ?: $profile_url);
|
$p['url'] = Contact::magicLink(($p['url'] ?? '') ?: $profile_url);
|
||||||
|
|
||||||
$tpl = Renderer::getMarkupTemplate('profile_vcard.tpl');
|
$tpl = Renderer::getMarkupTemplate('profile/vcard.tpl');
|
||||||
$o .= Renderer::replaceMacros($tpl, [
|
$o .= Renderer::replaceMacros($tpl, [
|
||||||
'$profile' => $p,
|
'$profile' => $p,
|
||||||
'$xmpp' => $xmpp,
|
'$xmpp' => $xmpp,
|
||||||
|
@ -747,8 +747,6 @@ class Profile
|
||||||
$uid = intval($a->profile['uid']);
|
$uid = intval($a->profile['uid']);
|
||||||
|
|
||||||
if ($a->profile['name']) {
|
if ($a->profile['name']) {
|
||||||
$tpl = Renderer::getMarkupTemplate('profile_advanced.tpl');
|
|
||||||
|
|
||||||
$profile = [];
|
$profile = [];
|
||||||
|
|
||||||
$profile['fullname'] = [DI::l10n()->t('Full Name:'), $a->profile['name']];
|
$profile['fullname'] = [DI::l10n()->t('Full Name:'), $a->profile['name']];
|
||||||
|
@ -776,9 +774,9 @@ class Profile
|
||||||
|
|
||||||
if (!empty($a->profile['dob'])
|
if (!empty($a->profile['dob'])
|
||||||
&& $a->profile['dob'] > DBA::NULL_DATE
|
&& $a->profile['dob'] > DBA::NULL_DATE
|
||||||
&& $age = Temporal::getAgeByTimezone($a->profile['dob'], $a->profile['timezone'], '')
|
&& $age = Temporal::getAgeByTimezone($a->profile['dob'], $a->profile['timezone'])
|
||||||
) {
|
) {
|
||||||
$profile['age'] = [DI::l10n()->t('Age:'), $age];
|
$profile['age'] = [DI::l10n()->t('Age: ') , DI::l10n()->tt('%d year old', '%d years old', $age)];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($a->profile['marital']) {
|
if ($a->profile['marital']) {
|
||||||
|
@ -875,6 +873,7 @@ class Profile
|
||||||
$profile['edit'] = [DI::baseUrl() . '/profiles/' . $a->profile['id'], DI::l10n()->t('Edit profile'), '', DI::l10n()->t('Edit profile')];
|
$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, [
|
return Renderer::replaceMacros($tpl, [
|
||||||
'$title' => DI::l10n()->t('Profile'),
|
'$title' => DI::l10n()->t('Profile'),
|
||||||
'$basic' => DI::l10n()->t('Basic'),
|
'$basic' => DI::l10n()->t('Basic'),
|
||||||
|
|
|
@ -82,8 +82,8 @@ class Profile extends BaseModule
|
||||||
|
|
||||||
$page['htmlhead'] .= "\n";
|
$page['htmlhead'] .= "\n";
|
||||||
|
|
||||||
$blocked = !local_user() && !Session::getRemoteContactID($a->profile['profile_uid']) && DI::config()->get('system', 'block_public');
|
$blocked = !local_user() && !Session::getRemoteContactID($a->profile['uid']) && DI::config()->get('system', 'block_public');
|
||||||
$userblock = !local_user() && !Session::getRemoteContactID($a->profile['profile_uid']) && $a->profile['hidewall'];
|
$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) {
|
if (!empty($a->profile['page-flags']) && $a->profile['page-flags'] == User::PAGE_FLAGS_COMMUNITY) {
|
||||||
$page['htmlhead'] .= '<meta name="friendica.community" content="true" />' . "\n";
|
$page['htmlhead'] .= '<meta name="friendica.community" content="true" />' . "\n";
|
||||||
|
@ -149,7 +149,7 @@ class Profile extends BaseModule
|
||||||
|
|
||||||
$hashtags = $_GET['tag'] ?? '';
|
$hashtags = $_GET['tag'] ?? '';
|
||||||
|
|
||||||
if (DI::config()->get('system', 'block_public') && !local_user() && !Session::getRemoteContactID($a->profile['profile_uid'])) {
|
if (DI::config()->get('system', 'block_public') && !local_user() && !Session::getRemoteContactID($a->profile['uid'])) {
|
||||||
return Login::form();
|
return Login::form();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,14 +157,14 @@ class Profile extends BaseModule
|
||||||
|
|
||||||
if ($update) {
|
if ($update) {
|
||||||
// Ensure we've got a profile owner if updating.
|
// Ensure we've got a profile owner if updating.
|
||||||
$a->profile['profile_uid'] = $update;
|
$a->profile['uid'] = $update;
|
||||||
} elseif ($a->profile['profile_uid'] == local_user()) {
|
} elseif ($a->profile['uid'] == local_user()) {
|
||||||
Nav::setSelected('home');
|
Nav::setSelected('home');
|
||||||
}
|
}
|
||||||
|
|
||||||
$remote_contact = Session::getRemoteContactID($a->profile['profile_uid']);
|
$remote_contact = Session::getRemoteContactID($a->profile['uid']);
|
||||||
$is_owner = local_user() == $a->profile['profile_uid'];
|
$is_owner = local_user() == $a->profile['uid'];
|
||||||
$last_updated_key = "profile:" . $a->profile['profile_uid'] . ":" . local_user() . ":" . $remote_contact;
|
$last_updated_key = "profile:" . $a->profile['uid'] . ":" . local_user() . ":" . $remote_contact;
|
||||||
|
|
||||||
if (!empty($a->profile['hidewall']) && !$is_owner && !$remote_contact) {
|
if (!empty($a->profile['hidewall']) && !$is_owner && !$remote_contact) {
|
||||||
notice(DI::l10n()->t('Access to this profile has been restricted.') . EOL);
|
notice(DI::l10n()->t('Access to this profile has been restricted.') . EOL);
|
||||||
|
@ -182,16 +182,16 @@ class Profile extends BaseModule
|
||||||
return $o;
|
return $o;
|
||||||
}
|
}
|
||||||
|
|
||||||
$o .= Widget::commonFriendsVisitor($a->profile['profile_uid']);
|
$o .= Widget::commonFriendsVisitor($a->profile['uid']);
|
||||||
|
|
||||||
$commpage = $a->profile['page-flags'] == User::PAGE_FLAGS_COMMUNITY;
|
$commpage = $a->profile['page-flags'] == User::PAGE_FLAGS_COMMUNITY;
|
||||||
$commvisitor = $commpage && $remote_contact;
|
$commvisitor = $commpage && $remote_contact;
|
||||||
|
|
||||||
DI::page()['aside'] .= Widget::postedByYear(DI::baseUrl()->get(true) . '/profile/' . $a->profile['nickname'], $a->profile['profile_uid'] ?? 0, true);
|
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::categories(DI::baseUrl()->get(true) . '/profile/' . $a->profile['nickname'], XML::escape($category));
|
||||||
DI::page()['aside'] .= Widget::tagCloud();
|
DI::page()['aside'] .= Widget::tagCloud();
|
||||||
|
|
||||||
if (Security::canWriteToUserWall($a->profile['profile_uid'])) {
|
if (Security::canWriteToUserWall($a->profile['uid'])) {
|
||||||
$x = [
|
$x = [
|
||||||
'is_owner' => $is_owner,
|
'is_owner' => $is_owner,
|
||||||
'allow_location' => ($is_owner || $commvisitor) && $a->profile['allow_location'],
|
'allow_location' => ($is_owner || $commvisitor) && $a->profile['allow_location'],
|
||||||
|
@ -206,7 +206,7 @@ class Profile extends BaseModule
|
||||||
'acl' => $is_owner ? ACL::getFullSelectorHTML(DI::page(), $a->user, true) : '',
|
'acl' => $is_owner ? ACL::getFullSelectorHTML(DI::page(), $a->user, true) : '',
|
||||||
'bang' => '',
|
'bang' => '',
|
||||||
'visitor' => $is_owner || $commvisitor ? 'block' : 'none',
|
'visitor' => $is_owner || $commvisitor ? 'block' : 'none',
|
||||||
'profile_uid' => $a->profile['profile_uid'],
|
'profile_uid' => $a->profile['uid'],
|
||||||
];
|
];
|
||||||
|
|
||||||
$o .= status_editor($a, $x);
|
$o .= status_editor($a, $x);
|
||||||
|
@ -214,7 +214,7 @@ class Profile extends BaseModule
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched his/her groups
|
// Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched his/her groups
|
||||||
$sql_extra = Item::getPermissionsSQLByUserId($a->profile['profile_uid']);
|
$sql_extra = Item::getPermissionsSQLByUserId($a->profile['uid']);
|
||||||
$sql_extra2 = '';
|
$sql_extra2 = '';
|
||||||
|
|
||||||
$last_updated_array = Session::get('last_updated', []);
|
$last_updated_array = Session::get('last_updated', []);
|
||||||
|
@ -246,7 +246,7 @@ class Profile extends BaseModule
|
||||||
$sql_extra4
|
$sql_extra4
|
||||||
$sql_extra
|
$sql_extra
|
||||||
ORDER BY `item`.`received` DESC",
|
ORDER BY `item`.`received` DESC",
|
||||||
$a->profile['profile_uid'],
|
$a->profile['uid'],
|
||||||
GRAVITY_ACTIVITY
|
GRAVITY_ACTIVITY
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -260,12 +260,12 @@ class Profile extends BaseModule
|
||||||
|
|
||||||
if (!empty($category)) {
|
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` ",
|
$sql_post_table = sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ",
|
||||||
DBA::escape(Strings::protectSprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($a->profile['profile_uid']));
|
DBA::escape(Strings::protectSprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($a->profile['uid']));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($hashtags)) {
|
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` ",
|
$sql_post_table .= sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ",
|
||||||
DBA::escape(Strings::protectSprintf($hashtags)), intval(TERM_OBJ_POST), intval(TERM_HASHTAG), intval($a->profile['profile_uid']));
|
DBA::escape(Strings::protectSprintf($hashtags)), intval(TERM_OBJ_POST), intval(TERM_HASHTAG), intval($a->profile['uid']));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($datequery)) {
|
if (!empty($datequery)) {
|
||||||
|
@ -277,7 +277,7 @@ class Profile extends BaseModule
|
||||||
|
|
||||||
// Does the profile page belong to a forum?
|
// Does the profile page belong to a forum?
|
||||||
// If not then we can improve the performance with an additional condition
|
// If not then we can improve the performance with an additional condition
|
||||||
$condition = ['uid' => $a->profile['profile_uid'], 'page-flags' => [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]];
|
$condition = ['uid' => $a->profile['uid'], 'page-flags' => [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]];
|
||||||
if (!DBA::exists('user', $condition)) {
|
if (!DBA::exists('user', $condition)) {
|
||||||
$sql_extra3 = sprintf(" AND `thread`.`contact-id` = %d ", intval(intval($a->profile['contact_id'])));
|
$sql_extra3 = sprintf(" AND `thread`.`contact-id` = %d ", intval(intval($a->profile['contact_id'])));
|
||||||
} else {
|
} else {
|
||||||
|
@ -321,7 +321,7 @@ class Profile extends BaseModule
|
||||||
$sql_extra2
|
$sql_extra2
|
||||||
ORDER BY `thread`.`received` DESC
|
ORDER BY `thread`.`received` DESC
|
||||||
$pager_sql",
|
$pager_sql",
|
||||||
$a->profile['profile_uid']
|
$a->profile['uid']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,13 +344,13 @@ class Profile extends BaseModule
|
||||||
|
|
||||||
$items = DBA::toArray($items_stmt);
|
$items = DBA::toArray($items_stmt);
|
||||||
|
|
||||||
if ($pager->getStart() == 0 && !empty($a->profile['profile_uid'])) {
|
if ($pager->getStart() == 0 && !empty($a->profile['uid'])) {
|
||||||
$pinned_items = Item::selectPinned($a->profile['profile_uid'], ['uri', 'pinned'], ['true' . $sql_extra]);
|
$pinned_items = Item::selectPinned($a->profile['uid'], ['uri', 'pinned'], ['true' . $sql_extra]);
|
||||||
$pinned = Item::inArray($pinned_items);
|
$pinned = Item::inArray($pinned_items);
|
||||||
$items = array_merge($items, $pinned);
|
$items = array_merge($items, $pinned);
|
||||||
}
|
}
|
||||||
|
|
||||||
$o .= conversation($a, $items, $pager, 'profile', $update, false, 'pinned_received', $a->profile['profile_uid']);
|
$o .= conversation($a, $items, $pager, 'profile', $update, false, 'pinned_received', $a->profile['uid']);
|
||||||
|
|
||||||
if (!$update) {
|
if (!$update) {
|
||||||
$o .= $pager->renderMinimal(count($items));
|
$o .= $pager->renderMinimal(count($items));
|
||||||
|
|
|
@ -40,7 +40,7 @@ class Contacts extends BaseModule
|
||||||
|
|
||||||
Profile::load($a, $nickname);
|
Profile::load($a, $nickname);
|
||||||
|
|
||||||
$is_owner = $a->profile['profile_uid'] == local_user();
|
$is_owner = $a->profile['uid'] == local_user();
|
||||||
|
|
||||||
// tabs
|
// tabs
|
||||||
$o = Profile::getTabs($a, 'contacts', $is_owner, $nickname);
|
$o = Profile::getTabs($a, 'contacts', $is_owner, $nickname);
|
||||||
|
|
|
@ -87,7 +87,7 @@ class Register extends BaseModule
|
||||||
if (DI::config()->get('system', 'publish_all')) {
|
if (DI::config()->get('system', 'publish_all')) {
|
||||||
$profile_publish = '<input type="hidden" name="profile_publish_reg" value="1" />';
|
$profile_publish = '<input type="hidden" name="profile_publish_reg" value="1" />';
|
||||||
} else {
|
} else {
|
||||||
$publish_tpl = Renderer::getMarkupTemplate('profile_publish.tpl');
|
$publish_tpl = Renderer::getMarkupTemplate('profile/publish.tpl');
|
||||||
$profile_publish = Renderer::replaceMacros($publish_tpl, [
|
$profile_publish = Renderer::replaceMacros($publish_tpl, [
|
||||||
'$instance' => 'reg',
|
'$instance' => 'reg',
|
||||||
'$pubdesc' => DI::l10n()->t('Include your profile in member directory?'),
|
'$pubdesc' => DI::l10n()->t('Include your profile in member directory?'),
|
||||||
|
|
203
src/Module/Settings/Profile/Photo/Crop.php
Normal file
203
src/Module/Settings/Profile/Photo/Crop.php
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Module\Settings\Profile\Photo;
|
||||||
|
|
||||||
|
use Friendica\Core\Renderer;
|
||||||
|
use Friendica\Core\Session;
|
||||||
|
use Friendica\Core\Worker;
|
||||||
|
use Friendica\Database\DBA;
|
||||||
|
use Friendica\DI;
|
||||||
|
use Friendica\Model\Contact;
|
||||||
|
use Friendica\Model\Photo;
|
||||||
|
use Friendica\Module\BaseSettingsModule;
|
||||||
|
use Friendica\Network\HTTPException;
|
||||||
|
|
||||||
|
class Crop extends BaseSettingsModule
|
||||||
|
{
|
||||||
|
public static function post(array $parameters = [])
|
||||||
|
{
|
||||||
|
if (!Session::isAuthenticated()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$photo_prefix = $parameters['guid'];
|
||||||
|
$resource_id = $photo_prefix;
|
||||||
|
$scale = 0;
|
||||||
|
if (substr($photo_prefix, -2, 1) == '-') {
|
||||||
|
list($resource_id, $scale) = explode('-', $photo_prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
self::checkFormSecurityTokenRedirectOnError('settings/profile/photo/crop/' . $photo_prefix, 'settings_profile_photo_crop');
|
||||||
|
|
||||||
|
$action = $_POST['action'] ?? 'crop';
|
||||||
|
|
||||||
|
// Image selection origin is top left
|
||||||
|
$selectionX = intval($_POST['xstart'] ?? 0);
|
||||||
|
$selectionY = intval($_POST['ystart'] ?? 0);
|
||||||
|
$selectionW = intval($_POST['width'] ?? 0);
|
||||||
|
$selectionH = intval($_POST['height'] ?? 0);
|
||||||
|
|
||||||
|
$path = 'profile/' . DI::app()->user['nickname'];
|
||||||
|
|
||||||
|
$base_image = Photo::selectFirst([], ['resource-id' => $resource_id, 'uid' => local_user(), 'scale' => $scale]);
|
||||||
|
if (DBA::isResult($base_image)) {
|
||||||
|
$Image = Photo::getImageForPhoto($base_image);
|
||||||
|
if ($Image->isValid()) {
|
||||||
|
// If setting for the default profile, unset the profile photo flag from any other photos I own
|
||||||
|
DBA::update('photo', ['profile' => 0], ['uid' => local_user()]);
|
||||||
|
|
||||||
|
// Normalizing expected square crop parameters
|
||||||
|
$selectionW = $selectionH = min($selectionW, $selectionH);
|
||||||
|
|
||||||
|
$imageIsSquare = $Image->getWidth() === $Image->getHeight();
|
||||||
|
$selectionIsFullImage = $selectionX === 0 && $selectionY === 0 && $selectionW === $Image->getWidth() && $selectionH === $Image->getHeight();
|
||||||
|
|
||||||
|
// Bypassed UI with a rectangle image, we force a square cropped image
|
||||||
|
if (!$imageIsSquare && $action == 'skip') {
|
||||||
|
$selectionX = $selectionY = 0;
|
||||||
|
$selectionW = $selectionH = min($Image->getWidth(), $Image->getHeight());
|
||||||
|
$action = 'crop';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Selective crop if it was asked and the selection isn't the full image
|
||||||
|
if ($action == 'crop'
|
||||||
|
&& !($imageIsSquare && !$selectionIsFullImage)
|
||||||
|
) {
|
||||||
|
$Image->crop(300, $selectionX, $selectionY, $selectionW, $selectionH);
|
||||||
|
$resource_id = Photo::newResource();
|
||||||
|
} else {
|
||||||
|
$Image->scaleDown(300);
|
||||||
|
}
|
||||||
|
|
||||||
|
$r = Photo::store(
|
||||||
|
$Image,
|
||||||
|
local_user(),
|
||||||
|
0,
|
||||||
|
$resource_id,
|
||||||
|
$base_image['filename'],
|
||||||
|
DI::l10n()->t('Profile Photos'),
|
||||||
|
4,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
if ($r === false) {
|
||||||
|
notice(DI::l10n()->t('Image size reduction [%s] failed.', '300'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$Image->scaleDown(80);
|
||||||
|
|
||||||
|
$r = Photo::store(
|
||||||
|
$Image,
|
||||||
|
local_user(),
|
||||||
|
0,
|
||||||
|
$resource_id,
|
||||||
|
$base_image['filename'],
|
||||||
|
DI::l10n()->t('Profile Photos'),
|
||||||
|
5,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
if ($r === false) {
|
||||||
|
notice(DI::l10n()->t('Image size reduction [%s] failed.', '80'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$Image->scaleDown(48);
|
||||||
|
|
||||||
|
$r = Photo::store(
|
||||||
|
$Image,
|
||||||
|
local_user(),
|
||||||
|
0,
|
||||||
|
$resource_id,
|
||||||
|
$base_image['filename'],
|
||||||
|
DI::l10n()->t('Profile Photos'),
|
||||||
|
6,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
if ($r === false) {
|
||||||
|
notice(DI::l10n()->t('Image size reduction [%s] failed.', '48'));
|
||||||
|
}
|
||||||
|
|
||||||
|
Contact::updateSelfFromUserID(local_user(), true);
|
||||||
|
|
||||||
|
info(DI::l10n()->t('Shift-reload the page or clear browser cache if the new photo does not display immediately.'));
|
||||||
|
// Update global directory in background
|
||||||
|
if ($path && strlen(DI::config()->get('system', 'directory'))) {
|
||||||
|
Worker::add(PRIORITY_LOW, 'Directory', DI::baseUrl()->get() . '/' . $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Worker::add(PRIORITY_LOW, 'ProfileUpdate', local_user());
|
||||||
|
} else {
|
||||||
|
notice(DI::l10n()->t('Unable to process image'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DI::baseUrl()->redirect($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function content(array $parameters = [])
|
||||||
|
{
|
||||||
|
if (!Session::isAuthenticated()) {
|
||||||
|
throw new HTTPException\ForbiddenException(DI::l10n()->t('Permission denied.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::content();
|
||||||
|
|
||||||
|
$resource_id = $parameters['guid'];
|
||||||
|
|
||||||
|
$photos = Photo::selectToArray([], ['resource-id' => $resource_id, 'uid' => local_user()], ['order' => ['scale' => false]]);
|
||||||
|
if (!DBA::isResult($photos)) {
|
||||||
|
throw new HTTPException\NotFoundException(DI::l10n()->t('Photo not found.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$havescale = false;
|
||||||
|
$smallest = 0;
|
||||||
|
foreach ($photos as $photo) {
|
||||||
|
$smallest = $photo['scale'] == 1 ? 1 : $smallest;
|
||||||
|
$havescale = $havescale || $photo['scale'] == 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set an already uloaded photo as profile photo
|
||||||
|
// if photo is in 'Profile Photos', change it in db
|
||||||
|
if ($photos[0]['album'] == DI::l10n()->t('Profile Photos') && $havescale) {
|
||||||
|
Photo::update(['profile' => false], ['uid' => local_user()]);
|
||||||
|
|
||||||
|
Photo::update(['profile' => true], ['resource-id' => $resource_id, 'uid' => local_user()]);
|
||||||
|
|
||||||
|
Contact::updateSelfFromUserID(local_user(), true);
|
||||||
|
|
||||||
|
// 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'));
|
||||||
|
}
|
||||||
|
|
||||||
|
notice(DI::l10n()->t('Profile picture successfully updated.'));
|
||||||
|
|
||||||
|
DI::baseUrl()->redirect('profile/' . DI::app()->user['nickname']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$Image = Photo::getImageForPhoto($photos[0]);
|
||||||
|
|
||||||
|
$imagecrop = [
|
||||||
|
'resource-id' => $resource_id,
|
||||||
|
'scale' => $smallest,
|
||||||
|
'ext' => $Image->getExt(),
|
||||||
|
];
|
||||||
|
|
||||||
|
$isSquare = $Image->getWidth() === $Image->getHeight();
|
||||||
|
|
||||||
|
DI::page()['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('settings/profile/photo/crop_head.tpl'), []);
|
||||||
|
|
||||||
|
$filename = $imagecrop['resource-id'] . '-' . $imagecrop['scale'] . '.' . $imagecrop['ext'];
|
||||||
|
$tpl = Renderer::getMarkupTemplate('settings/profile/photo/crop.tpl');
|
||||||
|
$o = Renderer::replaceMacros($tpl, [
|
||||||
|
'$filename' => $filename,
|
||||||
|
'$resource' => $imagecrop['resource-id'] . '-' . $imagecrop['scale'],
|
||||||
|
'$image_url' => DI::baseUrl() . '/photo/' . $filename,
|
||||||
|
'$title' => DI::l10n()->t('Crop Image'),
|
||||||
|
'$desc' => DI::l10n()->t('Please adjust the image cropping for optimum viewing.'),
|
||||||
|
'$form_security_token' => self::getFormSecurityToken('settings_profile_photo_crop'),
|
||||||
|
'$skip' => $isSquare ? DI::l10n()->t('Use Image As Is') : '',
|
||||||
|
'$crop' => DI::l10n()->t('Crop Image'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $o;
|
||||||
|
}
|
||||||
|
}
|
128
src/Module/Settings/Profile/Photo/Index.php
Normal file
128
src/Module/Settings/Profile/Photo/Index.php
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Module\Settings\Profile\Photo;
|
||||||
|
|
||||||
|
use Friendica\App\Arguments;
|
||||||
|
use Friendica\Core\Renderer;
|
||||||
|
use Friendica\Core\Session;
|
||||||
|
use Friendica\DI;
|
||||||
|
use Friendica\Model\Contact;
|
||||||
|
use Friendica\Model\Photo;
|
||||||
|
use Friendica\Module\BaseSettingsModule;
|
||||||
|
use Friendica\Network\HTTPException;
|
||||||
|
use Friendica\Object\Image;
|
||||||
|
use Friendica\Util\Images;
|
||||||
|
use Friendica\Util\Strings;
|
||||||
|
|
||||||
|
class Index extends BaseSettingsModule
|
||||||
|
{
|
||||||
|
public static function post(array $parameters = [])
|
||||||
|
{
|
||||||
|
if (!Session::isAuthenticated()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self::checkFormSecurityTokenRedirectOnError('/settings/profile/photo', 'settings_profile_photo');
|
||||||
|
|
||||||
|
if (empty($_FILES['userfile'])) {
|
||||||
|
notice(DI::l10n()->t('Missing uploaded image.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$src = $_FILES['userfile']['tmp_name'];
|
||||||
|
$filename = basename($_FILES['userfile']['name']);
|
||||||
|
$filesize = intval($_FILES['userfile']['size']);
|
||||||
|
$filetype = $_FILES['userfile']['type'];
|
||||||
|
if ($filetype == '') {
|
||||||
|
$filetype = Images::guessType($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
$maximagesize = DI::config()->get('system', 'maximagesize', 0);
|
||||||
|
|
||||||
|
if ($maximagesize && $filesize > $maximagesize) {
|
||||||
|
notice(DI::l10n()->t('Image exceeds size limit of %s', Strings::formatBytes($maximagesize)));
|
||||||
|
@unlink($src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$imagedata = @file_get_contents($src);
|
||||||
|
$Image = new Image($imagedata, $filetype);
|
||||||
|
|
||||||
|
if (!$Image->isValid()) {
|
||||||
|
notice(DI::l10n()->t('Unable to process image.'));
|
||||||
|
@unlink($src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$Image->orient($src);
|
||||||
|
@unlink($src);
|
||||||
|
|
||||||
|
$max_length = DI::config()->get('system', 'max_image_length', 0);
|
||||||
|
if ($max_length > 0) {
|
||||||
|
$Image->scaleDown($max_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
$width = $Image->getWidth();
|
||||||
|
$height = $Image->getHeight();
|
||||||
|
|
||||||
|
if ($width < 175 || $height < 175) {
|
||||||
|
$Image->scaleUp(300);
|
||||||
|
$width = $Image->getWidth();
|
||||||
|
$height = $Image->getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
$resource_id = Photo::newResource();
|
||||||
|
|
||||||
|
$filename = '';
|
||||||
|
|
||||||
|
if (Photo::store($Image, local_user(), 0, $resource_id, $filename, DI::l10n()->t('Profile Photos'), 0)) {
|
||||||
|
info(DI::l10n()->t('Image uploaded successfully.'));
|
||||||
|
} else {
|
||||||
|
notice(DI::l10n()->t('Image upload failed.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($width > 640 || $height > 640) {
|
||||||
|
$Image->scaleDown(640);
|
||||||
|
if (!Photo::store($Image, local_user(), 0, $resource_id, $filename, DI::l10n()->t('Profile Photos'), 1)) {
|
||||||
|
notice(DI::l10n()->t('Image size reduction [%s] failed.', '640'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DI::baseUrl()->redirect('settings/profile/photo/crop/' . $resource_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function content(array $parameters = [])
|
||||||
|
{
|
||||||
|
if (!Session::isAuthenticated()) {
|
||||||
|
throw new HTTPException\ForbiddenException(DI::l10n()->t('Permission denied.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::content();
|
||||||
|
|
||||||
|
$args = DI::args();
|
||||||
|
|
||||||
|
$newuser = $args->get($args->getArgc() - 1) === 'new';
|
||||||
|
|
||||||
|
$contact = Contact::selectFirst(['avatar'], ['uid' => local_user(), 'self' => true]);
|
||||||
|
|
||||||
|
$tpl = Renderer::getMarkupTemplate('settings/profile/photo/index.tpl');
|
||||||
|
$o = Renderer::replaceMacros($tpl, [
|
||||||
|
'$title' => DI::l10n()->t('Profile Picture Settings'),
|
||||||
|
'$current_picture' => DI::l10n()->t('Current Profile Picture'),
|
||||||
|
'$upload_picture' => DI::l10n()->t('Upload Profile Picture'),
|
||||||
|
'$lbl_upfile' => DI::l10n()->t('Upload Picture:'),
|
||||||
|
'$submit' => DI::l10n()->t('Upload'),
|
||||||
|
'$avatar' => $contact['avatar'],
|
||||||
|
'$form_security_token' => self::getFormSecurityToken('settings_profile_photo'),
|
||||||
|
'$select' => sprintf('%s %s',
|
||||||
|
DI::l10n()->t('or'),
|
||||||
|
($newuser) ?
|
||||||
|
'<a href="' . DI::baseUrl() . '">' . DI::l10n()->t('skip this step') . '</a>'
|
||||||
|
: '<a href="' . DI::baseUrl() . '/photos/' . DI::app()->user['nickname'] . '">'
|
||||||
|
. DI::l10n()->t('select a photo from your photo albums') . '</a>'
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $o;
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,7 +50,13 @@ class HTTPException
|
||||||
$message = $explanation[$e->getCode()] ?? '';
|
$message = $explanation[$e->getCode()] ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return ['$title' => $title, '$message' => $message, '$back' => DI::l10n()->t('Go back')];
|
$vars = ['$title' => $title, '$message' => $message, '$back' => DI::l10n()->t('Go back')];
|
||||||
|
|
||||||
|
if (is_site_admin()) {
|
||||||
|
$vars['$trace'] = $e->getTraceAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -61,7 +61,7 @@ class Thread
|
||||||
$this->writable = true;
|
$this->writable = true;
|
||||||
break;
|
break;
|
||||||
case 'profile':
|
case 'profile':
|
||||||
$this->profile_owner = $a->profile['profile_uid'];
|
$this->profile_owner = $a->profile['uid'];
|
||||||
$this->writable = Security::canWriteToUserWall($this->profile_owner);
|
$this->writable = Security::canWriteToUserWall($this->profile_owner);
|
||||||
break;
|
break;
|
||||||
case 'display':
|
case 'display':
|
||||||
|
|
154
src/Repository/PermissionSet.php
Normal file
154
src/Repository/PermissionSet.php
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Repository;
|
||||||
|
|
||||||
|
use Friendica\BaseModel;
|
||||||
|
use Friendica\BaseRepository;
|
||||||
|
use Friendica\Collection;
|
||||||
|
use Friendica\Core\L10n;
|
||||||
|
use Friendica\Database\DBA;
|
||||||
|
use Friendica\DI;
|
||||||
|
use Friendica\Model;
|
||||||
|
use Friendica\Model\Group;
|
||||||
|
use Friendica\Network\HTTPException;
|
||||||
|
|
||||||
|
class PermissionSet extends BaseRepository
|
||||||
|
{
|
||||||
|
protected static $table_name = 'permissionset';
|
||||||
|
|
||||||
|
protected static $model_class = Model\PermissionSet::class;
|
||||||
|
|
||||||
|
protected static $collection_class = Collection\PermissionSets::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
* @return Model\PermissionSet
|
||||||
|
*/
|
||||||
|
protected function create(array $data)
|
||||||
|
{
|
||||||
|
return new Model\PermissionSet($this->dba, $this->logger, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $condition
|
||||||
|
* @return Model\PermissionSet
|
||||||
|
* @throws \Friendica\Network\HTTPException\NotFoundException
|
||||||
|
*/
|
||||||
|
public function selectFirst(array $condition)
|
||||||
|
{
|
||||||
|
if (isset($condition['id']) && !$condition['id']) {
|
||||||
|
return $this->create([
|
||||||
|
'id' => 0,
|
||||||
|
'uid' => $condition['uid'] ?? 0,
|
||||||
|
'allow_cid' => '',
|
||||||
|
'allow_gid' => '',
|
||||||
|
'deny_cid' => '',
|
||||||
|
'deny_gid' => '',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::selectFirst($condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $condition
|
||||||
|
* @param array $params
|
||||||
|
* @return Collection\PermissionSets
|
||||||
|
* @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\PermissionSets
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the id of a given permission set. Generate a new one when needed
|
||||||
|
*
|
||||||
|
* @param int $uid
|
||||||
|
* @param string|null $allow_cid Allowed contact IDs - empty = everyone
|
||||||
|
* @param string|null $allow_gid Allowed group IDs - empty = everyone
|
||||||
|
* @param string|null $deny_cid Disallowed contact IDs - empty = no one
|
||||||
|
* @param string|null $deny_gid Disallowed group IDs - empty = no one
|
||||||
|
* @return int id
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function getIdFromACL(
|
||||||
|
int $uid,
|
||||||
|
string $allow_cid = null,
|
||||||
|
string $allow_gid = null,
|
||||||
|
string $deny_cid = null,
|
||||||
|
string $deny_gid = null
|
||||||
|
) {
|
||||||
|
$ACLFormatter = DI::aclFormatter();
|
||||||
|
|
||||||
|
$allow_cid = $ACLFormatter->sanitize($allow_cid);
|
||||||
|
$allow_gid = $ACLFormatter->sanitize($allow_gid);
|
||||||
|
$deny_cid = $ACLFormatter->sanitize($deny_cid);
|
||||||
|
$deny_gid = $ACLFormatter->sanitize($deny_gid);
|
||||||
|
|
||||||
|
// Public permission
|
||||||
|
if (!$allow_cid && !$allow_gid && !$deny_cid && !$deny_gid) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$condition = [
|
||||||
|
'uid' => $uid,
|
||||||
|
'allow_cid' => $allow_cid,
|
||||||
|
'allow_gid' => $allow_gid,
|
||||||
|
'deny_cid' => $deny_cid,
|
||||||
|
'deny_gid' => $deny_gid
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$permissionset = $this->selectFirst($condition);
|
||||||
|
} catch(HTTPException\NotFoundException $exception) {
|
||||||
|
$permissionset = $this->insert($condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $permissionset->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a permission set collection for a given contact
|
||||||
|
*
|
||||||
|
* @param integer $contact_id Contact id of the visitor
|
||||||
|
* @param integer $uid User id whom the items belong, used for ownership check.
|
||||||
|
*
|
||||||
|
* @return Collection\PermissionSets
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function selectByContactId($contact_id, $uid)
|
||||||
|
{
|
||||||
|
$groups = [];
|
||||||
|
if (DBA::exists('contact', ['id' => $contact_id, 'uid' => $uid, 'blocked' => false])) {
|
||||||
|
$groups = Group::getIdsByContactId($contact_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$group_str = '<<>>'; // should be impossible to match
|
||||||
|
foreach ($groups as $group_id) {
|
||||||
|
$group_str .= '|<' . preg_quote($group_id) . '>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$contact_str = '<' . $contact_id . '>';
|
||||||
|
|
||||||
|
$condition = ["`uid` = ? AND (NOT (`deny_cid` REGEXP ? OR deny_gid REGEXP ?)
|
||||||
|
AND (allow_cid REGEXP ? OR allow_gid REGEXP ? OR (allow_cid = '' AND allow_gid = '')))",
|
||||||
|
$uid, $contact_str, $group_str, $contact_str, $group_str];
|
||||||
|
|
||||||
|
return $this->select($condition);
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,30 +12,57 @@ final class ACLFormatter
|
||||||
/**
|
/**
|
||||||
* Turn user/group ACLs stored as angle bracketed text into arrays
|
* Turn user/group ACLs stored as angle bracketed text into arrays
|
||||||
*
|
*
|
||||||
* @param string|null $ids A angle-bracketed list of IDs
|
* @param string|null $acl_string A angle-bracketed list of IDs
|
||||||
*
|
*
|
||||||
* @return array The array based on the IDs (empty in case there is no list)
|
* @return array The array based on the IDs (empty in case there is no list)
|
||||||
*/
|
*/
|
||||||
public function expand(string $ids = null)
|
public function expand(string $acl_string = null)
|
||||||
{
|
{
|
||||||
// In case there is no ID list, return empty array (=> no ACL set)
|
// In case there is no ID list, return empty array (=> no ACL set)
|
||||||
if (!isset($ids)) {
|
if (!isset($acl_string)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// turn string array of angle-bracketed elements into numeric array
|
// turn string array of angle-bracketed elements into numeric array
|
||||||
// e.g. "<1><2><3>" => array(1,2,3);
|
// e.g. "<1><2><3>" => array(1,2,3);
|
||||||
preg_match_all('/<(' . Group::FOLLOWERS . '|'. Group::MUTUALS . '|[0-9]+)>/', $ids, $matches, PREG_PATTERN_ORDER);
|
preg_match_all('/<(' . Group::FOLLOWERS . '|'. Group::MUTUALS . '|[0-9]+)>/', $acl_string, $matches, PREG_PATTERN_ORDER);
|
||||||
|
|
||||||
return $matches[1];
|
return $matches[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes an arbitrary ACL string and sanitizes it for storage
|
||||||
|
*
|
||||||
|
* @param string|null $acl_string
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function sanitize(string $acl_string = null)
|
||||||
|
{
|
||||||
|
if (empty($acl_string)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$cleaned_list = trim($acl_string, '<>');
|
||||||
|
|
||||||
|
if (empty($cleaned_list)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$elements = explode('><', $cleaned_list);
|
||||||
|
|
||||||
|
sort($elements);
|
||||||
|
|
||||||
|
array_walk($elements, [$this, 'sanitizeItem']);
|
||||||
|
|
||||||
|
return implode('', $elements);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap ACL elements in angle brackets for storage
|
* Wrap ACL elements in angle brackets for storage
|
||||||
*
|
*
|
||||||
* @param string $item The item to sanitise
|
* @param string $item The item to sanitise
|
||||||
*/
|
*/
|
||||||
private function sanitize(string &$item) {
|
private function sanitizeItem(string &$item) {
|
||||||
// The item is an ACL int value
|
// The item is an ACL int value
|
||||||
if (intval($item)) {
|
if (intval($item)) {
|
||||||
$item = '<' . intval(Strings::escapeTags(trim($item))) . '>';
|
$item = '<' . intval(Strings::escapeTags(trim($item))) . '>';
|
||||||
|
@ -70,7 +97,7 @@ final class ACLFormatter
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($item)) {
|
if (is_array($item)) {
|
||||||
array_walk($item, [$this, 'sanitize']);
|
array_walk($item, [$this, 'sanitizeItem']);
|
||||||
$return = implode('', $item);
|
$return = implode('', $item);
|
||||||
}
|
}
|
||||||
return $return;
|
return $return;
|
||||||
|
|
|
@ -131,12 +131,15 @@ class Temporal
|
||||||
|
|
||||||
if ($dob < '0000-01-01') {
|
if ($dob < '0000-01-01') {
|
||||||
$value = '';
|
$value = '';
|
||||||
|
$age = 0;
|
||||||
|
} elseif ($dob < '0001-00-00') {
|
||||||
|
$value = substr($dob, 5);
|
||||||
|
$age = 0;
|
||||||
} else {
|
} else {
|
||||||
$value = DateTimeFormat::utc(($year > 1000) ? $dob : '1000-' . $month . '-' . $day, 'Y-m-d');
|
$value = DateTimeFormat::utc($dob, 'Y-m-d');
|
||||||
|
$age = self::getAgeByTimezone($value, $timezone);
|
||||||
}
|
}
|
||||||
|
|
||||||
$age = (intval($value) ? self::getAgeByTimezone($value, $timezone, $timezone) : "");
|
|
||||||
|
|
||||||
$tpl = Renderer::getMarkupTemplate("field_input.tpl");
|
$tpl = Renderer::getMarkupTemplate("field_input.tpl");
|
||||||
$o = Renderer::replaceMacros($tpl,
|
$o = Renderer::replaceMacros($tpl,
|
||||||
[
|
[
|
||||||
|
@ -144,7 +147,7 @@ class Temporal
|
||||||
'dob',
|
'dob',
|
||||||
DI::l10n()->t('Birthday:'),
|
DI::l10n()->t('Birthday:'),
|
||||||
$value,
|
$value,
|
||||||
intval($age) > 0 ? DI::l10n()->t('Age: ') . $age : "",
|
intval($age) > 0 ? DI::l10n()->t('Age: ') . DI::l10n()->tt('%d year old', '%d years old', $age) : '',
|
||||||
'',
|
'',
|
||||||
'placeholder="' . DI::l10n()->t('YYYY-MM-DD or MM-DD') . '"'
|
'placeholder="' . DI::l10n()->t('YYYY-MM-DD or MM-DD') . '"'
|
||||||
]
|
]
|
||||||
|
@ -339,48 +342,31 @@ class Temporal
|
||||||
/**
|
/**
|
||||||
* Returns timezone correct age in years.
|
* Returns timezone correct age in years.
|
||||||
*
|
*
|
||||||
* Returns the age in years, given a date of birth, the timezone of the person
|
* Returns the age in years, given a date of birth and the timezone of the person
|
||||||
* whose date of birth is provided, and the timezone of the person viewing the
|
* whose date of birth is provided.
|
||||||
* result.
|
|
||||||
*
|
|
||||||
* Why? Bear with me. Let's say I live in Mittagong, Australia, and my birthday
|
|
||||||
* is on New Year's. You live in San Bruno, California.
|
|
||||||
* When exactly are you going to see my age increase?
|
|
||||||
*
|
|
||||||
* A: 5:00 AM Dec 31 San Bruno time. That's precisely when I start celebrating
|
|
||||||
* and become a year older. If you wish me happy birthday on January 1
|
|
||||||
* (San Bruno time), you'll be a day late.
|
|
||||||
*
|
*
|
||||||
* @param string $dob Date of Birth
|
* @param string $dob Date of Birth
|
||||||
* @param string $owner_tz (optional) Timezone of the person of interest
|
* @param string $owner_tz (optional) Timezone of the person of interest
|
||||||
* @param string $viewer_tz (optional) Timezone of the person viewing
|
|
||||||
*
|
*
|
||||||
* @return int Age in years
|
* @return int Age in years
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function getAgeByTimezone($dob, $owner_tz = '', $viewer_tz = '')
|
public static function getAgeByTimezone($dob, $owner_tz = '')
|
||||||
{
|
{
|
||||||
if (!intval($dob)) {
|
if (!intval($dob)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$owner_tz) {
|
if (!$owner_tz) {
|
||||||
$owner_tz = date_default_timezone_get();
|
$owner_tz = date_default_timezone_get();
|
||||||
}
|
}
|
||||||
if (!$viewer_tz) {
|
|
||||||
$viewer_tz = date_default_timezone_get();
|
|
||||||
}
|
|
||||||
|
|
||||||
$birthdate = DateTimeFormat::convert($dob . ' 00:00:00+00:00', $owner_tz, 'UTC', 'Y-m-d');
|
$birthdate = new DateTime($dob . ' 00:00:00', new DateTimeZone($owner_tz));
|
||||||
list($year, $month, $day) = explode("-", $birthdate);
|
$currentDate = new DateTime('now', new DateTimeZone('UTC'));
|
||||||
$year_diff = DateTimeFormat::timezoneNow($viewer_tz, 'Y') - $year;
|
|
||||||
$curr_month = DateTimeFormat::timezoneNow($viewer_tz, 'm');
|
|
||||||
$curr_day = DateTimeFormat::timezoneNow($viewer_tz, 'd');
|
|
||||||
|
|
||||||
if (($curr_month < $month) || (($curr_month == $month) && ($curr_day < $day))) {
|
$interval = $birthdate->diff($currentDate);
|
||||||
$year_diff--;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $year_diff;
|
return $interval->format('%y');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -228,6 +228,10 @@ return [
|
||||||
'/verify' => [Module\Settings\TwoFactor\Verify::class, [R::GET, R::POST]],
|
'/verify' => [Module\Settings\TwoFactor\Verify::class, [R::GET, R::POST]],
|
||||||
],
|
],
|
||||||
'/delegation[/{action}/{user_id}]' => [Module\Settings\Delegation::class, [R::GET, R::POST]],
|
'/delegation[/{action}/{user_id}]' => [Module\Settings\Delegation::class, [R::GET, R::POST]],
|
||||||
|
'/profile' => [
|
||||||
|
'/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]],
|
||||||
|
],
|
||||||
'/userexport[/{action}]' => [Module\Settings\UserExport::class, [R::GET, R::POST]],
|
'/userexport[/{action}]' => [Module\Settings\UserExport::class, [R::GET, R::POST]],
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
10
update.php
10
update.php
|
@ -15,15 +15,15 @@ use Friendica\Util\DateTimeFormat;
|
||||||
use Friendica\Worker\Delivery;
|
use Friendica\Worker\Delivery;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* update.php - automatic post-databse structure change updates
|
||||||
*
|
*
|
||||||
* update.php - automatic system update
|
* These functions are responsible for doing critical post update changes to the data (not the structure) in the database.
|
||||||
*
|
|
||||||
* This function is responsible for doing post update changes to the data
|
|
||||||
* (not the structure) in the database.
|
|
||||||
*
|
*
|
||||||
* Database structure changes are done in static/dbstructure.config.php
|
* Database structure changes are done in static/dbstructure.config.php
|
||||||
*
|
*
|
||||||
* If there is a need for a post process to a structure change, update this file
|
* For non-critical database migrations, please add a method in the Database\PostUpdate class
|
||||||
|
*
|
||||||
|
* If there is a need for a post update to a structure change, update this file
|
||||||
* by adding a new function at the end with the number of the new DB_UPDATE_VERSION.
|
* by adding a new function at the end with the number of the new DB_UPDATE_VERSION.
|
||||||
*
|
*
|
||||||
* The numbered script in this file has to be exactly like the DB_UPDATE_VERSION
|
* The numbered script in this file has to be exactly like the DB_UPDATE_VERSION
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<div id="acl-wrapper">
|
<div id="acl-wrapper">
|
||||||
<div class="panel-group" id="visibility-accordion" role="tablist" aria-multiselectable="true">
|
<div class="panel-group" id="visibility-accordion-{{$input_group_id}}" role="tablist" aria-multiselectable="true">
|
||||||
<div class="panel panel-success">
|
<div class="panel panel-success">
|
||||||
<label class="panel-heading{{if $visibility != 'public'}} collapsed{{/if}}" id="visibility-public-heading" aria-expanded="{{if $visibility == 'public'}}true{{else}}false{{/if}}">
|
<label class="panel-heading{{if $visibility != 'public'}} collapsed{{/if}}" id="visibility-public-heading-{{$input_group_id}}" aria-expanded="{{if $visibility == 'public'}}true{{else}}false{{/if}}">
|
||||||
<input type="radio" name="visibility" id="visibility-public" value="public" tabindex="14" {{if $visibility == 'public'}}checked{{/if}}>
|
<input type="radio" name="{{$input_names.visibility}}" id="visibility-public-{{$input_group_id}}" value="public" tabindex="14" {{if $visibility == 'public'}}checked{{/if}}>
|
||||||
<i class="fa fa-globe"></i> {{$public_title}}
|
<i class="fa fa-globe"></i> {{$public_title}}
|
||||||
</label>
|
</label>
|
||||||
<fieldset id="visibility-public-panel" class="panel-collapse collapse{{if $visibility == 'public'}} in{{/if}}" role="tabpanel" aria-labelledby="visibility-public-heading" {{if $visibility != 'public'}}disabled{{/if}}>
|
<fieldset id="visibility-public-panel-{{$input_group_id}}" class="panel-collapse collapse{{if $visibility == 'public'}} in{{/if}}" role="tabpanel" aria-labelledby="visibility-public-heading-{{$input_group_id}}" {{if $visibility != 'public'}}disabled{{/if}}>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<p>{{$public_desc}}</p>
|
<p>{{$public_desc}}</p>
|
||||||
{{if $for_federation}}
|
{{if $for_federation}}
|
||||||
|
@ -39,26 +39,26 @@
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-info">
|
<div class="panel panel-info">
|
||||||
<label class="panel-heading{{if $visibility != 'custom'}} collapsed{{/if}}" id="visibility-custom-heading" aria-expanded="{{if $visibility == 'custom'}}true{{else}}false{{/if}}">
|
<label class="panel-heading{{if $visibility != 'custom'}} collapsed{{/if}}" id="visibility-custom-heading-{{$input_group_id}}" aria-expanded="{{if $visibility == 'custom'}}true{{else}}false{{/if}}">
|
||||||
<input type="radio" name="visibility" id="visibility-custom" value="custom" tabindex="15" {{if $visibility == 'custom'}}checked{{/if}}>
|
<input type="radio" name="{{$input_names.visibility}}" id="visibility-custom-{{$input_group_id}}" value="custom" tabindex="15" {{if $visibility == 'custom'}}checked{{/if}}>
|
||||||
<i class="fa fa-lock"></i> {{$custom_title}}
|
<i class="fa fa-lock"></i> {{$custom_title}}
|
||||||
</label>
|
</label>
|
||||||
<fieldset id="visibility-custom-panel" class="panel-collapse collapse{{if $visibility == 'custom'}} in{{/if}}" role="tabpanel" aria-labelledby="visibility-custom-heading" {{if $visibility != 'custom'}}disabled{{/if}}>
|
<fieldset id="visibility-custom-panel-{{$input_group_id}}" class="panel-collapse collapse{{if $visibility == 'custom'}} in{{/if}}" role="tabpanel" aria-labelledby="visibility-custom-heading-{{$input_group_id}}" {{if $visibility != 'custom'}}disabled{{/if}}>
|
||||||
<input type="hidden" name="group_allow" value="{{$group_allow}}"/>
|
<input type="hidden" name="{{$input_names.group_allow}}" value="{{$group_allow}}"/>
|
||||||
<input type="hidden" name="contact_allow" value="{{$contact_allow}}"/>
|
<input type="hidden" name="{{$input_names.contact_allow}}" value="{{$contact_allow}}"/>
|
||||||
<input type="hidden" name="group_deny" value="{{$group_deny}}"/>
|
<input type="hidden" name="{{$input_names.group_deny}}" value="{{$group_deny}}"/>
|
||||||
<input type="hidden" name="contact_deny" value="{{$contact_deny}}"/>
|
<input type="hidden" name="{{$input_names.contact_deny}}" value="{{$contact_deny}}"/>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<p>{{$custom_desc}}</p>
|
<p>{{$custom_desc}}</p>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="acl_allow">{{$allow_label}}</label>
|
<label for="acl_allow-{{$input_group_id}}">{{$allow_label}}</label>
|
||||||
<input type="text" class="form-control input-lg" id="acl_allow">
|
<input type="text" class="form-control input-lg" id="acl_allow-{{$input_group_id}}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="acl_deny">{{$deny_label}}</label>
|
<label for="acl_deny-{{$input_group_id}}">{{$deny_label}}</label>
|
||||||
<input type="text" class="form-control input-lg" id="acl_deny">
|
<input type="text" class="form-control input-lg" id="acl_deny-{{$input_group_id}}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
@ -68,29 +68,29 @@
|
||||||
|
|
||||||
{{if $for_federation}}
|
{{if $for_federation}}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="profile-jot-email" id="profile-jot-email-label">{{$emailcc}}</label>
|
<label for="profile-jot-email" id="profile-jot-email-label-{{$input_group_id}}">{{$emailcc}}</label>
|
||||||
<input type="text" name="emailcc" id="profile-jot-email" class="form-control" title="{{$emtitle}}" />
|
<input type="text" name="{{$input_names.emailcc}}" id="profile-jot-email-{{$input_group_id}}" class="form-control" title="{{$emtitle}}" />
|
||||||
</div>
|
</div>
|
||||||
<div id="profile-jot-email-end"></div>
|
<div id="profile-jot-email-end-{{$input_group_id}}"></div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function() {
|
$(function() {
|
||||||
let $acl_allow_input = $('#acl_allow');
|
let $acl_allow_input = $('#acl_allow-{{$input_group_id}}');
|
||||||
let $contact_allow_input = $('[name=contact_allow]');
|
let $contact_allow_input = $('[name="{{$input_names.contact_allow}}"]');
|
||||||
let $group_allow_input = $('[name=group_allow]');
|
let $group_allow_input = $('[name="{{$input_names.group_allow}}"]');
|
||||||
let $acl_deny_input = $('#acl_deny');
|
let $acl_deny_input = $('#acl_deny-{{$input_group_id}}');
|
||||||
let $contact_deny_input = $('[name=contact_deny]');
|
let $contact_deny_input = $('[name="{{$input_names.contact_deny}}"]');
|
||||||
let $group_deny_input = $('[name=group_deny]');
|
let $group_deny_input = $('[name="{{$input_names.group_deny}}"]');
|
||||||
let $visibility_public_panel = $('#visibility-public-panel');
|
let $visibility_public_panel = $('#visibility-public-panel-{{$input_group_id}}');
|
||||||
let $visibility_custom_panel = $('#visibility-custom-panel');
|
let $visibility_custom_panel = $('#visibility-custom-panel-{{$input_group_id}}');
|
||||||
let $visibility_public_radio = $('#visibility-public');
|
let $visibility_public_radio = $('#visibility-public-{{$input_group_id}}');
|
||||||
let $visibility_custom_radio = $('#visibility-custom');
|
let $visibility_custom_radio = $('#visibility-custom-{{$input_group_id}}');
|
||||||
|
|
||||||
// Frio specific
|
// Frio specific
|
||||||
if ($.fn.collapse) {
|
if ($.fn.collapse) {
|
||||||
$visibility_public_panel.collapse({parent: '#visibility-accordion', toggle: false});
|
$visibility_public_panel.collapse({parent: '#visibility-accordion-{{$input_group_id}}', toggle: false});
|
||||||
$visibility_custom_panel.collapse({parent: '#visibility-accordion', toggle: false});
|
$visibility_custom_panel.collapse({parent: '#visibility-accordion-{{$input_group_id}}', toggle: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
$visibility_public_radio.on('change', function (e) {
|
$visibility_public_radio.on('change', function (e) {
|
||||||
|
@ -101,13 +101,13 @@
|
||||||
$visibility_public_panel.prop('disabled', false);
|
$visibility_public_panel.prop('disabled', false);
|
||||||
$visibility_custom_panel.prop('disabled', true);
|
$visibility_custom_panel.prop('disabled', true);
|
||||||
|
|
||||||
$('.profile-jot-net input[type=checkbox]').each(function() {
|
$('#visibility-public-panel-{{$input_group_id}} .profile-jot-net input[type=checkbox]').each(function() {
|
||||||
// Restores checkbox state if it had been saved
|
// Restores checkbox state if it had been saved
|
||||||
if ($(this).attr('data-checked') !== undefined) {
|
if ($(this).attr('data-checked') !== undefined) {
|
||||||
$(this).prop('checked', $(this).attr('data-checked') === 'true');
|
$(this).prop('checked', $(this).attr('data-checked') === 'true');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$('.profile-jot-net input').attr('disabled', false);
|
$('#visibility-public-panel-{{$input_group_id}} .profile-jot-net input').attr('disabled', false);
|
||||||
});
|
});
|
||||||
|
|
||||||
$visibility_custom_radio.on('change', function(e) {
|
$visibility_custom_radio.on('change', function(e) {
|
||||||
|
@ -118,13 +118,13 @@
|
||||||
$visibility_public_panel.prop('disabled', true);
|
$visibility_public_panel.prop('disabled', true);
|
||||||
$visibility_custom_panel.prop('disabled', false);
|
$visibility_custom_panel.prop('disabled', false);
|
||||||
|
|
||||||
$('.profile-jot-net input[type=checkbox]').each(function() {
|
$('#visibility-public-panel-{{$input_group_id}} .profile-jot-net input[type=checkbox]').each(function() {
|
||||||
// Saves current checkbox state
|
// Saves current checkbox state
|
||||||
$(this)
|
$(this)
|
||||||
.attr('data-checked', $(this).prop('checked'))
|
.attr('data-checked', $(this).prop('checked'))
|
||||||
.prop('checked', false);
|
.prop('checked', false);
|
||||||
});
|
});
|
||||||
$('.profile-jot-net input').attr('disabled', 'disabled');
|
$('#visibility-public-panel-{{$input_group_id}} .profile-jot-net input').attr('disabled', 'disabled');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Custom visibility tags inputs
|
// Custom visibility tags inputs
|
||||||
|
@ -233,9 +233,11 @@
|
||||||
|
|
||||||
// Anti-duplicate callback + acl fields value generation
|
// Anti-duplicate callback + acl fields value generation
|
||||||
|
|
||||||
$acl_allow_input.on('itemAdded', function (event) {
|
$acl_allow_input.on('itemAdded itemRemoved', function (event) {
|
||||||
|
if (event.type === 'itemAdded') {
|
||||||
// Removes duplicate in the opposite acl box
|
// Removes duplicate in the opposite acl box
|
||||||
$acl_deny_input.tagsinput('remove', event.item);
|
$acl_deny_input.tagsinput('remove', event.item);
|
||||||
|
}
|
||||||
|
|
||||||
// Update the real acl field
|
// Update the real acl field
|
||||||
$group_allow_input.val('');
|
$group_allow_input.val('');
|
||||||
|
@ -249,9 +251,11 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$acl_deny_input.on('itemAdded', function (event) {
|
$acl_deny_input.on('itemAdded itemRemoved', function (event) {
|
||||||
|
if (event.type === 'itemAdded') {
|
||||||
// Removes duplicate in the opposite acl box
|
// Removes duplicate in the opposite acl box
|
||||||
$acl_allow_input.tagsinput('remove', event.item);
|
$acl_allow_input.tagsinput('remove', event.item);
|
||||||
|
}
|
||||||
|
|
||||||
// Update the real acl field
|
// Update the real acl field
|
||||||
$group_deny_input.val('');
|
$group_deny_input.val('');
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
<h1>{{$title}}</h1>
|
|
||||||
<p id="cropimage-desc">
|
|
||||||
{{$desc nofilter}}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div id="cropimage-wrapper">
|
|
||||||
<img src="{{$image_url}}" id="croppa" class="imgCrop" alt="{{$title}}" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="cropimage-preview-wrapper" >
|
|
||||||
<div id="previewWrap" class="crop-preview"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript" language="javascript">
|
|
||||||
|
|
||||||
var image = document.getElementById('croppa');
|
|
||||||
var cropper = new Cropper(image, {
|
|
||||||
aspectRatio: 1 / 1,
|
|
||||||
viewMode: 1,
|
|
||||||
preview: '#profile-photo-wrapper, .crop-preview',
|
|
||||||
crop: function(e) {
|
|
||||||
$( '#x1' ).val(e.detail.x);
|
|
||||||
$( '#y1' ).val(e.detail.y);
|
|
||||||
$( '#x2' ).val(e.detail.x + e.detail.width);
|
|
||||||
$( '#y2' ).val(e.detail.y + e.detail.height);
|
|
||||||
$( '#width' ).val(e.detail.scaleX);
|
|
||||||
$( '#height' ).val(e.detail.scaleY);
|
|
||||||
},
|
|
||||||
ready: function() {
|
|
||||||
// Add the "crop-preview" class to the preview element ("profile-photo-wrapper").
|
|
||||||
var cwrapper = document.getElementById("profile-photo-wrapper");
|
|
||||||
cwrapper.classList.add("crop-preview");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<form action="profile_photo/{{$resource}}" id="crop-image-form" method="post" />
|
|
||||||
<input type='hidden' name='form_security_token' value='{{$form_security_token}}'>
|
|
||||||
|
|
||||||
<input type='hidden' name='profile' value='{{$profile}}'>
|
|
||||||
<input type="hidden" name="cropfinal" value="1" />
|
|
||||||
<input type="hidden" name="xstart" id="x1" />
|
|
||||||
<input type="hidden" name="ystart" id="y1" />
|
|
||||||
<input type="hidden" name="xfinal" id="x2" />
|
|
||||||
<input type="hidden" name="yfinal" id="y2" />
|
|
||||||
<input type="hidden" name="height" id="height" />
|
|
||||||
<input type="hidden" name="width" id="width" />
|
|
||||||
|
|
||||||
<div id="crop-image-submit-wrapper" >
|
|
||||||
<input type="submit" name="submit" value="{{$done}}" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</form>
|
|
|
@ -2,5 +2,8 @@
|
||||||
<img class="hare" src="images/friendica-404_svg_flexy-o-hare.png"/>
|
<img class="hare" src="images/friendica-404_svg_flexy-o-hare.png"/>
|
||||||
<h1>{{$title}}</h1>
|
<h1>{{$title}}</h1>
|
||||||
<p>{{$message}}</p>
|
<p>{{$message}}</p>
|
||||||
|
{{if $trace}}
|
||||||
|
<pre>{{$trace nofilter}}</pre>
|
||||||
|
{{/if}}
|
||||||
<p><button type="button" onclick="window.history.back()" class="btn btn-primary">{{$back}}</button></p>
|
<p><button type="button" onclick="window.history.back()" class="btn btn-primary">{{$back}}</button></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>{{$title}}</h1>
|
<h1>{{$title}}</h1>
|
||||||
<p>{{$description nofilter}}</p>
|
<p>{{$message nofilter}}</p>
|
||||||
|
{{if $trace}}
|
||||||
|
<pre>{{$trace nofilter}}</pre>
|
||||||
|
{{/if}}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
|
|
||||||
<h1>{{$title}}</h1>
|
|
||||||
|
|
||||||
<form enctype="multipart/form-data" action="profile_photo" method="post">
|
|
||||||
<input type='hidden' name='form_security_token' value='{{$form_security_token}}'>
|
|
||||||
|
|
||||||
<div id="profile-photo-upload-wrapper">
|
|
||||||
<label id="profile-photo-upload-label" for="profile-photo-upload">{{$lbl_upfile}} </label>
|
|
||||||
<input name="userfile" type="file" id="profile-photo-upload" size="48" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label id="profile-photo-profiles-label" for="profile-photo-profiles">{{$lbl_profiles}} </label>
|
|
||||||
<select name="profile" id="profile-photo-profiles" />
|
|
||||||
{{foreach $profiles as $p}}
|
|
||||||
<option value="{{$p.id}}" {{if $p.default}}selected="selected"{{/if}}>{{$p.name}}</option>
|
|
||||||
{{/foreach}}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<div id="profile-photo-submit-wrapper">
|
|
||||||
<input type="submit" name="submit" id="profile-photo-submit" value="{{$submit}}">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div id="profile-photo-link-select-wrapper">
|
|
||||||
{{$select nofilter}}
|
|
||||||
</div>
|
|
55
view/templates/settings/profile/photo/crop.tpl
Normal file
55
view/templates/settings/profile/photo/crop.tpl
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<div class="generic-page-wrapper">
|
||||||
|
<h1>{{$title}}</h1>
|
||||||
|
<p id="cropimage-desc">
|
||||||
|
{{$desc nofilter}}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div id="cropimage-wrapper">
|
||||||
|
<p><img src="{{$image_url}}" id="croppa" class="imgCrop" alt="{{$title}}"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="cropimage-preview-wrapper" >
|
||||||
|
<div id="previewWrap" class="crop-preview"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="settings/profile/photo/crop/{{$resource}}" id="crop-image-form" method="post">
|
||||||
|
<input type="hidden" name="form_security_token" value="{{$form_security_token}}">
|
||||||
|
|
||||||
|
<input type="hidden" name="xstart" id="x1" />
|
||||||
|
<input type="hidden" name="ystart" id="y1" />
|
||||||
|
<input type="hidden" name="height" id="height" />
|
||||||
|
<input type="hidden" name="width" id="width" />
|
||||||
|
|
||||||
|
<div id="settings-profile-photo-crop-submit-wrapper" class="pull-right settings-submit-wrapper">
|
||||||
|
{{if $skip}}
|
||||||
|
<button type="submit" name="action" id="settings-profile-photo-crop-skip" class="btn" value="skip">{{$skip}}</button>
|
||||||
|
{{/if}}
|
||||||
|
<button type="submit" name="action" id="settings-profile-photo-crop-submit" class="btn btn-primary" value="crop">{{$crop}}</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clear"></div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script type="text/javascript" language="javascript">
|
||||||
|
|
||||||
|
var image = document.getElementById('croppa');
|
||||||
|
var cropper = new Cropper(image, {
|
||||||
|
aspectRatio: 1,
|
||||||
|
viewMode: 1,
|
||||||
|
preview: '#profile-photo-wrapper, .crop-preview',
|
||||||
|
crop: function(e) {
|
||||||
|
$('#x1').val(e.detail.x);
|
||||||
|
$('#y1').val(e.detail.y);
|
||||||
|
$('#width').val(e.detail.width);
|
||||||
|
$('#height').val(e.detail.height);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var skip_button = document.getElementById('settings-profile-photo-crop-skip');
|
||||||
|
|
||||||
|
skip_button.addEventListener('click', function() {
|
||||||
|
let image_data = cropper.getImageData();
|
||||||
|
cropper.setData({x: 0, y: 0, width: image_data.width, height: image_data.height});
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</div>
|
25
view/templates/settings/profile/photo/index.tpl
Normal file
25
view/templates/settings/profile/photo/index.tpl
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<div class="generic-page-wrapper">
|
||||||
|
<h1>{{$title}}</h1>
|
||||||
|
|
||||||
|
<h2>{{$current_picture}}</h2>
|
||||||
|
<p><img src="{{$avatar}}" alt="{{$current_picture}}"/></p>
|
||||||
|
<h2>{{$upload_picture}}</h2>
|
||||||
|
<form enctype="multipart/form-data" action="settings/profile/photo" method="post">
|
||||||
|
<input type="hidden" name="form_security_token" value="{{$form_security_token}}">
|
||||||
|
|
||||||
|
<div id="profile-photo-upload-wrapper" class="form-group field input">
|
||||||
|
<label id="profile-photo-upload-label" for="profile-photo-upload">{{$lbl_upfile}} </label>
|
||||||
|
<input class="form-control" name="userfile" type="file" id="profile-photo-upload" size="48">
|
||||||
|
<div class="clear"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="profile-photo-submit-wrapper" class="pull-right settings-submit-wrapper">
|
||||||
|
<button type="submit" name="submit" id="profile-photo-submit" class="btn btn-primary" value="{{$submit}}">{{$submit}}</button>
|
||||||
|
</div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p id="profile-photo-link-select-wrapper">
|
||||||
|
{{$select nofilter}}
|
||||||
|
</p>
|
||||||
|
</div>
|
|
@ -22,7 +22,7 @@
|
||||||
<h4>{{$profile nofilter}}</h4>
|
<h4>{{$profile nofilter}}</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a target="newmember" href="profile_photo">{{$profile_photo_link}}</a><br />
|
<a target="newmember" href="settings/profile/photo">{{$profile_photo_link}}</a><br />
|
||||||
{{$profile_photo_txt nofilter}}
|
{{$profile_photo_txt nofilter}}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|
|
@ -2288,7 +2288,7 @@ ul.dropdown-menu li:hover {
|
||||||
* PAGES
|
* PAGES
|
||||||
*********/
|
*********/
|
||||||
|
|
||||||
.generic-page-wrapper, .profile_photo-content-wrapper, .videos-content-wrapper,
|
.generic-page-wrapper, .videos-content-wrapper,
|
||||||
.suggest-content-wrapper, .common-content-wrapper, .help-content-wrapper,
|
.suggest-content-wrapper, .common-content-wrapper, .help-content-wrapper,
|
||||||
.allfriends-content-wrapper, .match-content-wrapper, .dirfind-content-wrapper,
|
.allfriends-content-wrapper, .match-content-wrapper, .dirfind-content-wrapper,
|
||||||
.delegation-content-wrapper, .notes-content-wrapper,
|
.delegation-content-wrapper, .notes-content-wrapper,
|
||||||
|
@ -2850,21 +2850,15 @@ ul li:hover .contact-wrapper .contact-action-link:hover {
|
||||||
#profile-listing-new-link-wrapper {
|
#profile-listing-new-link-wrapper {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
.panel-group-settings {
|
|
||||||
margin-left: -15px;
|
|
||||||
margin-right: -15px;
|
|
||||||
}
|
|
||||||
.panel-group-settings > .panel,
|
.panel-group-settings > .panel,
|
||||||
.panel-group-settings > form > .panel {
|
.panel-group-settings > form > .panel {
|
||||||
padding-left: 15px;
|
padding-left: 10px;
|
||||||
padding-right: 15px;
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
.profiles-content-wrapper #profile-photo-upload-section {
|
#profile-photo-upload-section {
|
||||||
display: none;
|
display: none;
|
||||||
margin-left: -15px;
|
padding: 10px;
|
||||||
margin-right: -15px;
|
|
||||||
margin-top: 15px;
|
|
||||||
padding: 15px;
|
|
||||||
}
|
}
|
||||||
#profile-photo-upload-close {
|
#profile-photo-upload-close {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
@ -3537,7 +3531,7 @@ section .profile-match-wrapper {
|
||||||
right: 10px;
|
right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.generic-page-wrapper, .profile_photo-content-wrapper, .videos-content-wrapper, .suggest-content-wrapper, .common-content-wrapper, .help-content-wrapper, .allfriends-content-wrapper, .match-content-wrapper, .dirfind-content-wrapper, .directory-content-wrapper, .delegation-content-wrapper, .notes-content-wrapper, .message-content-wrapper, .apps-content-wrapper, #adminpage, .delegate-content-wrapper, .uexport-content-wrapper, .dfrn_request-content-wrapper, .friendica-content-wrapper, .credits-content-wrapper, .nogroup-content-wrapper, .profperm-content-wrapper, .invite-content-wrapper, .tos-content-wrapper, .fsuggest-content-wrapper {
|
.generic-page-wrapper, .videos-content-wrapper, .suggest-content-wrapper, .common-content-wrapper, .help-content-wrapper, .allfriends-content-wrapper, .match-content-wrapper, .dirfind-content-wrapper, .directory-content-wrapper, .delegation-content-wrapper, .notes-content-wrapper, .message-content-wrapper, .apps-content-wrapper, #adminpage, .delegate-content-wrapper, .uexport-content-wrapper, .dfrn_request-content-wrapper, .friendica-content-wrapper, .credits-content-wrapper, .nogroup-content-wrapper, .profperm-content-wrapper, .invite-content-wrapper, .tos-content-wrapper, .fsuggest-content-wrapper {
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,21 +6,10 @@
|
||||||
<div class="action">
|
<div class="action">
|
||||||
<a class="icon s16 edit ttright" href="#" rel="#profiles-menu" title="{{$profile.edit.3}}"><span>{{$profile.edit.1}}</span></a>
|
<a class="icon s16 edit ttright" href="#" rel="#profiles-menu" title="{{$profile.edit.3}}"><span>{{$profile.edit.1}}</span></a>
|
||||||
<ul id="profiles-menu" class="menu-popup">
|
<ul id="profiles-menu" class="menu-popup">
|
||||||
{{if $profile.menu.entries}}
|
|
||||||
{{foreach $profile.menu.entries as $e}}
|
|
||||||
<li>
|
|
||||||
<a href="profiles/{{$e.id}}"><img src='{{$e.photo}}'>{{$e.profile_name}}</a>
|
|
||||||
</li>
|
|
||||||
{{/foreach}}
|
|
||||||
{{else}}
|
|
||||||
<li>
|
<li>
|
||||||
<a href="{{$profile.edit.0}}">{{$profile.edit.1}}</a>
|
<a href="{{$profile.edit.0}}">{{$profile.edit.1}}</a>
|
||||||
</li>
|
</li>
|
||||||
{{/if}}
|
<li><a href="settings/profile/photo" >{{$profile.menu.chg_photo}}</a></li>
|
||||||
<li><a href="profile_photo" >{{$profile.menu.chg_photo}}</a></li>
|
|
||||||
{{if $profile.menu.cr_new }}
|
|
||||||
<li><a href="profiles/new" id="profile-listing-new-link">{{$profile.menu.cr_new}}</a></li>
|
|
||||||
{{/if}}
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
|
@ -145,7 +145,7 @@ function vier_community_info()
|
||||||
|
|
||||||
$tpl = Renderer::getMarkupTemplate('ch_directory_item.tpl');
|
$tpl = Renderer::getMarkupTemplate('ch_directory_item.tpl');
|
||||||
|
|
||||||
$r = q("SELECT `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`
|
$r = q("SELECT `profile`.*, `user`.`nickname`
|
||||||
FROM `profile` LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
|
FROM `profile` LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
|
||||||
WHERE `is-default` = 1 $publish AND `user`.`blocked` = 0 $order LIMIT %d , %d ",
|
WHERE `is-default` = 1 $publish AND `user`.`blocked` = 0 $order LIMIT %d , %d ",
|
||||||
0,
|
0,
|
||||||
|
@ -157,7 +157,7 @@ function vier_community_info()
|
||||||
$aside['$lastusers_items'] = [];
|
$aside['$lastusers_items'] = [];
|
||||||
|
|
||||||
foreach ($r as $rr) {
|
foreach ($r as $rr) {
|
||||||
$profile_link = 'profile/' . ((strlen($rr['nickname'])) ? $rr['nickname'] : $rr['profile_uid']);
|
$profile_link = 'profile/' . ((strlen($rr['nickname'])) ? $rr['nickname'] : $rr['uid']);
|
||||||
$entry = Renderer::replaceMacros($tpl, [
|
$entry = Renderer::replaceMacros($tpl, [
|
||||||
'$id' => $rr['id'],
|
'$id' => $rr['id'],
|
||||||
'$profile_link' => $profile_link,
|
'$profile_link' => $profile_link,
|
||||||
|
|
Loading…
Reference in a new issue