diff --git a/.htaccess b/.htaccess index 2e0e58575..cb5cba8cc 100644 --- a/.htaccess +++ b/.htaccess @@ -1,5 +1,6 @@ Options -Indexes +AddType application/x-java-archive .jar RewriteEngine on diff --git a/database.sql b/database.sql index 93d793cd0..8493e9d14 100644 --- a/database.sql +++ b/database.sql @@ -40,9 +40,9 @@ CREATE TABLE IF NOT EXISTS `contact` ( `id` int(11) NOT NULL AUTO_INCREMENT, `uid` int(11) NOT NULL COMMENT 'owner uid', `created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', - `self` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'boolean 1 == info for local UID, primarily name and photo to use in item displays.', + `self` tinyint(1) NOT NULL DEFAULT '0', `name` char(255) NOT NULL, - `photo` text NOT NULL COMMENT 'remote photo URL initially until approved', + `photo` text NOT NULL, `thumb` text NOT NULL, `site-pubkey` text NOT NULL, `issued-id` char(255) NOT NULL, @@ -64,9 +64,9 @@ CREATE TABLE IF NOT EXISTS `contact` ( `blocked` tinyint(1) NOT NULL DEFAULT '1', `readonly` tinyint(1) NOT NULL DEFAULT '0', `pending` tinyint(1) NOT NULL DEFAULT '1', - `rating` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0-5 reputation, 0 unknown, 1 call police, 5 inscrutable', - `reason` text NOT NULL COMMENT 'why a rating was given - will help friends decide to make friends or not', - `profile-id` int(11) NOT NULL DEFAULT '0' COMMENT 'which profile to display - 0 is public default', + `rating` tinyint(1) NOT NULL DEFAULT '0', + `reason` text NOT NULL, + `profile-id` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; @@ -141,6 +141,8 @@ CREATE TABLE IF NOT EXISTS `item` ( `title` char(255) NOT NULL, `body` text NOT NULL, `resource-id` char(255) NOT NULL, + `like` mediumtext NOT NULL, + `tag` mediumtext NOT NULL, `allow_cid` mediumtext NOT NULL, `allow_gid` mediumtext NOT NULL, `deny_cid` mediumtext NOT NULL, diff --git a/jumploader_z.jar b/jumploader_z.jar new file mode 100644 index 000000000..30a85a33f Binary files /dev/null and b/jumploader_z.jar differ diff --git a/mod/photos.php b/mod/photos.php new file mode 100644 index 000000000..4a502b9fb --- /dev/null +++ b/mod/photos.php @@ -0,0 +1,423 @@ +argc > 1) { + $nick = $a->argv[1]; + $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' LIMIT 1", + dbesc($nick) + ); + + if(! count($r)) + return; + + $a->data['user'] = $r[0]; + + $albums = q("SELECT distinct(`album`) AS `album` FROM `photo` WHERE `uid` = %d", + intval($a->data['user']['uid']) + ); + + if(count($albums)) { + $a->data['albums'] = $albums; + + $o .= '

' . $a->data['user']['username'] . '

'; + $o .= '

' . '' . t('Photo Albums') . '

'; + + $o .= ''; + } + $a->page['aside'] .= $o; + } + + +} + + + + +function photos_post(&$a) { + + + if(! local_user()) { + notice( t('Permission denied.') . EOL ); + killme(); + } + + $r = q("SELECT * FROM `contact` LEFT JOIN `user` ON `user`.`uid` = `contact`.`uid` WHERE `user`.`uid` = %d AND `self` = 1 LIMIT 1", + intval($_SESSION['uid']) + ); + + $contact_record = $r[0]; + + if(! x($_FILES,'userfile')) + killme(); + + if($_POST['partitionCount']) + $java_upload = true; + else + $java_upload = false; + + $album = notags(trim($_POST['album'])); + $newalbum = notags(trim($_POST['newalbum'])); + + if(! strlen($album)) { + if(strlen($newalbum)) + $album = $newalbum; + else + $album = datetime_convert('UTC',date_default_timezone_get(),'now', 'Y'); + } + + $src = $_FILES['userfile']['tmp_name']; + $filename = basename($_FILES['userfile']['name']); + $filesize = intval($_FILES['userfile']['size']); + + $imagedata = @file_get_contents($src); + $ph = new Photo($imagedata); + + if(! ($image = $ph->getImage())) { + notice( t('Unable to process image.') . EOL ); + @unlink($src); + killme(); + } + + @unlink($src); + + $width = $ph->getWidth(); + $height = $ph->getHeight(); + + $smallest = 0; + + $photo_hash = hash('md5',uniqid(mt_rand(),true)); + + $r = $ph->store($_SESSION['uid'], 0, $photo_hash, $filename, $album, 0 ); + + if(! $r) { + notice( t('Image upload failed.') . EOL ); + killme(); + } + + if($width > 640 || $height > 640) { + $ph->scaleImage(640); + $ph->store($_SESSION['uid'], 0, $photo_hash, $filename, $album, 1 ); + $smallest = 1; + } + + if($width > 320 || $height > 320) { + $ph->scaleImage(320); + $ph->store($_SESSION['uid'], 0, $photo_hash, $filename, $album, 2 ); + $smallest = 2; + } + + $basename = basename($filename); + + // Create item container + + $body = '[url=' . $a->get_baseurl() . '/photos/' . $contact_record['nickname'] . '/image/' . $photo_hash . ']' + . '[img]' . $a->get_baseurl() . "/photo/{$photo_hash}-{$smallest}.jpg" . '[/img]' + . '[/url]'; + + do { + $dups = false; + $item_hash = random_string(); + + $uri = "urn:X-dfrn:" . $a->get_hostname() . ':' . $profile_uid . ':' . $item_hash; + + $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' LIMIT 1", + dbesc($uri)); + if(count($r)) + $dups = true; + } while($dups == true); + + + $r = q("INSERT INTO `item` (`uid`, `type`, `resource-id`, `contact-id`,`owner-name`,`owner-link`,`owner-avatar`, `created`, + `edited`, `uri`, `parent-uri`, `title`, `body`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid`) + VALUES( %d, '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", + intval($_SESSION['uid']), + dbesc('photo'), + dbesc($photo_hash), + intval($contact_record['id']), + dbesc($contact_record['name']), + dbesc($contact_record['url']), + dbesc($contact_record['thumb']), + datetime_convert(), + datetime_convert(), + dbesc($uri), + dbesc($uri), + dbesc($title), + dbesc($body), + dbesc($str_contact_allow), + dbesc($str_group_allow), + dbesc($str_contact_deny), + dbesc($str_group_deny) + + ); + if($r) { + + $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' LIMIT 1", + dbesc($uri) + ); + if(count($r)) + q("UPDATE `item` SET `parent` = %d, `last-child` = 1 WHERE `id` = %d LIMIT 1", + intval($r[0]['id']), + intval($r[0]['id']) + ); + + } + + // if album has no featured photo, promote one. + + + if(! $java_upload) { + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + return; // NOTREACHED + } + + killme(); + return; // NOTREACHED + +} + + + +function photos_content(&$a) { + + // URLs: + // photos/name + // photos/name/upload + // photos/name/album/xxxxx + // photos/name/album/xxxxx/edit + // photos/name/album/xxxxx/drop + // photos/name/image/xxxxx + // photos/name/image/xxxxx/edit + // photos/name/image/xxxxx/drop + + if(! x($a->data,'user')) { + notice( t('No photos selected') . EOL ); + return; + } + + $_SESSION['photo_return'] = $a->cmd; + + // + // Parse arguments + // + + if($a->argc > 3) { + $datatype = $a->argv[2]; + $datum = $a->argv[3]; + } + elseif(($a->argc > 2) && ($a->argv[2] == 'upload')) + $datatype = 'upload'; + else + $datatype = 'summary'; + + if($a->argc > 4) + $cmd = $a->argv[4]; + else + $cmd = 'view'; + + // + // Setup permissions structures + // + + $owner_uid = $a->data['user']['uid']; + + if(remote_user()) { + $contact_id = $_SESSION['visitor_id']; + $groups = init_groups_visitor($contact_id); + } + + // default permissions - anonymous user + + $sql_extra = " AND `allow_cid` = '' AND `allow_gid` = '' AND `deny_cid` = '' AND `deny_gid` = '' "; + + // Profile owner - everything is visible + + if(local_user() && ($_SESSION['uid'] == $owner_uid)) { + $sql_extra = ''; + } + elseif(remote_user()) { + // authenticated visitor - here lie dragons + $gs = '<<>>'; // should be impossible to match + if(count($groups)) { + foreach($groups as $g) + $gs .= '|<' . intval($g) . '>'; + } + $sql_extra = sprintf( + " AND ( `allow_cid` = '' OR `allow_cid` REGEXP '<%d>' ) + AND ( `deny_cid` = '' OR NOT `deny_cid` REGEXP '<%d>' ) + AND ( `allow_gid` = '' OR `allow_gid` REGEXP '%s' ) + AND ( `deny_gid` = '' OR NOT `deny_gid` REGEXP '%s') ", + + intval($_SESSION['visitor_id']), + intval($_SESSION['visitor_id']), + dbesc($gs), + dbesc($gs) + ); + } + + // + // dispatch request + // + + + if($datatype == 'upload') { + if( ! (local_user() && ($_SESSION['uid'] == $a->data['user']['uid']))) { + notice( t('Permission denied.')); + return; + } + $albumselect = ''; + $tpl = file_get_contents('view/photos_upload.tpl'); + $o .= replace_macros($tpl,array( + '$pagename' => t('Upload Photos'), + '$sessid' => session_id(), + '$newalbum' => t('New album name: '), + '$existalbumtext' => t('or existing album name: '), + '$filestext' => t('Select files to upload: '), + '$albumselect' => $albumselect, + '$archive' => $a->get_baseurl() . '/jumploader_z.jar', + '$nojava' => t('Use the following controls only if the Java uploader (above) fails to launch.'), + '$uploadurl' => $a->get_baseurl() . '/photos', + '$submit' => t('Submit') + )); + + return $o; + + } + + if($datatype == 'album') { + + $album = hex2bin($datum); + + $r = q("SELECT `resource-id`, max(`scale`) AS `scale` FROM `photo` WHERE `uid` = %d AND `album` = '%s' + $sql_extra GROUP BY `resource-id`", + intval($a->data['user']['uid']), + dbesc($album) + ); + if(count($r)) + $a->set_pager_total(count($r)); + + + $r = q("SELECT `resource-id`, max(`scale`) AS `scale` FROM `photo` WHERE `uid` = %d AND `album` = '%s' + $sql_extra GROUP BY `resource-id` LIMIT %d , %d", + intval($a->data['user']['uid']), + dbesc($album), + intval($a->pager['start']), + intval($a->pager['itemspage']) + ); + + $o .= '

' . $album . '

'; + + $tpl = file_get_contents('view/photo_album.tpl'); + if(count($r)) + foreach($r as $rr) { + $o .= replace_macros($tpl,array( + '$id' => $rr['id'], + '$photolink' => $a->get_baseurl() . '/photos/' . $a->data['user']['nickname'] . '/image/' . $rr['resource-id'], + '$phototitle' => t('View Photo'), + '$imgsrc' => $a->get_baseurl() . '/photo/' . $rr['resource-id'] . '-' . $rr['scale'] . '.jpg', + '$imgalt' => $rr['filename'] + )); + + } + $o .= '
'; + return $o; + + } + + + if($datatype == 'image') { + + // fetch item containing image, then comments + $r = q("SELECT * FROM `photo` WHERE `uid` = %d AND `resource-id` = '%s' + $sql_extra ORDER BY `scale` ASC ", + intval($a->data['user']['uid']), + dbesc($datum) + ); + + if(! count($r)) { + notice( t('Photo not available') . EOL ); + return; + } + + if(count($r) == 1) + $hires = $lores = $r[0]; + if(count($r) > 1) { + $hires = $r[0]; + $lores = $r[1]; + } + + $o .= ''; + + + return $o; + } + + // Default - show recent photos with upload link (if applicable) + + $r = q("SELECT `resource-id`, max(`scale`) AS `scale` FROM `photo` WHERE `uid` = %d AND `album` != '%s' + $sql_extra GROUP BY `resource-id`", + intval($a->data['user']['uid']), + dbesc( t('Contact Photos')) + ); + if(count($r)) + $a->set_pager_total(count($r)); + + + $r = q("SELECT `resource-id`, `album`, max(`scale`) AS `scale` FROM `photo` WHERE `uid` = %d AND `album` != '%s' + $sql_extra GROUP BY `resource-id` ORDER BY `created` DESC LIMIT %d , %d", + intval($a->data['user']['uid']), + dbesc( t('Contact Photos')), + intval($a->pager['start']), + intval($a->pager['itemspage']) + ); + + $o .= '

' . t('Recent Photos') . '

'; + + if( local_user() && ($_SESSION['uid'] == $a->data['user']['uid'])) { + $o .= ''; + } + + $tpl = file_get_contents('view/photo_top.tpl'); + if(count($r)) { + foreach($r as $rr) { + $o .= replace_macros($tpl,array( + '$id' => $rr['id'], + '$photolink' => $a->get_baseurl() . '/photos/' . $a->data['user']['nickname'] + . '/image/' . $rr['resource-id'], + '$phototitle' => t('View Photo'), + '$imgsrc' => $a->get_baseurl() . '/photo/' + . $rr['resource-id'] . '-' . $rr['scale'] . '.jpg', + '$albumlink' => $a->get_baseurl . '/photos/' + . $a->data['user']['nickname'] . '/album/' . bin2hex($rr['album']), + '$albumname' => $rr['album'], + '$albumalt' => t('View Album'), + '$imgalt' => $rr['filename'] + )); + + } + $o .= '
'; + } + return $o; +} diff --git a/mod/profile.php b/mod/profile.php index 07c5357ff..c8cfc4edd 100644 --- a/mod/profile.php +++ b/mod/profile.php @@ -106,7 +106,8 @@ function profile_content(&$a, $update = false) { $tpl = file_get_contents('view/profile_tabs.tpl'); $o .= replace_macros($tpl,array( - '$url' => $a->get_baseurl() . '/' . $a->cmd + '$url' => $a->get_baseurl() . '/' . $a->cmd, + '$phototab' => $a->get_baseurl() . '/photos/' . $a->profile['nickname'] )); diff --git a/view/photo_album.tpl b/view/photo_album.tpl new file mode 100644 index 000000000..323a9cdff --- /dev/null +++ b/view/photo_album.tpl @@ -0,0 +1,5 @@ + +
+ $imgalt +
+
diff --git a/view/photo_top.tpl b/view/photo_top.tpl new file mode 100644 index 000000000..e2ebb6fd5 --- /dev/null +++ b/view/photo_top.tpl @@ -0,0 +1,6 @@ + +
+ $imgalt + +
+
diff --git a/view/photos_upload.tpl b/view/photos_upload.tpl new file mode 100644 index 000000000..36e1780d5 --- /dev/null +++ b/view/photos_upload.tpl @@ -0,0 +1,53 @@ +

$pagename

+
+
+
+ +
+ +
+
+
+
$existalbumtext
+ $albumselect +
+
+ +
$filestext
+ +
+ + + + + + + + + + + + + + + + +
+ +
+ $nojava +
+ + + +
+ +
+
+
+ diff --git a/view/profile_tabs.tpl b/view/profile_tabs.tpl index bb459a2c2..0877edd73 100644 --- a/view/profile_tabs.tpl +++ b/view/profile_tabs.tpl @@ -2,5 +2,5 @@
Status Profile - Photos + Photos
diff --git a/view/style.css b/view/style.css index ba5e55e6f..77f3d12c9 100644 --- a/view/style.css +++ b/view/style.css @@ -1217,4 +1217,64 @@ input#dfrn-url { } #sidebar-group-list li { - margin-top: 10px; \ No newline at end of file + margin-top: 10px; +} + +.photo-album-image-wrapper { + float: left; + margin-top: 15px; + height: 350px; + width: 350px; +} + +#photo-album-end { + clear: both; +} + +.photo-top-image-wrapper { + float: left; + margin-top: 15px; + height: 350px; + width: 350px; +} + +#photo-top-end { + clear: both; +} + +#photo-top-links { + margin-bottom: 30px; + margin-left: 30px; +} + +#photos-upload-newalbum-div { + float: left; + width: 175px; +} +#photos-upload-existing-album-text { + float: left; + width: 175px; +} +#photos-upload-newalbum { + float: left; +} +#photos-upload-album-select { + float: left; +} +#photos-upload-new-end, #photos-upload-exist-end { + clear: both; +} +#photos-upload-exist-end { + margin-bottom: 15px; +} +#photos-upload-submit { + margin-top: 15px; +} + +#photos_upload_applet_wrapper { + margin-bottom: 15px; +} + +#photos-upload-no-java-message { + margin-bottom: 15px; +} \ No newline at end of file