mirror of
https://codeberg.org/streams/streams.git
synced 2024-09-19 16:35:19 +00:00
refactor site customisation
This commit is contained in:
parent
1c62f7f5ad
commit
fa09727217
12 changed files with 1300 additions and 50 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
499
Zotlabs/Module/Admin/Cover_photo.php
Normal file
499
Zotlabs/Module/Admin/Cover_photo.php
Normal file
|
@ -0,0 +1,499 @@
|
|||
<?php
|
||||
namespace Zotlabs\Module\Admin;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\Libprofile;
|
||||
use Zotlabs\Access\AccessControl;
|
||||
use Zotlabs\Web\Controller;
|
||||
|
||||
/*
|
||||
@file cover_photo.php
|
||||
@brief Module-file with functions for handling of cover-photos
|
||||
|
||||
*/
|
||||
|
||||
require_once('include/attach.php');
|
||||
require_once('include/photo_factory.php');
|
||||
require_once('include/photos.php');
|
||||
|
||||
|
||||
|
||||
/* @brief Initalize the cover-photo edit view
|
||||
*
|
||||
* @param $a Current application
|
||||
* @return void
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
class Cover_photo {
|
||||
|
||||
function init() {
|
||||
if (! local_channel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$channel = App::get_channel();
|
||||
Libprofile::load($channel['channel_address']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Evaluate posted values
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
*/
|
||||
|
||||
function post() {
|
||||
|
||||
if (! local_channel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$channel = App::get_channel();
|
||||
|
||||
check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo');
|
||||
|
||||
if ((array_key_exists('cropfinal',$_POST)) && ($_POST['cropfinal'] == 1)) {
|
||||
|
||||
// phase 2 - we have finished cropping
|
||||
|
||||
if (argc() != 2) {
|
||||
notice( t('Image uploaded but image cropping failed.') . EOL );
|
||||
return;
|
||||
}
|
||||
|
||||
$image_id = argv(1);
|
||||
|
||||
if (substr($image_id,-2,1) == '-') {
|
||||
$scale = substr($image_id,-1,1);
|
||||
$image_id = substr($image_id,0,-2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
$srcX = intval($_POST['xstart']);
|
||||
$srcY = intval($_POST['ystart']);
|
||||
$srcW = intval($_POST['xfinal']) - $srcX;
|
||||
$srcH = intval($_POST['yfinal']) - $srcY;
|
||||
|
||||
$r = q("select gender from profile where uid = %d and is_default = 1 limit 1",
|
||||
intval(local_channel())
|
||||
);
|
||||
if ($r) {
|
||||
$profile = array_shift($r);
|
||||
}
|
||||
|
||||
$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())
|
||||
);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
534
Zotlabs/Module/Admin/Profile_photo.php
Normal file
534
Zotlabs/Module/Admin/Profile_photo.php
Normal file
|
@ -0,0 +1,534 @@
|
|||
<?php
|
||||
namespace Zotlabs\Module\Admin;
|
||||
|
||||
/*
|
||||
* @file Profile_photo.php
|
||||
* @brief Module-file with functions for uploading and scaling of profile-photos
|
||||
*
|
||||
*/
|
||||
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
use Zotlabs\Lib\Libprofile;
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Daemon\Run;
|
||||
|
||||
|
||||
require_once('include/photo_factory.php');
|
||||
require_once('include/photos.php');
|
||||
|
||||
|
||||
class Profile_photo {
|
||||
|
||||
|
||||
/* @brief Initalize the profile-photo edit view
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
*/
|
||||
|
||||
function init() {
|
||||
|
||||
if(! is_site_admin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$channel = get_sys_channel();
|
||||
Libprofile::load($channel['channel_address']);
|
||||
|
||||
}
|
||||
|
||||
/* @brief Evaluate posted values
|
||||
*
|
||||
* @param $a Current application
|
||||
* @return void
|
||||
*
|
||||
*/
|
||||
|
||||
function post() {
|
||||
|
||||
if (! is_site_admin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$channel = get_sys_channel();
|
||||
|
||||
check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo');
|
||||
|
||||
if ((array_key_exists('cropfinal',$_POST)) && (intval($_POST['cropfinal']) == 1)) {
|
||||
|
||||
// logger('crop: ' . print_r($_POST,true));
|
||||
|
||||
// phase 2 - we have finished cropping
|
||||
|
||||
if (argc() != 3) {
|
||||
notice( t('Image uploaded but image cropping failed.') . EOL );
|
||||
return;
|
||||
}
|
||||
|
||||
$image_id = argv(2);
|
||||
|
||||
if (substr($image_id,-2,1) == '-') {
|
||||
$scale = substr($image_id,-1,1);
|
||||
$image_id = substr($image_id,0,-2);
|
||||
}
|
||||
|
||||
// unless proven otherwise
|
||||
$is_default_profile = 1;
|
||||
|
||||
if ($_REQUEST['profile']) {
|
||||
$r = q("select id, profile_guid, is_default, gender from profile where id = %d and uid = %d limit 1",
|
||||
intval($_REQUEST['profile']),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
if ($r) {
|
||||
$profile = array_shift($r);
|
||||
if (! intval($profile['is_default'])) {
|
||||
$is_default_profile = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$srcX = intval($_POST['xstart']);
|
||||
$srcY = intval($_POST['ystart']);
|
||||
$srcW = intval($_POST['xfinal']) - $srcX;
|
||||
$srcH = intval($_POST['yfinal']) - $srcY;
|
||||
|
||||
$r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale = %d LIMIT 1",
|
||||
dbesc($image_id),
|
||||
dbesc($channel['channel_id']),
|
||||
intval($scale));
|
||||
if ($r) {
|
||||
|
||||
$base_image = array_shift($r);
|
||||
$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()) {
|
||||
|
||||
$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;
|
||||
}
|
||||
}
|
|
@ -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 ],
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
48
view/tpl/admin_cropbody.tpl
Normal file
48
view/tpl/admin_cropbody.tpl
Normal file
|
@ -0,0 +1,48 @@
|
|||
<h1>{{$title}}</h1>
|
||||
<p id="cropimage-desc">
|
||||
{{$desc}}
|
||||
</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 d-lg-none" style="height: 300px; width: 300px; max-width: 300px; max-height: 300px; overflow: hidden;"></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);
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<form action="admin/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>
|
195
view/tpl/admin_profile_photo.tpl
Normal file
195
view/tpl/admin_profile_photo.tpl
Normal file
|
@ -0,0 +1,195 @@
|
|||
<script src="vendor/blueimp/jquery-file-upload/js/vendor/jquery.ui.widget.js"></script>
|
||||
<script src="vendor/blueimp/jquery-file-upload/js/jquery.iframe-transport.js"></script>
|
||||
<script src="vendor/blueimp/jquery-file-upload/js/jquery.fileupload.js"></script>
|
||||
|
||||
|
||||
<script>
|
||||
var initializeEmbedPhotoDialog = function () {
|
||||
$('.embed-photo-selected-photo').each(function (index) {
|
||||
$(this).removeClass('embed-photo-selected-photo');
|
||||
});
|
||||
getPhotoAlbumList();
|
||||
$('#embedPhotoModalBodyAlbumDialog').off('click');
|
||||
$('#embedPhotoModal').modal('show');
|
||||
};
|
||||
|
||||
var choosePhotoFromAlbum = function (album) {
|
||||
$.post("embedphotos/album", {name: album},
|
||||
function(data) {
|
||||
if (data['status']) {
|
||||
$('#embedPhotoModalLabel').html("{{$modalchooseimages}}");
|
||||
$('#embedPhotoModalBodyAlbumDialog').html('\
|
||||
<div><div class="nav nav-pills flex-column">\n\
|
||||
<li class="nav-item"><a class="nav-link" href="#" onclick="initializeEmbedPhotoDialog();return false;">\n\
|
||||
<i class="fa fa-chevron-left"></i> \n\
|
||||
{{$modaldiffalbum}}\n\
|
||||
</a>\n\
|
||||
</li>\n\
|
||||
</div><br></div>')
|
||||
$('#embedPhotoModalBodyAlbumDialog').append(data['content']);
|
||||
$('#embedPhotoModalBodyAlbumDialog').click(function (evt) {
|
||||
evt.preventDefault();
|
||||
var image = document.getElementById(evt.target.id);
|
||||
if (typeof($(image).parent()[0]) !== 'undefined') {
|
||||
var imageparent = document.getElementById($(image).parent()[0].id);
|
||||
$(imageparent).toggleClass('embed-photo-selected-photo');
|
||||
var href = $(imageparent).attr('href');
|
||||
$.post("embedphotos/photolink", {href: href},
|
||||
function(ddata) {
|
||||
if (ddata['status']) {
|
||||
var pf = $('#profile-photo-profiles').val();
|
||||
var prof = ((typeof pf !== 'undefined') ? '?f=&pf=' + pf : '');
|
||||
window.location.href = 'admin/profile_photo/use/' + ddata['resource_id'] + prof;
|
||||
} else {
|
||||
window.console.log("{{$modalerrorlink}}" + ':' + ddata['errormsg']);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
'json');
|
||||
$('#embedPhotoModalBodyAlbumDialog').html('');
|
||||
$('#embedPhotoModalBodyAlbumDialog').off('click');
|
||||
$('#embedPhotoModal').modal('hide');
|
||||
}
|
||||
});
|
||||
|
||||
$('#embedPhotoModalBodyAlbumListDialog').addClass('d-none');
|
||||
$('#embedPhotoModalBodyAlbumDialog').removeClass('d-none');
|
||||
} else {
|
||||
window.console.log("{{$modalerroralbum}} " + JSON.stringify(album) + ':' + data['errormsg']);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
'json');
|
||||
};
|
||||
|
||||
var getPhotoAlbumList = function () {
|
||||
$.post("embedphotos/albumlist", {},
|
||||
function(data) {
|
||||
if (data['status']) {
|
||||
var albums = data['albumlist']; //JSON.parse(data['albumlist']);
|
||||
$('#embedPhotoModalLabel').html("{{$modalchoosealbum}}");
|
||||
$('#embedPhotoModalBodyAlbumList').html('<ul class="nav nav-pills flex-column"></ul>');
|
||||
for(var i=0; i<albums.length; i++) {
|
||||
var albumName = albums[i].text;
|
||||
var jsAlbumName = albums[i].jstext;
|
||||
var albumLink = '<li class="nav-item">';
|
||||
albumLink += '<a class="nav-link" href="#" onclick="choosePhotoFromAlbum(\'' + jsAlbumName + '\'); return false;">' + albumName + '</a>';
|
||||
albumLink += '</li>';
|
||||
$('#embedPhotoModalBodyAlbumList').find('ul').append(albumLink);
|
||||
}
|
||||
$('#embedPhotoModalBodyAlbumDialog').addClass('d-none');
|
||||
$('#embedPhotoModalBodyAlbumListDialog').removeClass('d-none');
|
||||
} else {
|
||||
window.console.log("{{$modalerrorlist}}" + ':' + data['errormsg']);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
'json');
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<input id="invisible-photos-file-upload" type="file" name="files" style="visibility:hidden;position:absolute;top:-50;left:-50;width:0;height:0;" >
|
||||
|
||||
|
||||
<div id="profile-photo-content" class="generic-content-wrapper">
|
||||
<div class="section-title-wrapper">
|
||||
<h2>{{$title}}</h2>
|
||||
</div>
|
||||
<div class="section-content-wrapper">
|
||||
|
||||
<form enctype="multipart/form-data" id="profile-photo-form" action="admin/profile_photo" method="post">
|
||||
<input type='hidden' name='form_security_token' value='{{$form_security_token}}'>
|
||||
|
||||
<div id="profile-photo-upload-wrapper">
|
||||
{{if $info}}
|
||||
<div class="section-content-warning-wrapper">{{$info}}</div>
|
||||
{{/if}}
|
||||
{{if $importfile}}
|
||||
<input type="hidden" name="importfile" value="{{$importfile}}">
|
||||
{{else}}
|
||||
<div id="profile-photo-upload-spinner" class="spinner-wrapper">
|
||||
<div class="spinner m"></div>
|
||||
</div>
|
||||
<!--label id="profile-photo-upload-label" class="form-label" for="profile-photo-upload">{{$lbl_upfile}}</label>
|
||||
<input name="userfile" class="form-input" type="file" id="profile-photo-upload" size="48" / -->
|
||||
{{/if}}
|
||||
<div class="clear"></div>
|
||||
|
||||
|
||||
{{if $single}}
|
||||
<input type="hidden" name="profile" value="{{$profile0.id}}" />
|
||||
{{else}}
|
||||
|
||||
|
||||
|
||||
<label id="profile-photo-profiles-label" class="form-label" for="profile-photo-profiles">{{$lbl_profiles}}</label>
|
||||
<select name="profile" id="profile-photo-profiles" class="form-control" >
|
||||
{{foreach $profiles as $p}}
|
||||
<option value="{{$p.id}}" {{if $p.selected}}selected="selected"{{/if}}>{{$p.name}}</option>
|
||||
{{/foreach}}
|
||||
</select>
|
||||
<div class="clear"></div>
|
||||
<br>
|
||||
<br>
|
||||
{{/if}}
|
||||
|
||||
<div id="profile-photo-submit-wrapper">
|
||||
<input type="submit" name="submit" id="profile-photo-submit" value="{{$submit}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
<br>
|
||||
<div id="profile-photo-link-select-wrapper">
|
||||
<button id="embed-photo-wrapper" class="btn btn-default btn-primary" title="{{$embedPhotos}}" onclick="initializeEmbedPhotoDialog();return false;">
|
||||
<i id="embed-photo" class="fa fa-file-image-o"></i> {{$select}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('#invisible-photos-file-upload').fileupload({
|
||||
url: 'admin/profile_photo',
|
||||
dataType: 'json',
|
||||
dropZone: $('#profile-photo-content'),
|
||||
maxChunkSize: 2 * 1024 * 1024,
|
||||
|
||||
add: function(e,data) {
|
||||
data.formData = $('#profile-photo-form').serializeArray();
|
||||
data.submit();
|
||||
$('#profile-photo-upload-spinner').show();
|
||||
},
|
||||
|
||||
done: function(e,data) {
|
||||
$('#profile-photo-upload-spinner').hide();
|
||||
window.location.href = window.location.href + '/use/' + data.result.message;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$('#profile-photo-submit').click(function(event) { event.preventDefault(); $('#invisible-photos-file-upload').trigger('click'); return false;});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<div class="modal" id="embedPhotoModal" tabindex="-1" role="dialog" aria-labelledby="embedPhotoLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="embedPhotoModalLabel">{{$embedPhotosModalTitle}}</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
</div>
|
||||
<div class="modal-body" id="embedPhotoModalBody" >
|
||||
<div id="embedPhotoModalBodyAlbumListDialog" class="d-none">
|
||||
<div id="embedPhotoModalBodyAlbumList"></div>
|
||||
</div>
|
||||
<div id="embedPhotoModalBodyAlbumDialog" class="d-none"></div>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
|
@ -55,7 +55,6 @@
|
|||
<div id="basic-settings-collapse" class="collapse show" role="tabpanel" aria-labelledby="basic-settings" data-parent="#settings">
|
||||
<div class="section-content-tools-wrapper">
|
||||
{{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}}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="project-banner" title="{{$project_title}}"><a href="{{$baseurl}}/siteinfo"><img src="{{$project_icon}}" alt="{{$project_title}}"></a></div>
|
||||
<div class="project-banner" title="{{$project_title}}"><a href="{{$baseurl}}/siteinfo"><img src="{{$project_icon}}" alt="{{$project_title}}" class="nav-avatar"></a></div>
|
||||
{{if $nav.login && !$userinfo}}
|
||||
<div class="d-lg-none pt-1 pb-1">
|
||||
{{if $nav.loginmenu.1.4}}
|
||||
|
|
Loading…
Reference in a new issue