From 54371e854e7b9996864ad7954ddbc3eb344181e1 Mon Sep 17 00:00:00 2001 From: Papa Dragon Date: Wed, 9 Sep 2020 23:23:38 +0200 Subject: [PATCH 01/12] Daily global cron job needs an executable script (added missing chmod a+x) --- .homeinstall/zotserver-setup.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.homeinstall/zotserver-setup.sh b/.homeinstall/zotserver-setup.sh index e5901939f..797ac354e 100755 --- a/.homeinstall/zotserver-setup.sh +++ b/.homeinstall/zotserver-setup.sh @@ -698,6 +698,8 @@ function configure_cron_daily { echo "#" >> /var/www/$zotcron echo "shutdown -r now" >> /var/www/$zotcron + chmod a+x /var/www/$zotcron + # If global cron job does not exist we add it to /etc/crontab if grep -q $zotcron /etc/crontab then From fa097272176a7506c5399b2b1a5f93f40eb17cda Mon Sep 17 00:00:00 2001 From: nobody Date: Wed, 9 Sep 2020 17:29:46 -0700 Subject: [PATCH 02/12] refactor site customisation --- Zotlabs/Lib/Libzot.php | 10 +- Zotlabs/Lib/System.php | 12 +- Zotlabs/Module/Admin/Cover_photo.php | 499 +++++++++++++++++++++++ Zotlabs/Module/Admin/Profile_photo.php | 534 +++++++++++++++++++++++++ Zotlabs/Module/Admin/Site.php | 15 - Zotlabs/Widget/Admin.php | 21 +- include/nav.php | 6 +- view/theme/redbasic/css/style.css | 7 +- view/tpl/admin_cropbody.tpl | 48 +++ view/tpl/admin_profile_photo.tpl | 195 +++++++++ view/tpl/admin_site.tpl | 1 - view/tpl/navbar_default.tpl | 2 +- 12 files changed, 1300 insertions(+), 50 deletions(-) create mode 100644 Zotlabs/Module/Admin/Cover_photo.php create mode 100644 Zotlabs/Module/Admin/Profile_photo.php create mode 100644 view/tpl/admin_cropbody.tpl create mode 100644 view/tpl/admin_profile_photo.tpl diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 59e836a4d..9bc43316d 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -3286,19 +3286,15 @@ class Libzot { } } } - - $f = 'images/' . strtolower(System::get_platform_name()) . '.png'; - if (file_exists($f)) { - $ret['site']['logo'] = z_root() . '/' . $f; - } - + $ret['site']['about'] = bbcode(get_config('system','siteinfo'), [ 'export' => true ]); $ret['site']['plugins'] = $visible_plugins; $ret['site']['sitehash'] = get_config('system','location_hash'); - $ret['site']['sitename'] = get_config('system','sitename'); $ret['site']['sellpage'] = get_config('system','sellpage'); $ret['site']['location'] = get_config('system','site_location'); $ret['site']['realm'] = get_directory_realm(); + $ret['site']['sitename'] = System::get_site_name(); + $ret['site']['logo'] = System::get_site_icon(); $ret['site']['project'] = System::get_platform_name(); $ret['site']['version'] = System::get_project_version(); } diff --git a/Zotlabs/Lib/System.php b/Zotlabs/Lib/System.php index b124c7a99..5cac1e2b3 100644 --- a/Zotlabs/Lib/System.php +++ b/Zotlabs/Lib/System.php @@ -20,11 +20,10 @@ class System { static public function get_banner() { - if(is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('banner',App::$config['system'])) + if(is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('banner',App::$config['system']) && App::$config['system']['banner']) { return App::$config['system']['banner']; - - - return EMPTY_STR; + } + return self::get_site_name(); } static public function get_project_icon() { @@ -32,7 +31,6 @@ class System { return App::$config['system']['icon']; } return z_root() . '/images/' . PLATFORM_NAME . '-64.png'; - } @@ -55,13 +53,13 @@ class System { static public function get_notify_icon() { if(is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['email_notify_icon_url']) return App::$config['system']['email_notify_icon_url']; - return z_root() . DEFAULT_NOTIFY_ICON; + return self::get_project_icon(); } static public function get_site_icon() { if(is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['site_icon_url']) return App::$config['system']['site_icon_url']; - return z_root() . DEFAULT_PLATFORM_ICON ; + return self::get_project_icon(); } diff --git a/Zotlabs/Module/Admin/Cover_photo.php b/Zotlabs/Module/Admin/Cover_photo.php new file mode 100644 index 000000000..42aa238e6 --- /dev/null +++ b/Zotlabs/Module/Admin/Cover_photo.php @@ -0,0 +1,499 @@ + 0 order by imgscale asc LIMIT 1", + dbesc($image_id), + intval(local_channel()) + ); + + if ($r) { + + $max_thumb = intval(get_config('system','max_thumbnail',1600)); + $iscaled = false; + if (intval($r[0]['height']) > $max_thumb || intval($r[0]['width']) > $max_thumb) { + $imagick_path = get_config('system','imagick_convert_path'); + if ($imagick_path && @file_exists($imagick_path) && intval($r[0]['os_storage'])) { + + $fname = dbunescbin($r[0]['content']); + $tmp_name = $fname . '-001'; + $newsize = photo_calculate_scale(array_merge(getimagesize($fname),['max' => $max_thumb])); + $cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $fname) . ' -resize ' . $newsize . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmp_name); + // logger('imagick thumbnail command: ' . $cmd); + for ($x = 0; $x < 4; $x ++) { + exec($cmd); + if (file_exists($tmp_name)) { + break; + } + } + if (file_exists($tmp_name)) { + $base_image = $r[0]; + $gis = getimagesize($tmp_name); +logger('gis: ' . print_r($gis,true)); + $base_image['width'] = $gis[0]; + $base_image['height'] = $gis[1]; + $base_image['content'] = @file_get_contents($tmp_name); + $iscaled = true; + @unlink($tmp_name); + } + } + } + if (! $iscaled) { + $base_image = $r[0]; + $base_image['content'] = (($base_image['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content'])); + } + + $im = photo_factory($base_image['content'], $base_image['mimetype']); + if ($im->is_valid()) { + + // We are scaling and cropping the relative pixel locations to the original photo instead of the + // scaled photo we operated on. + + // First load the scaled photo to check its size. (Should probably pass this in the post form and save + // a query.) + + $g = q("select width, height from photo where resource_id = '%s' and uid = %d and imgscale = 3", + dbesc($image_id), + intval(local_channel()) + ); + + + $scaled_width = $g[0]['width']; + $scaled_height = $g[0]['height']; + + if ((! $scaled_width) || (! $scaled_height)) { + logger('potential divide by zero scaling cover photo'); + return; + } + + // unset all other cover photos + + q("update photo set photo_usage = %d where photo_usage = %d and uid = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_COVER), + intval(local_channel()) + ); + + $orig_srcx = ( $base_image['width'] / $scaled_width ) * $srcX; + $orig_srcy = ( $base_image['height'] / $scaled_height ) * $srcY; + $orig_srcw = ( $srcW / $scaled_width ) * $base_image['width']; + $orig_srch = ( $srcH / $scaled_height ) * $base_image['height']; + + $im->cropImageRect(1200,435,$orig_srcx, $orig_srcy, $orig_srcw, $orig_srch); + + $aid = get_account_id(); + + $p = [ + 'aid' => $aid, + 'uid' => local_channel(), + 'resource_id' => $base_image['resource_id'], + 'filename' => $base_image['filename'], + 'album' => t('Cover Photos'), + 'os_path' => $base_image['os_path'], + 'display_path' => $base_image['display_path'], + 'created' => $base_image['created'], + 'edited' => $base_image['edited'] + ]; + + $p['imgscale'] = 7; + $p['photo_usage'] = PHOTO_COVER; + + $r1 = $im->storeThumbnail($p, PHOTO_RES_COVER_1200); + + $im->doScaleImage(850,310); + $p['imgscale'] = 8; + + $r2 = $im->storeThumbnail($p, PHOTO_RES_COVER_850); + + $im->doScaleImage(425,160); + $p['imgscale'] = 9; + + $r3 = $im->storeThumbnail($p, PHOTO_RES_COVER_425); + + if ($r1 === false || $r2 === false || $r3 === false) { + // if one failed, delete them all so we can start over. + notice( t('Image resize failed.') . EOL ); + $x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale >= 7 ", + dbesc($base_image['resource_id']), + local_channel() + ); + return; + } + + $channel = App::get_channel(); + $this->send_cover_photo_activity($channel,$base_image,$profile); + + + } + else + notice( t('Unable to process image') . EOL); + } + + goaway(z_root() . '/channel/' . $channel['channel_address']); + + } + + + $hash = photo_new_resource(); + $smallest = 0; + + $matches = []; + $partial = false; + + if (array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) { + $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches); + if ($pm) { + logger('Content-Range: ' . print_r($matches,true)); + $partial = true; + } + } + + if ($partial) { + $x = save_chunk($channel,$matches[1],$matches[2],$matches[3]); + + if ($x['partial']) { + header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); + json_return_and_die($result); + } + else { + header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + + $_FILES['userfile'] = [ + 'name' => $x['name'], + 'type' => $x['type'], + 'tmp_name' => $x['tmp_name'], + 'error' => $x['error'], + 'size' => $x['size'] + ]; + } + } + else { + if (! array_key_exists('userfile',$_FILES)) { + $_FILES['userfile'] = [ + 'name' => $_FILES['files']['name'], + 'type' => $_FILES['files']['type'], + 'tmp_name' => $_FILES['files']['tmp_name'], + 'error' => $_FILES['files']['error'], + 'size' => $_FILES['files']['size'] + ]; + } + } + + $res = attach_store(App::get_channel(), get_observer_hash(), '', array('album' => t('Cover Photos'), 'hash' => $hash)); + + logger('attach_store: ' . print_r($res,true),LOGGER_DEBUG); + + json_return_and_die([ 'message' => $hash ]); + + } + + function send_cover_photo_activity($channel,$photo,$profile) { + + $arr = []; + $arr['item_thread_top'] = 1; + $arr['item_origin'] = 1; + $arr['item_wall'] = 1; + $arr['uuid'] = new_uuid(); + $arr['mid'] = z_root() . '/item/' . $arr['uuid']; + $arr['obj_type'] = ACTIVITY_OBJ_NOTE; + $arr['verb'] = ACTIVITY_CREATE; + + if ($profile && stripos($profile['gender'],t('female')) !== false) { + $t = t('%1$s updated her %2$s'); + } + elseif ($profile && stripos($profile['gender'],t('male')) !== false) { + $t = t('%1$s updated his %2$s'); + } + else { + $t = t('%1$s updated their %2$s'); + } + + $ptext = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']' . t('cover photo') . '[/zrl]'; + + $ltext = '[zrl=' . z_root() . '/profile/' . $channel['channel_address'] . ']' . '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-8[/zmg][/zrl]'; + + $arr['body'] = sprintf($t,$channel['channel_name'],$ptext) . "\n\n" . $ltext; + + $arr['obj'] = [ + 'type' => ACTIVITY_OBJ_NOTE, + 'published' => datetime_convert('UTC','UTC',$photo['created'],ATOM_TIME), + 'updated' => datetime_convert('UTC','UTC',$photo['edited'],ATOM_TIME), + 'id' => $arr['mid'], + 'url' => [ 'type' => 'Link', 'mediaType' => $photo['mimetype'], 'href' => z_root() . '/photo/' . $photo['resource_id'] . '-7' ], + 'source' => [ 'content' => $arr['body'], 'mediaType' => 'text/bbcode' ], + 'content' => bbcode($arr['body']), + 'actor' => Activity::encode_person($channel,false), + ]; + + $acl = new AccessControl($channel); + $x = $acl->get(); + $arr['allow_cid'] = $x['allow_cid']; + + $arr['allow_gid'] = $x['allow_gid']; + $arr['deny_cid'] = $x['deny_cid']; + $arr['deny_gid'] = $x['deny_gid']; + + $arr['uid'] = $channel['channel_id']; + $arr['aid'] = $channel['channel_account_id']; + + $arr['owner_xchan'] = $channel['channel_hash']; + $arr['author_xchan'] = $channel['channel_hash']; + + post_activity_item($arr); + + + } + + + /** + * @brief Generate content of profile-photo view + * + * @return string + * + */ + + + function get() { + + if (! local_channel()) { + notice( t('Permission denied.') . EOL ); + return; + } + + $channel = App::get_channel(); + + $newuser = false; + + if (argc() == 2 && argv(1) === 'new') + $newuser = true; + + if (argv(1) === 'use') { + if (argc() < 3) { + notice( t('Permission denied.') . EOL ); + return; + }; + + // check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo'); + + $resource_id = argv(2); + + $r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' and imgscale > 0 ORDER BY imgscale ASC", + intval(local_channel()), + dbesc($resource_id) + ); + if (! $r) { + notice( t('Photo not available.') . EOL ); + return; + } + $havescale = false; + foreach ($r as $rr) { + if ($rr['imgscale'] == 7) { + $havescale = true; + } + } + + $r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1", + intval($r[0]['id']), + intval(local_channel()) + + ); + if (! $r) { + notice( t('Photo not available.') . EOL ); + return; + } + + if (intval($r[0]['os_storage'])) { + $data = @file_get_contents(dbunescbin($r[0]['content'])); + } + else { + $data = dbunescbin($r[0]['content']); + } + + $ph = photo_factory($data, $r[0]['mimetype']); + $smallest = 0; + if ($ph->is_valid()) { + // go ahead as if we have just uploaded a new photo to crop + $i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d and imgscale = 0", + dbesc($r[0]['resource_id']), + intval(local_channel()) + ); + + if ($i) { + $hash = $i[0]['resource_id']; + foreach ($i as $ii) { + $smallest = intval($ii['imgscale']); + } + } + } + + $this->cover_photo_crop_ui_head($ph, $hash, $smallest); + } + + + if(! array_key_exists('imagecrop',App::$data)) { + + $o .= replace_macros(get_markup_template('cover_photo.tpl'), [ + '$user' => App::$channel['channel_address'], + '$info' => t('Your cover photo may be visible to anybody on the internet'), + '$existing' => get_cover_photo(local_channel(),'array',PHOTO_RES_COVER_850), + '$lbl_upfile' => t('Upload File:'), + '$lbl_profiles' => t('Select a profile:'), + '$title' => t('Change Cover Photo'), + '$submit' => t('Upload'), + '$profiles' => $profiles, + '$embedPhotos' => t('Use a photo from your albums'), + '$embedPhotosModalTitle' => t('Use a photo from your albums'), + '$embedPhotosModalCancel' => t('Cancel'), + '$embedPhotosModalOK' => t('OK'), + '$modalchooseimages' => t('Choose images to embed'), + '$modalchoosealbum' => t('Choose an album'), + '$modaldiffalbum' => t('Choose a different album'), + '$modalerrorlist' => t('Error getting album list'), + '$modalerrorlink' => t('Error getting photo link'), + '$modalerroralbum' => t('Error getting album'), + '$form_security_token' => get_form_security_token("cover_photo"), + '$select' => t('Select previously uploaded photo'), + + ]); + + call_hooks('cover_photo_content_end', $o); + + return $o; + } + else { + $filename = App::$data['imagecrop'] . '-3'; + $resolution = 3; + + $o .= replace_macros(get_markup_template('cropcover.tpl'), [ + '$filename' => $filename, + '$profile' => intval($_REQUEST['profile']), + '$resource' => \App::$data['imagecrop'] . '-3', + '$image_url' => z_root() . '/photo/' . $filename, + '$title' => t('Crop Image'), + '$desc' => t('Please adjust the image cropping for optimum viewing.'), + '$form_security_token' => get_form_security_token("cover_photo"), + '$done' => t('Done Editing') + ]); + return $o; + } + } + + /* @brief Generate the UI for photo-cropping + * + * @param $a Current application + * @param $ph Photo-Factory + * @return void + * + */ + + function cover_photo_crop_ui_head($ph, $hash, $smallest){ + + $max_length = get_config('system','max_image_length'); + if (! $max_length) { + $max_length = MAX_IMAGE_LENGTH; + } + if ($max_length > 0) { + $ph->scaleImage($max_length); + } + + $width = $ph->getWidth(); + $height = $ph->getHeight(); + + if ($width < 300 || $height < 300) { + $ph->scaleImageUp(240); + $width = $ph->getWidth(); + $height = $ph->getHeight(); + } + + + App::$data['imagecrop'] = $hash; + App::$data['imagecrop_resolution'] = $smallest; + App::$page['htmlhead'] .= replace_macros(get_markup_template('crophead.tpl'), []); + return; + } + + +} diff --git a/Zotlabs/Module/Admin/Profile_photo.php b/Zotlabs/Module/Admin/Profile_photo.php new file mode 100644 index 000000000..bc7160832 --- /dev/null +++ b/Zotlabs/Module/Admin/Profile_photo.php @@ -0,0 +1,534 @@ +is_valid()) { + + $im->cropImage(300,$srcX,$srcY,$srcW,$srcH); + + $aid = 0; + + $p = [ + 'aid' => $aid, + 'uid' => $channel['channel_id'], + 'resource_id' => $base_image['resource_id'], + 'filename' => $base_image['filename'], + 'album' => t('Profile Photos'), + 'os_path' => $base_image['os_path'], + 'display_path' => $base_image['display_path'], + 'created' => $base_image['created'], + 'edited' => $base_image['edited'] + ]; + + $p['imgscale'] = PHOTO_RES_PROFILE_300; + $p['photo_usage'] = (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL); + + $r1 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_300); + + $im->scaleImage(80); + $p['imgscale'] = PHOTO_RES_PROFILE_80; + + $r2 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_80); + + $im->scaleImage(48); + $p['imgscale'] = PHOTO_RES_PROFILE_48; + + $r3 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_48); + + if ($r1 === false || $r2 === false || $r3 === false) { + // if one failed, delete them all so we can start over. + notice( t('Image resize failed.') . EOL ); + $x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale in ( %d, %d, %d ) ", + dbesc($base_image['resource_id']), + $channel['channel_id'], + intval(PHOTO_RES_PROFILE_300), + intval(PHOTO_RES_PROFILE_80), + intval(PHOTO_RES_PROFILE_48) + ); + return; + } + + + $r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d + AND resource_id != '%s' AND uid = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + dbesc($base_image['resource_id']), + intval($channel['channel_id']) + ); + + // We'll set the updated profile-photo timestamp even if it isn't the default profile, + // so that browsers will do a cache update unconditionally + // Also set links back to site-specific profile photo url in case it was + // changed to a generic URL by a clone operation. Otherwise the new photo may + // not get pushed to other sites correctly. + + $r = q("UPDATE xchan set xchan_photo_mimetype = '%s', xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s' + where xchan_hash = '%s'", + dbesc($im->getType()), + dbesc(datetime_convert()), + dbesc(z_root() . '/photo/profile/l/' . $channel['channel_id']), + dbesc(z_root() . '/photo/profile/m/' . $channel['channel_id']), + dbesc(z_root() . '/photo/profile/s/' . $channel['channel_id']), + dbesc($channel['xchan_hash']) + ); + + // Similarly, tell the nav bar to bypass the cache and update the avatar image. + $_SESSION['reload_avatar'] = true; + Config::Set('system','site_icon_url',z_root() . '/photo/profile/m/' . $channel['channel_id']); + + info( t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL); + + } + else { + notice( t('Unable to process image') . EOL); + } + } + + goaway(z_root() . '/admin'); + } + + // A new photo was uploaded. Store it and save some important details + // in App::$data for use in the cropping function + + + $hash = photo_new_resource(); + $importing = false; + $smallest = 0; + + + if ($_REQUEST['importfile']) { + $hash = $_REQUEST['importfile']; + $importing = true; + } + else { + + $matches = []; + $partial = false; + + if (array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) { + $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches); + if ($pm) { + logger('Content-Range: ' . print_r($matches,true), LOGGER_DEBUG); + $partial = true; + } + } + + if ($partial) { + $x = save_chunk($channel,$matches[1],$matches[2],$matches[3]); + + if ($x['partial']) { + header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); + json_return_and_die($result); + } + else { + header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + + $_FILES['userfile'] = [ + 'name' => $x['name'], + 'type' => $x['type'], + 'tmp_name' => $x['tmp_name'], + 'error' => $x['error'], + 'size' => $x['size'] + ]; + } + } + else { + if (! array_key_exists('userfile',$_FILES)) { + $_FILES['userfile'] = [ + 'name' => $_FILES['files']['name'], + 'type' => $_FILES['files']['type'], + 'tmp_name' => $_FILES['files']['tmp_name'], + 'error' => $_FILES['files']['error'], + 'size' => $_FILES['files']['size'] + ]; + } + } + + $res = attach_store($channel, $channel['channel_hash'], '', array('album' => t('Profile Photos'), 'hash' => $hash)); + + logger('attach_store: ' . print_r($res,true), LOGGER_DEBUG); + + json_return_and_die([ 'message' => $hash ]); + } + + if (($res && intval($res['data']['is_photo'])) || $importing) { + $i = q("select * from photo where resource_id = '%s' and uid = %d order by imgscale", + dbesc($hash), + intval($channel['channel_hash']) + ); + + if (! $i) { + notice( t('Image upload failed.') . EOL ); + return; + } + $os_storage = false; + + foreach ($i as $ii) { + if (intval($ii['imgscale']) < PHOTO_RES_640) { + $smallest = intval($ii['imgscale']); + $os_storage = intval($ii['os_storage']); + $imagedata = $ii['content']; + $filetype = $ii['mimetype']; + } + } + } + + $imagedata = (($os_storage) ? @file_get_contents(dbunescbin($imagedata)) : dbunescbin($imagedata)); + $ph = photo_factory($imagedata, $filetype); + + if (! $ph->is_valid()) { + notice( t('Unable to process image.') . EOL ); + return; + } + + return $this->profile_photo_crop_ui_head($ph, $hash, $smallest); + + // This will "fall through" to the get() method, and since + // App::$data['imagecrop'] is set, it will proceed to cropping + // rather than present the upload form + } + + + /* @brief Generate content of profile-photo view + * + * @return void + * + */ + + + function get() { + + if (! is_site_admin()) { + notice( t('Permission denied.') . EOL ); + return; + } + + $channel = get_sys_channel(); + $pf = 0; + $newuser = false; + + if (argc() == 3 && argv(2) === 'new') { + $newuser = true; + } + + if (argv(2) === 'reset') { + Config::Delete('system','site_icon_url'); + } + + if (argv(2) === 'use') { + if (argc() < 4) { + notice( t('Permission denied.') . EOL ); + return; + }; + + $resource_id = argv(3); + + $pf = (($_REQUEST['pf']) ? intval($_REQUEST['pf']) : 0); + + $c = q("select id, is_default from profile where uid = %d", + intval($channel['channel_id']) + ); + + $multi_profiles = true; + + if (($c) && (count($c) === 1) && (intval($c[0]['is_default']))) { + $_REQUEST['profile'] = $c[0]['id']; + $multi_profiles = false; + } + else { + $_REQUEST['profile'] = $pf; + } + + $r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY imgscale ASC", + intval($channel['channel_id']), + dbesc($resource_id) + ); + if (! $r) { + notice( t('Photo not available.') . EOL ); + return; + } + $havescale = false; + foreach ($r as $rr) { + if ($rr['imgscale'] == PHOTO_RES_PROFILE_80) { + $havescale = true; + } + } + + // set an already loaded and cropped photo as profile photo + + if ($havescale) { + // unset any existing profile photos + $r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND uid = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + intval($channel['channel_id']) + ); + + $r = q("UPDATE photo SET photo_usage = %d WHERE uid = %d AND resource_id = '%s'", + intval(PHOTO_PROFILE), + intval($channel['channel_id']), + dbesc($resource_id) + ); + + $r = q("UPDATE xchan set xchan_photo_date = '%s' where xchan_hash = '%s'", + dbesc(datetime_convert()), + dbesc($channel['xchan_hash']) + ); + + goaway(z_root() . '/admin'); + } + + $r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1", + intval($r[0]['id']), + intval($channel['channel_id']) + + ); + if (! $r) { + notice( t('Photo not available.') . EOL ); + return; + } + + if (intval($r[0]['os_storage'])) { + $data = @file_get_contents(dbunescbin($r[0]['content'])); + } + else { + $data = dbunescbin($r[0]['content']); + } + + $ph = photo_factory($data, $r[0]['mimetype']); + $smallest = 0; + if ($ph->is_valid()) { + // go ahead as if we have just uploaded a new photo to crop + $i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d order by imgscale", + dbesc($r[0]['resource_id']), + intval($channel['channel_id']) + ); + + if ($i) { + $hash = $i[0]['resource_id']; + foreach ($i as $ii) { + if (intval($ii['imgscale']) < PHOTO_RES_640) { + $smallest = intval($ii['imgscale']); + } + } + } + } + + if ($multi_profiles) { + App::$data['importfile'] = $resource_id; + } + else { + $this->profile_photo_crop_ui_head($ph, $hash, $smallest); + } + + // falls through with App::$data['imagecrop'] set so we go straight to the cropping section + + } + + // present an upload form + + $profiles = q("select id, profile_name as name, is_default from profile where uid = %d order by id asc", + intval($channel['channel_id']) + ); + + if ($profiles) { + for ($x = 0; $x < count($profiles); $x ++) { + $profiles[$x]['selected'] = false; + if ($pf && $profiles[$x]['id'] == $pf) { + $profiles[$x]['selected'] = true; + } + if ((! $pf) && $profiles[$x]['is_default']) { + $profiles[$x]['selected'] = true; + } + } + } + + $importing = ((array_key_exists('importfile',App::$data)) ? true : false); + + if (! array_key_exists('imagecrop', App::$data)) { + + $tpl = get_markup_template('admin_profile_photo.tpl'); + + $o .= replace_macros($tpl, [ + '$user' => $channel['channel_address'], + '$info' => ((count($profiles) > 1) ? t('Your default profile photo is visible to anybody on the internet. Profile photos for alternate profiles will inherit the permissions of the profile') : t('Your site photo is visible to anybody on the internet and may be distributed to other websites.')), + '$importfile' => (($importing) ? App::$data['importfile'] : ''), + '$lbl_upfile' => t('Upload File:'), + '$lbl_profiles' => t('Select a profile:'), + '$title' => (($importing) ? t('Use Photo for Site Logo') : t('Change Site Logo')), + '$submit' => (($importing) ? t('Use') : t('Upload')), + '$profiles' => $profiles, + '$single' => ((count($profiles) == 1) ? true : false), + '$profile0' => $profiles[0], + '$embedPhotos' => t('Use a photo from your albums'), + '$embedPhotosModalTitle' => t('Use a photo from your albums'), + '$embedPhotosModalCancel' => t('Cancel'), + '$embedPhotosModalOK' => t('OK'), + '$modalchooseimages' => t('Choose images to embed'), + '$modalchoosealbum' => t('Choose an album'), + '$modaldiffalbum' => t('Choose a different album'), + '$modalerrorlist' => t('Error getting album list'), + '$modalerrorlink' => t('Error getting photo link'), + '$modalerroralbum' => t('Error getting album'), + '$form_security_token' => get_form_security_token("profile_photo"), + '$select' => t('Select previously uploaded photo'), + ]); + + call_hooks('profile_photo_content_end', $o); + return $o; + } + else { + + // present a cropping form + + $filename = App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution']; + $resolution = App::$data['imagecrop_resolution']; + $o .= replace_macros(get_markup_template('admin_cropbody.tpl'), [ + '$filename' => $filename, + '$profile' => intval($_REQUEST['profile']), + '$resource' => App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution'], + '$image_url' => z_root() . '/photo/' . $filename, + '$title' => t('Crop Image'), + '$desc' => t('Please adjust the image cropping for optimum viewing.'), + '$form_security_token' => get_form_security_token("profile_photo"), + '$done' => t('Done Editing') + ]); + return $o; + } + } + + /* @brief Generate the UI for photo-cropping + * + * @param $ph Photo-Factory + * @return void + * + */ + + function profile_photo_crop_ui_head($ph, $hash, $smallest) { + $max_length = get_config('system','max_image_length'); + if (! $max_length) { + $max_length = MAX_IMAGE_LENGTH; + } + if ($max_length > 0) { + $ph->scaleImage($max_length); + } + + App::$data['width'] = $ph->getWidth(); + App::$data['height'] = $ph->getHeight(); + + if (App::$data['width'] < 500 || App::$data['height'] < 500) { + $ph->scaleImageUp(400); + App::$data['width'] = $ph->getWidth(); + App::$data['height'] = $ph->getHeight(); + } + + App::$data['imagecrop'] = $hash; + App::$data['imagecrop_resolution'] = $smallest; + App::$page['htmlhead'] .= replace_macros(get_markup_template('crophead.tpl'), []); + return; + } +} diff --git a/Zotlabs/Module/Admin/Site.php b/Zotlabs/Module/Admin/Site.php index eb34e5b8a..c3797e33f 100644 --- a/Zotlabs/Module/Admin/Site.php +++ b/Zotlabs/Module/Admin/Site.php @@ -25,8 +25,6 @@ class Site { $sitename = ((x($_POST,'sitename')) ? notags(trim($_POST['sitename'])) : ''); - $banner = ((x($_POST,'banner')) ? trim($_POST['banner']) : false); - $admininfo = ((x($_POST,'admininfo')) ? trim($_POST['admininfo']) : false); $siteinfo = ((x($_POST,'siteinfo')) ? trim($_POST['siteinfo']) : ''); $language = ((x($_POST,'language')) ? notags(trim($_POST['language'])) : 'en'); @@ -123,13 +121,6 @@ class Site { set_config('system','directory_server',$directory_server); } - if ($banner == '') { - del_config('system', 'banner'); - } - else { - set_config('system', 'banner', $banner); - } - if ($admininfo == '') { del_config('system', 'admininfo'); } @@ -250,11 +241,6 @@ class Site { } } - /* Banner */ - - $banner = System::get_banner(); - - $banner = htmlspecialchars($banner); /* Admin Info */ @@ -304,7 +290,6 @@ class Site { '$advanced' => t('Advanced'), '$baseurl' => z_root(), '$sitename' => [ 'sitename', t("Site name"), htmlspecialchars(get_config('system','sitename'), ENT_QUOTES, 'UTF-8'),'' ], - '$banner' => [ 'banner', t("Banner/Logo"), $banner, t('Unfiltered HTML/CSS/JS is allowed') ], '$admininfo' => [ 'admininfo', t("Administrator Information"), $admininfo, t("Contact information for site administrators. Displayed on siteinfo page. BBCode may be used here.") ], '$siteinfo' => [ 'siteinfo', t('Site Information'), get_config('system','siteinfo'), t("Publicly visible description of this site. Displayed on siteinfo page. BBCode may be used here.") ], '$language' => [ 'language', t("System language"), get_config('system','language','en'), "", $lang_choices ], diff --git a/Zotlabs/Widget/Admin.php b/Zotlabs/Widget/Admin.php index 2bf62570b..95e64244e 100644 --- a/Zotlabs/Widget/Admin.php +++ b/Zotlabs/Widget/Admin.php @@ -19,16 +19,17 @@ class Admin { // array( url, name, extra css classes ) $aside = [ - 'site' => array(z_root() . '/admin/site/', t('Site'), 'site'), - 'accounts' => array(z_root() . '/admin/accounts/', t('Accounts'), 'accounts', 'pending-update', t('Member registrations waiting for confirmation')), - 'channels' => array(z_root() . '/admin/channels/', t('Channels'), 'channels'), - 'security' => array(z_root() . '/admin/security/', t('Security'), 'security'), -// 'features' => array(z_root() . '/admin/features/', t('Features'), 'features'), - 'addons' => array(z_root() . '/admin/addons/', t('Addons'), 'addons'), - 'themes' => array(z_root() . '/admin/themes/', t('Themes'), 'themes'), - 'queue' => array(z_root() . '/admin/queue', t('Inspect queue'), 'queue'), -// 'profs' => array(z_root() . '/admin/profs', t('Profile Fields'), 'profs'), - 'dbsync' => array(z_root() . '/admin/dbsync/', t('DB updates'), 'dbsync') + 'site' => array(z_root() . '/admin/site/', t('Site'), 'site'), + 'profile_photo' => array(z_root() . '/admin/profile_photo', t('Site icon/logo'), 'profile_photo'), + 'accounts' => array(z_root() . '/admin/accounts/', t('Accounts'), 'accounts', 'pending-update', t('Member registrations waiting for confirmation')), + 'channels' => array(z_root() . '/admin/channels/', t('Channels'), 'channels'), + 'security' => array(z_root() . '/admin/security/', t('Security'), 'security'), +// 'features' => array(z_root() . '/admin/features/', t('Features'), 'features'), + 'addons' => array(z_root() . '/admin/addons/', t('Addons'), 'addons'), + 'themes' => array(z_root() . '/admin/themes/', t('Themes'), 'themes'), + 'queue' => array(z_root() . '/admin/queue', t('Inspect queue'), 'queue'), +// 'profs' => array(z_root() . '/admin/profs', t('Profile Fields'), 'profs'), + 'dbsync' => array(z_root() . '/admin/dbsync/', t('DB updates'), 'dbsync') ]; /* get plugins admin page */ diff --git a/include/nav.php b/include/nav.php index 2cc8501dd..7d7e7b252 100644 --- a/include/nav.php +++ b/include/nav.php @@ -47,9 +47,9 @@ function nav($template = 'default') { $channel_apps[] = channel_apps($is_owner, App::$profile['channel_address']); - $project_icon = System::get_project_icon(); + $site_icon = System::get_site_icon(); - $banner = System::get_banner(); + $banner = System::get_site_name(); App::$page['header'] .= replace_macros(get_markup_template('hdr.tpl'), array( //we could additionally use this to display important system notifications e.g. for updates @@ -284,7 +284,7 @@ function nav($template = 'default') { App::$page['nav'] .= replace_macros($tpl, array( '$baseurl' => z_root(), - '$project_icon' => $project_icon, + '$project_icon' => $site_icon, '$project_title' => t('Powered by $Projectname'), '$fulldocs' => t('Help'), '$sitelocation' => $sitelocation, diff --git a/view/theme/redbasic/css/style.css b/view/theme/redbasic/css/style.css index 5a16dba4e..4b5ec53c9 100644 --- a/view/theme/redbasic/css/style.css +++ b/view/theme/redbasic/css/style.css @@ -15,11 +15,6 @@ html { margin-right: 1.5rem; } -.project-banner img { - height: 32px; - width: 32px; -} - .project-banner a { color: $banner_colour; } @@ -1301,7 +1296,7 @@ img.mail-conv-sender-photo { width: 3.75rem; } -#avatar { +#avatar, .nav-avatar { width: 2.35rem; height: 2.35rem; border-radius: $radius; diff --git a/view/tpl/admin_cropbody.tpl b/view/tpl/admin_cropbody.tpl new file mode 100644 index 000000000..a5954576e --- /dev/null +++ b/view/tpl/admin_cropbody.tpl @@ -0,0 +1,48 @@ +

{{$title}}

+

+{{$desc}} +

+
+{{$title}} +
+
+
+
+ + + +
+ + + + + + + + + + + +
+ +
+ +
diff --git a/view/tpl/admin_profile_photo.tpl b/view/tpl/admin_profile_photo.tpl new file mode 100644 index 000000000..547d4e7d6 --- /dev/null +++ b/view/tpl/admin_profile_photo.tpl @@ -0,0 +1,195 @@ + + + + + + + + + + + + +
+
+

{{$title}}

+
+
+ +
+ + +
+ {{if $info}} +
{{$info}}
+ {{/if}} + {{if $importfile}} + + {{else}} +
+
+
+ + {{/if}} +
+ + + {{if $single}} + + {{else}} + + + + + +
+
+
+ {{/if}} + +
+ +
+
+ +
+
+ +
+
+ + + + + diff --git a/view/tpl/admin_site.tpl b/view/tpl/admin_site.tpl index 634bdf898..0d7819ee8 100755 --- a/view/tpl/admin_site.tpl +++ b/view/tpl/admin_site.tpl @@ -55,7 +55,6 @@
{{include file="field_input.tpl" field=$sitename}} - {{include file="field_textarea.tpl" field=$banner}} {{include file="field_textarea.tpl" field=$siteinfo}} {{include file="field_textarea.tpl" field=$admininfo}} {{include file="field_input.tpl" field=$reply_address}} diff --git a/view/tpl/navbar_default.tpl b/view/tpl/navbar_default.tpl index d91a06f34..28e26ba80 100755 --- a/view/tpl/navbar_default.tpl +++ b/view/tpl/navbar_default.tpl @@ -1,4 +1,4 @@ -
{{$project_title}}
+
{{$project_title}}
{{if $nav.login && !$userinfo}}
{{if $nav.loginmenu.1.4}} From 56b1e4eaf67f34d7205c9cfe5e584e2ad4add7a8 Mon Sep 17 00:00:00 2001 From: nobody Date: Wed, 9 Sep 2020 18:34:09 -0700 Subject: [PATCH 03/12] site cover photos --- Zotlabs/Module/Admin/Cover_photo.php | 117 +++++-------------- view/tpl/admin_cover_photo.tpl | 167 +++++++++++++++++++++++++++ view/tpl/admin_cropcover.tpl | 47 ++++++++ 3 files changed, 242 insertions(+), 89 deletions(-) create mode 100755 view/tpl/admin_cover_photo.tpl create mode 100755 view/tpl/admin_cropcover.tpl diff --git a/Zotlabs/Module/Admin/Cover_photo.php b/Zotlabs/Module/Admin/Cover_photo.php index 42aa238e6..db890cbcf 100644 --- a/Zotlabs/Module/Admin/Cover_photo.php +++ b/Zotlabs/Module/Admin/Cover_photo.php @@ -30,11 +30,11 @@ require_once('include/photos.php'); class Cover_photo { function init() { - if (! local_channel()) { + if (! is_site_admin()) { return; } - $channel = App::get_channel(); + $channel = get_sys_channel(); Libprofile::load($channel['channel_address']); } @@ -47,24 +47,24 @@ class Cover_photo { function post() { - if (! local_channel()) { + if (! is_site_admin()) { return; } - $channel = App::get_channel(); + $channel = get_sys_channel(); - check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo'); + check_form_security_token_redirectOnErr('/admin/cover_photo', 'cover_photo'); if ((array_key_exists('cropfinal',$_POST)) && ($_POST['cropfinal'] == 1)) { // phase 2 - we have finished cropping - if (argc() != 2) { + if (argc() != 3) { notice( t('Image uploaded but image cropping failed.') . EOL ); return; } - $image_id = argv(1); + $image_id = argv(2); if (substr($image_id,-2,1) == '-') { $scale = substr($image_id,-1,1); @@ -79,7 +79,7 @@ class Cover_photo { $srcH = intval($_POST['yfinal']) - $srcY; $r = q("select gender from profile where uid = %d and is_default = 1 limit 1", - intval(local_channel()) + intval($channel['channel_id']) ); if ($r) { $profile = array_shift($r); @@ -87,7 +87,7 @@ class Cover_photo { $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale > 0 order by imgscale asc LIMIT 1", dbesc($image_id), - intval(local_channel()) + intval($channel['channel_id']) ); if ($r) { @@ -137,7 +137,7 @@ logger('gis: ' . print_r($gis,true)); $g = q("select width, height from photo where resource_id = '%s' and uid = %d and imgscale = 3", dbesc($image_id), - intval(local_channel()) + intval($channel['channel_id']) ); @@ -154,7 +154,7 @@ logger('gis: ' . print_r($gis,true)); q("update photo set photo_usage = %d where photo_usage = %d and uid = %d", intval(PHOTO_NORMAL), intval(PHOTO_COVER), - intval(local_channel()) + intval($channel['channel_id']) ); $orig_srcx = ( $base_image['width'] / $scaled_width ) * $srcX; @@ -167,8 +167,8 @@ logger('gis: ' . print_r($gis,true)); $aid = get_account_id(); $p = [ - 'aid' => $aid, - 'uid' => local_channel(), + 'aid' => 0, + 'uid' => $channel['channel_id'], 'resource_id' => $base_image['resource_id'], 'filename' => $base_image['filename'], 'album' => t('Cover Photos'), @@ -198,21 +198,17 @@ logger('gis: ' . print_r($gis,true)); notice( t('Image resize failed.') . EOL ); $x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale >= 7 ", dbesc($base_image['resource_id']), - local_channel() + intval($channel['channel_id']) ); return; - } - - $channel = App::get_channel(); - $this->send_cover_photo_activity($channel,$base_image,$profile); - + } } else notice( t('Unable to process image') . EOL); } - goaway(z_root() . '/channel/' . $channel['channel_address']); + goaway(z_root() . '/admin'); } @@ -262,7 +258,7 @@ logger('gis: ' . print_r($gis,true)); } } - $res = attach_store(App::get_channel(), get_observer_hash(), '', array('album' => t('Cover Photos'), 'hash' => $hash)); + $res = attach_store($channel, $channel['channel_hash'], '', array('album' => t('Cover Photos'), 'hash' => $hash)); logger('attach_store: ' . print_r($res,true),LOGGER_DEBUG); @@ -270,63 +266,6 @@ logger('gis: ' . print_r($gis,true)); } - function send_cover_photo_activity($channel,$photo,$profile) { - - $arr = []; - $arr['item_thread_top'] = 1; - $arr['item_origin'] = 1; - $arr['item_wall'] = 1; - $arr['uuid'] = new_uuid(); - $arr['mid'] = z_root() . '/item/' . $arr['uuid']; - $arr['obj_type'] = ACTIVITY_OBJ_NOTE; - $arr['verb'] = ACTIVITY_CREATE; - - if ($profile && stripos($profile['gender'],t('female')) !== false) { - $t = t('%1$s updated her %2$s'); - } - elseif ($profile && stripos($profile['gender'],t('male')) !== false) { - $t = t('%1$s updated his %2$s'); - } - else { - $t = t('%1$s updated their %2$s'); - } - - $ptext = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']' . t('cover photo') . '[/zrl]'; - - $ltext = '[zrl=' . z_root() . '/profile/' . $channel['channel_address'] . ']' . '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-8[/zmg][/zrl]'; - - $arr['body'] = sprintf($t,$channel['channel_name'],$ptext) . "\n\n" . $ltext; - - $arr['obj'] = [ - 'type' => ACTIVITY_OBJ_NOTE, - 'published' => datetime_convert('UTC','UTC',$photo['created'],ATOM_TIME), - 'updated' => datetime_convert('UTC','UTC',$photo['edited'],ATOM_TIME), - 'id' => $arr['mid'], - 'url' => [ 'type' => 'Link', 'mediaType' => $photo['mimetype'], 'href' => z_root() . '/photo/' . $photo['resource_id'] . '-7' ], - 'source' => [ 'content' => $arr['body'], 'mediaType' => 'text/bbcode' ], - 'content' => bbcode($arr['body']), - 'actor' => Activity::encode_person($channel,false), - ]; - - $acl = new AccessControl($channel); - $x = $acl->get(); - $arr['allow_cid'] = $x['allow_cid']; - - $arr['allow_gid'] = $x['allow_gid']; - $arr['deny_cid'] = $x['deny_cid']; - $arr['deny_gid'] = $x['deny_gid']; - - $arr['uid'] = $channel['channel_id']; - $arr['aid'] = $channel['channel_account_id']; - - $arr['owner_xchan'] = $channel['channel_hash']; - $arr['author_xchan'] = $channel['channel_hash']; - - post_activity_item($arr); - - - } - /** * @brief Generate content of profile-photo view @@ -338,30 +277,30 @@ logger('gis: ' . print_r($gis,true)); function get() { - if (! local_channel()) { + if (! is_site_admin()) { notice( t('Permission denied.') . EOL ); return; } - $channel = App::get_channel(); + $channel = get_sys_channel(); $newuser = false; - if (argc() == 2 && argv(1) === 'new') + if (argc() == 3 && argv(1) === 'new') $newuser = true; - if (argv(1) === 'use') { - if (argc() < 3) { + if (argv(2) === 'use') { + if (argc() < 4) { notice( t('Permission denied.') . EOL ); return; }; // check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo'); - $resource_id = argv(2); + $resource_id = argv(3); $r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' and imgscale > 0 ORDER BY imgscale ASC", - intval(local_channel()), + intval($channel['channel_id']), dbesc($resource_id) ); if (! $r) { @@ -377,7 +316,7 @@ logger('gis: ' . print_r($gis,true)); $r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1", intval($r[0]['id']), - intval(local_channel()) + intval($channel['channel_id']) ); if (! $r) { @@ -398,7 +337,7 @@ logger('gis: ' . print_r($gis,true)); // go ahead as if we have just uploaded a new photo to crop $i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d and imgscale = 0", dbesc($r[0]['resource_id']), - intval(local_channel()) + intval($channel['channel_id']) ); if ($i) { @@ -416,9 +355,9 @@ logger('gis: ' . print_r($gis,true)); if(! array_key_exists('imagecrop',App::$data)) { $o .= replace_macros(get_markup_template('cover_photo.tpl'), [ - '$user' => App::$channel['channel_address'], + '$user' => $channel['channel_address'], '$info' => t('Your cover photo may be visible to anybody on the internet'), - '$existing' => get_cover_photo(local_channel(),'array',PHOTO_RES_COVER_850), + '$existing' => get_cover_photo($channel['channel_id'],'array',PHOTO_RES_COVER_850), '$lbl_upfile' => t('Upload File:'), '$lbl_profiles' => t('Select a profile:'), '$title' => t('Change Cover Photo'), diff --git a/view/tpl/admin_cover_photo.tpl b/view/tpl/admin_cover_photo.tpl new file mode 100755 index 000000000..33a9f912b --- /dev/null +++ b/view/tpl/admin_cover_photo.tpl @@ -0,0 +1,167 @@ + + + + + + + + + +
+
+

{{$title}}

+
+
+ {{if $info}} +
{{$info}}
+ {{/if}} + {{if $existing}} + {{t('Cover Photo')}} + {{/if}} +
+ +
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ + + + diff --git a/view/tpl/admin_cropcover.tpl b/view/tpl/admin_cropcover.tpl new file mode 100755 index 000000000..377068bae --- /dev/null +++ b/view/tpl/admin_cropcover.tpl @@ -0,0 +1,47 @@ +

{{$title}}

+

+{{$desc}} +

+
+{{$title}} +
+
+
+
+ + + +
+ + + + + + + + + + + +
+ +
+ +
From ef3b0a37187e80c6011670878baa3f67d5ce8008 Mon Sep 17 00:00:00 2001 From: nobody Date: Wed, 9 Sep 2020 18:39:43 -0700 Subject: [PATCH 04/12] bugfixes to site cover photos --- Zotlabs/Module/Admin/Cover_photo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Zotlabs/Module/Admin/Cover_photo.php b/Zotlabs/Module/Admin/Cover_photo.php index db890cbcf..db084b0f9 100644 --- a/Zotlabs/Module/Admin/Cover_photo.php +++ b/Zotlabs/Module/Admin/Cover_photo.php @@ -354,7 +354,7 @@ logger('gis: ' . print_r($gis,true)); if(! array_key_exists('imagecrop',App::$data)) { - $o .= replace_macros(get_markup_template('cover_photo.tpl'), [ + $o .= replace_macros(get_markup_template('admin_cover_photo.tpl'), [ '$user' => $channel['channel_address'], '$info' => t('Your cover photo may be visible to anybody on the internet'), '$existing' => get_cover_photo($channel['channel_id'],'array',PHOTO_RES_COVER_850), @@ -386,7 +386,7 @@ logger('gis: ' . print_r($gis,true)); $filename = App::$data['imagecrop'] . '-3'; $resolution = 3; - $o .= replace_macros(get_markup_template('cropcover.tpl'), [ + $o .= replace_macros(get_markup_template('admin_cropcover.tpl'), [ '$filename' => $filename, '$profile' => intval($_REQUEST['profile']), '$resource' => \App::$data['imagecrop'] . '-3', From a61fe419e6d4c562ef84610e0d557f2dafd1eb40 Mon Sep 17 00:00:00 2001 From: nobody Date: Wed, 9 Sep 2020 20:14:06 -0700 Subject: [PATCH 05/12] provide site cover photo on homepage --- Zotlabs/Widget/Cover_photo.php | 8 ++++++++ boot.php | 1 - view/pdl/mod_home.pdl | 3 +++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 view/pdl/mod_home.pdl diff --git a/Zotlabs/Widget/Cover_photo.php b/Zotlabs/Widget/Cover_photo.php index 955048992..a4661746d 100644 --- a/Zotlabs/Widget/Cover_photo.php +++ b/Zotlabs/Widget/Cover_photo.php @@ -2,6 +2,8 @@ namespace Zotlabs\Widget; +use App; + class Cover_photo { function widget($arr) { @@ -13,6 +15,12 @@ class Cover_photo { return ''; $channel_id = 0; + + if (App::$module === 'home') { + $channel = get_sys_channel(); + $channel_id = $channel['channel_id']; + } + if(array_key_exists('channel_id', $arr) && intval($arr['channel_id'])) $channel_id = intval($arr['channel_id']); if(! $channel_id) diff --git a/boot.php b/boot.php index ec1d67ac8..ac705bab9 100755 --- a/boot.php +++ b/boot.php @@ -2233,7 +2233,6 @@ function construct_page() { call_hooks('construct_page', $arr); App::$layout = $arr['layout']; - foreach(App::$layout as $k => $v) { if((strpos($k, 'region_') === 0) && strlen($v)) { if(strpos($v, '$region_') !== false) { diff --git a/view/pdl/mod_home.pdl b/view/pdl/mod_home.pdl new file mode 100644 index 000000000..7c70c39d0 --- /dev/null +++ b/view/pdl/mod_home.pdl @@ -0,0 +1,3 @@ +[region=banner] +[widget=cover_photo][/widget] +[/region] From 2e4fd68c07cc11c0d9151684281577bad1418ca5 Mon Sep 17 00:00:00 2001 From: nobody Date: Wed, 9 Sep 2020 20:18:50 -0700 Subject: [PATCH 06/12] provide ability to reset site cover photo --- Zotlabs/Module/Admin/Cover_photo.php | 11 ++++++++++- Zotlabs/Widget/Admin.php | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Zotlabs/Module/Admin/Cover_photo.php b/Zotlabs/Module/Admin/Cover_photo.php index db084b0f9..ebfb35bf9 100644 --- a/Zotlabs/Module/Admin/Cover_photo.php +++ b/Zotlabs/Module/Admin/Cover_photo.php @@ -288,7 +288,16 @@ logger('gis: ' . print_r($gis,true)); if (argc() == 3 && argv(1) === 'new') $newuser = true; - + + + if (argv(2) === 'reset') { + q("update photo set photo_usage = %d where photo_usage = %d and uid = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_COVER), + intval($channel['channel_id']) + ); + } + if (argv(2) === 'use') { if (argc() < 4) { notice( t('Permission denied.') . EOL ); diff --git a/Zotlabs/Widget/Admin.php b/Zotlabs/Widget/Admin.php index 95e64244e..cbba812d7 100644 --- a/Zotlabs/Widget/Admin.php +++ b/Zotlabs/Widget/Admin.php @@ -21,6 +21,7 @@ class Admin { $aside = [ 'site' => array(z_root() . '/admin/site/', t('Site'), 'site'), 'profile_photo' => array(z_root() . '/admin/profile_photo', t('Site icon/logo'), 'profile_photo'), + 'cover_photo' => array(z_root() . '/admin/cover_photo', t('Site photo'), 'cover_photo'), 'accounts' => array(z_root() . '/admin/accounts/', t('Accounts'), 'accounts', 'pending-update', t('Member registrations waiting for confirmation')), 'channels' => array(z_root() . '/admin/channels/', t('Channels'), 'channels'), 'security' => array(z_root() . '/admin/security/', t('Security'), 'security'), From fcb7933c85227eaa1188bb902e82df85afdab787 Mon Sep 17 00:00:00 2001 From: nobody Date: Wed, 9 Sep 2020 20:52:42 -0700 Subject: [PATCH 07/12] make embedded photos work for site logo and cover photo --- Zotlabs/Module/Admin/Cover_photo.php | 1 + Zotlabs/Module/Admin/Profile_photo.php | 1 + Zotlabs/Module/Embedphotos.php | 27 +++++++++++++++++++------- view/tpl/admin_cover_photo.tpl | 6 +++--- view/tpl/admin_profile_photo.tpl | 6 +++--- 5 files changed, 28 insertions(+), 13 deletions(-) diff --git a/Zotlabs/Module/Admin/Cover_photo.php b/Zotlabs/Module/Admin/Cover_photo.php index ebfb35bf9..4f2c24833 100644 --- a/Zotlabs/Module/Admin/Cover_photo.php +++ b/Zotlabs/Module/Admin/Cover_photo.php @@ -365,6 +365,7 @@ logger('gis: ' . print_r($gis,true)); $o .= replace_macros(get_markup_template('admin_cover_photo.tpl'), [ '$user' => $channel['channel_address'], + '$channel_id' => $channel['channel_id'], '$info' => t('Your cover photo may be visible to anybody on the internet'), '$existing' => get_cover_photo($channel['channel_id'],'array',PHOTO_RES_COVER_850), '$lbl_upfile' => t('Upload File:'), diff --git a/Zotlabs/Module/Admin/Profile_photo.php b/Zotlabs/Module/Admin/Profile_photo.php index bc7160832..53e8b8e58 100644 --- a/Zotlabs/Module/Admin/Profile_photo.php +++ b/Zotlabs/Module/Admin/Profile_photo.php @@ -455,6 +455,7 @@ class Profile_photo { $o .= replace_macros($tpl, [ '$user' => $channel['channel_address'], + '$channel_id' => $channel['channel_id'], '$info' => ((count($profiles) > 1) ? t('Your default profile photo is visible to anybody on the internet. Profile photos for alternate profiles will inherit the permissions of the profile') : t('Your site photo is visible to anybody on the internet and may be distributed to other websites.')), '$importfile' => (($importing) ? App::$data['importfile'] : ''), '$lbl_upfile' => t('Upload File:'), diff --git a/Zotlabs/Module/Embedphotos.php b/Zotlabs/Module/Embedphotos.php index e00ff63c1..95e89d003 100644 --- a/Zotlabs/Module/Embedphotos.php +++ b/Zotlabs/Module/Embedphotos.php @@ -16,18 +16,24 @@ class Embedphotos extends Controller { * */ function post() { + if (argc() > 2 && is_site_admin() && intval(argv(2))) { + $channel_id = argv(2); + } + else { + $channel_id = local_channel(); + } if (argc() > 1 && argv(1) === 'album') { // API: /embedphotos/album $name = (x($_POST,'name') ? $_POST['name'] : null ); if (! $name) { json_return_and_die(array('errormsg' => 'Error retrieving album', 'status' => false)); } - $album = $this->embedphotos_widget_album(array('channel_id' => local_channel(), 'album' => $name)); + $album = $this->embedphotos_widget_album(array('channel_id' => $channel_id, 'album' => $name)); json_return_and_die(array('status' => true, 'content' => $album)); } if (argc() > 1 && argv(1) === 'albumlist') { // API: /embedphotos/albumlist - $album_list = $this->embedphotos_album_list(); + $album_list = $this->embedphotos_album_list($channel_id); json_return_and_die(array('status' => true, 'albumlist' => $album_list)); } if (argc() > 1 && argv(1) === 'photolink') { @@ -38,7 +44,7 @@ class Embedphotos extends Controller { } $resource_id = array_pop(explode("/", $href)); - $x = self::photolink($resource_id); + $x = self::photolink($resource_id, $channel_id); if ($x) { json_return_and_die(array('status' => true, 'photolink' => $x, 'resource_id' => $resource_id)); } @@ -48,8 +54,14 @@ class Embedphotos extends Controller { } - protected static function photolink($resource) { - $channel = App::get_channel(); + protected static function photolink($resource, $channel_id = 0) { + if (intval($channel_id)) { + $channel = channelx_by_n($channel_id); + } + else { + $channel = App::get_channel(); + } + $output = EMPTY_STR; if ($channel) { $resolution = ((feature_enabled($channel['channel_id'],'large_photos')) ? 1 : 2); @@ -216,8 +228,9 @@ class Embedphotos extends Controller { return $o; } - function embedphotos_album_list() { - $p = photos_albums_list(App::get_channel(),App::get_observer()); + function embedphotos_album_list($channel_id) { + $channel = channelx_by_n($channel_id); + $p = photos_albums_list($channel,App::get_observer()); if ($p['success']) { return $p['albums']; } diff --git a/view/tpl/admin_cover_photo.tpl b/view/tpl/admin_cover_photo.tpl index 33a9f912b..26f32554c 100755 --- a/view/tpl/admin_cover_photo.tpl +++ b/view/tpl/admin_cover_photo.tpl @@ -14,7 +14,7 @@ }; var choosePhotoFromAlbum = function (album) { - $.post("embedphotos/album", {name: album}, + $.post("embedphotos/album/{{$channel_id}}", {name: album}, function(data) { if (data['status']) { $('#embedPhotoModalLabel').html("{{$modalchooseimages}}"); @@ -34,7 +34,7 @@ var imageparent = document.getElementById($(image).parent()[0].id); $(imageparent).toggleClass('embed-photo-selected-photo'); var href = $(imageparent).attr('href'); - $.post("embedphotos/photolink", {href: href}, + $.post("embedphotos/photolink/{{$channel_id}}", {href: href}, function(ddata) { if (ddata['status']) { window.location.href = 'admin/cover_photo/use/' + ddata['resource_id']; @@ -61,7 +61,7 @@ }; var getPhotoAlbumList = function () { - $.post("embedphotos/albumlist", {}, + $.post("embedphotos/albumlist/{{$channel_id}}", {}, function(data) { if (data['status']) { var albums = data['albumlist']; //JSON.parse(data['albumlist']); diff --git a/view/tpl/admin_profile_photo.tpl b/view/tpl/admin_profile_photo.tpl index 547d4e7d6..510c5ce3a 100644 --- a/view/tpl/admin_profile_photo.tpl +++ b/view/tpl/admin_profile_photo.tpl @@ -14,7 +14,7 @@ }; var choosePhotoFromAlbum = function (album) { - $.post("embedphotos/album", {name: album}, + $.post("embedphotos/album/{{$channel_id}}", {name: album}, function(data) { if (data['status']) { $('#embedPhotoModalLabel').html("{{$modalchooseimages}}"); @@ -34,7 +34,7 @@ var imageparent = document.getElementById($(image).parent()[0].id); $(imageparent).toggleClass('embed-photo-selected-photo'); var href = $(imageparent).attr('href'); - $.post("embedphotos/photolink", {href: href}, + $.post("embedphotos/photolink/{{$channel_id}}", {href: href}, function(ddata) { if (ddata['status']) { var pf = $('#profile-photo-profiles').val(); @@ -63,7 +63,7 @@ }; var getPhotoAlbumList = function () { - $.post("embedphotos/albumlist", {}, + $.post("embedphotos/albumlist/{{$channel_id}}", {}, function(data) { if (data['status']) { var albums = data['albumlist']; //JSON.parse(data['albumlist']); From 857c953a8af1197c0c66d9faee9d75cf0f3de12d Mon Sep 17 00:00:00 2001 From: nobody Date: Wed, 9 Sep 2020 21:04:19 -0700 Subject: [PATCH 08/12] revision --- boot.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot.php b/boot.php index ac705bab9..6ca97413d 100755 --- a/boot.php +++ b/boot.php @@ -16,7 +16,7 @@ use Zotlabs\Daemon\Run; * @brief This file defines some global constants and includes the central App class. */ -define ( 'STD_VERSION', '20.09.09' ); +define ( 'STD_VERSION', '20.09.10' ); define ( 'ZOT_REVISION', '6.0' ); define ( 'DB_UPDATE_VERSION', 1242 ); From 23099aeb39890bae21e405ce52b4490b45d58a52 Mon Sep 17 00:00:00 2001 From: nobody Date: Wed, 9 Sep 2020 21:11:45 -0700 Subject: [PATCH 09/12] incorrect attribution --- Zotlabs/Widget/Cover_photo.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Zotlabs/Widget/Cover_photo.php b/Zotlabs/Widget/Cover_photo.php index a4661746d..979d5806d 100644 --- a/Zotlabs/Widget/Cover_photo.php +++ b/Zotlabs/Widget/Cover_photo.php @@ -3,6 +3,7 @@ namespace Zotlabs\Widget; use App; +use Zotlabs\Lib\System; class Cover_photo { @@ -11,14 +12,18 @@ class Cover_photo { require_once('include/channel.php'); $o = ''; + if(\App::$module == 'channel' && $_REQUEST['mid']) return ''; $channel_id = 0; + $site_banner = false; + if (App::$module === 'home') { $channel = get_sys_channel(); $channel_id = $channel['channel_id']; + $site_banner = System::get_site_name(); } if(array_key_exists('channel_id', $arr) && intval($arr['channel_id'])) @@ -55,11 +60,18 @@ class Cover_photo { else $title = $channel['channel_name']; + if(array_key_exists('subtitle', $arr) && isset($arr['subtitle'])) $subtitle = $arr['subtitle']; else $subtitle = str_replace('@','@',$channel['xchan_addr']); + + if ($site_banner) { + $title = $site_banner; + $subtitle = ''; + } + $c = get_cover_photo($channel_id,'html'); if($c) { From 6e06c801e91a552ca9852cf667883bebf5563a70 Mon Sep 17 00:00:00 2001 From: nobody Date: Wed, 9 Sep 2020 21:23:01 -0700 Subject: [PATCH 10/12] include url on sites page to distinguish multiple sites with same sitename --- Zotlabs/Module/Sites.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Zotlabs/Module/Sites.php b/Zotlabs/Module/Sites.php index c567e4e9f..0b35d54b0 100644 --- a/Zotlabs/Module/Sites.php +++ b/Zotlabs/Module/Sites.php @@ -37,6 +37,9 @@ class Sites extends \Zotlabs\Web\Controller { $sitename = get_sconfig($rr['site_url'],'system','sitename',$rr['site_url']); + if ($sitename !== $rr['site_url']) { + $sitename .= ' (' . $rr['site_url'] . ')'; + } $disabled = (($access === 'private' || $register === 'closed') ? true : false); $logo = get_sconfig($rr['site_url'],'system','logo'); $about = get_sconfig($rr['site_url'],'system','about'); From 47dea5c53d2001f305a69e1d3f5c4a03b3709935 Mon Sep 17 00:00:00 2001 From: nobody Date: Wed, 9 Sep 2020 21:30:18 -0700 Subject: [PATCH 11/12] code comments --- Zotlabs/Module/Embedphotos.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Zotlabs/Module/Embedphotos.php b/Zotlabs/Module/Embedphotos.php index 95e89d003..cd4db4aa9 100644 --- a/Zotlabs/Module/Embedphotos.php +++ b/Zotlabs/Module/Embedphotos.php @@ -16,6 +16,11 @@ class Embedphotos extends Controller { * */ function post() { + + // The admin tools for setting a site logo and cover photo set the channel_id explicitly + // to the 'sys' channel and use stored resources for that channel. + // Legacy behaviour uses the local logged in channel. + if (argc() > 2 && is_site_admin() && intval(argv(2))) { $channel_id = argv(2); } From 65b2cf694513718800f52f4f4c76accfe72140cd Mon Sep 17 00:00:00 2001 From: nobody Date: Wed, 9 Sep 2020 22:25:39 -0700 Subject: [PATCH 12/12] label the list and group entries in the acl selector - we can't use icons here. --- include/acl_selectors.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/acl_selectors.php b/include/acl_selectors.php index a1b80d901..d3d32230a 100644 --- a/include/acl_selectors.php +++ b/include/acl_selectors.php @@ -86,7 +86,7 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti if($r) { foreach($r as $rr) { $selected = (($single_group && $rr['hash'] === $allow_gid[0]) ? ' selected = "selected" ' : ''); - $groups .= '' . "\r\n"; + $groups .= '' . "\r\n"; } } @@ -95,7 +95,7 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti if($forums) { foreach($forums as $f) { $selected = (($single_group && $f['hash'] === $allow_cid[0]) ? ' selected = "selected" ' : ''); - $groups .= '' . "\r\n"; + $groups .= '' . "\r\n"; } }