diff --git a/db/libdb.pm.in b/db/libdb.pm.in index f3eb394f0522cba4692d87874d6808051a158456..2b1df6173927115de8ee17d37c4a65b2e64c3ee0 100644 --- a/db/libdb.pm.in +++ b/db/libdb.pm.in @@ -842,19 +842,22 @@ sub TBImageIDAccessCheck($$$) # No GIDs yet. # my $query_result = - DBQueryFatal("SELECT pid,shared FROM images WHERE imageid='$imageid'"); + DBQueryFatal("SELECT pid,gid,shared,global FROM images ". + "WHERE imageid='$imageid'"); if ($query_result->numrows == 0) { return 0; } my @row = $query_result->fetchrow_array(); my $pid = $row[0]; - my $shared = $row[1]; + my $gid = $row[1]; + my $shared = $row[2]; + my $global = $row[3]; # # Global ImageIDs can be read by anyone. # - if ($shared) { + if ($global) { if ($access_type == TB_IMAGEID_READINFO) { return 1; } @@ -866,12 +869,18 @@ sub TBImageIDAccessCheck($$$) # if ($access_type == TB_IMAGEID_READINFO) { $mintrust = PROJMEMBERTRUST_USER; + # + # Shared imageids are readable by anyone in the project. + # + if ($shared) { + $gid = $pid; + } } else { $mintrust = PROJMEMBERTRUST_LOCALROOT; } - return TBMinTrust(TBProjTrust($uid, $pid), $mintrust); + return TBMinTrust(TBGrpTrust($uid, $pid, $gid), $mintrust); } # diff --git a/sql/database-create.sql b/sql/database-create.sql index fcdf0cd004e68ba2b6cd0bb02b3a654159aff05f..6b2f89ac302f965670ba4fbef871f9857400f468 100644 --- a/sql/database-create.sql +++ b/sql/database-create.sql @@ -303,6 +303,7 @@ CREATE TABLE iface_counters ( CREATE TABLE images ( imagename varchar(30) NOT NULL default '', pid varchar(12) NOT NULL default '', + gid varchar(12) NOT NULL default '', imageid varchar(45) NOT NULL default '', creator varchar(8) default NULL, created datetime default NULL, @@ -320,10 +321,12 @@ CREATE TABLE images ( load_busy tinyint(4) NOT NULL default '0', ezid tinyint(4) NOT NULL default '0', shared tinyint(4) NOT NULL default '0', + global tinyint(4) NOT NULL default '0', updated datetime default NULL, max_concurrent int(11) default NULL, PRIMARY KEY (imagename,pid), KEY imageid (imageid) + KEY gid (gid) ) TYPE=MyISAM; -- diff --git a/sql/database-migrate.txt b/sql/database-migrate.txt index a182d4855ebb37731985cc1ed3ccd58e7bb33aa0..82f75898e30202461a9bdd03b755d117a24e1dc8 100644 --- a/sql/database-migrate.txt +++ b/sql/database-migrate.txt @@ -104,3 +104,16 @@ last_net_act,last_cpu_act,last_ext_act); user_pubkeys_new to user_pubkeys; drop table user_pubkeys_old; +1.120: Add gid slot to images table for per-subgroup image support + Also add global global flag, to replace shared flag. Global + means testbed wide, while shared means within a project. To + migrate an existing DB, just need to set pid=gid,global=shared + for all existing images, and then set shared=0. + + alter table images add gid varchar(12) NOT NULL default '' after pid; + alter table images add INDEX (gid); + alter table images add global tinyint(4) NOT NULL default '0' \ + after shared; + update images set gid=pid,global=shared; + update images set shared=0; + diff --git a/tbsetup/os_load.in b/tbsetup/os_load.in index dfd29d8cadc6640b3859a1ab81cd29f034a2ceae..f1351f7a549c3ada73ddf3bcda06252f304c3cad 100755 --- a/tbsetup/os_load.in +++ b/tbsetup/os_load.in @@ -196,7 +196,6 @@ foreach my $node (@nodes) { my $loadlen = $imageid_row{'loadlength'}; my $imagepath = $imageid_row{'path'}; my $defosid = $imageid_row{'default_osid'}; - my $shared = $imageid_row{'shared'}; my $max_concurrent = $imageid_row{'max_concurrent'}; # Check for a few errors early! @@ -248,15 +247,6 @@ foreach my $node (@nodes) { if ($loadpart) { $diskpart = "wd0:s${loadpart}"; } else {$diskpart = "wd0"; } - # For now, all testbed default images come from boss and all pid specific - # images come from ops:/proj. - if (! $shared && $mereuser) { - if (! ($imagepath =~ /^\/proj\//)) { - die("*** $0:\n". - " Your image must reside in /proj\n"); - } - } - print STDOUT "Changing default OS for $node to $defosid\n"; if (!$TESTMODE) { system("$osselect -m PXEBOOT $node"); @@ -444,7 +434,7 @@ sub dolisting() { $query_result = DBQueryFatal("select distinct i.* from images as i ". "left join group_membership as g on g.pid=i.pid ". - "where g.uid='$me' or i.shared ". + "where g.uid='$me' or i.global ". "order by i.pid,i.imageid"); } else { $query_result = diff --git a/utils/create_image.in b/utils/create_image.in index 9f483bdb3e7f5e5f7c81972f9d65fd4cd4155530..a058058711f72d1ef26db12dc0e83b476665066d 100755 --- a/utils/create_image.in +++ b/utils/create_image.in @@ -32,7 +32,6 @@ my $TB = "@prefix@"; my $TBOPS = "@TBOPSEMAIL@"; my $TBLOGS = "@TBLOGSEMAIL@"; my $BOSSNODE = "@BOSSNODE@"; -my $PROJROOT = "/proj"; my $TFTPDIR = "/tftpboot"; # @@ -170,9 +169,8 @@ if ($mereuser && } # -# Make sure that the filename is a /proj/$pid filename and a directory that -# exists and is writeable for the user. We test this by creating the file. -# Its going to get wiped anyway. +# Make sure that the directory exists and is writeable for the user. +# We test this by creating the file. Its going to get wiped anyway. # my $filename = $imageid_row{'path'}; @@ -184,9 +182,6 @@ else { fatal("Bad filename: $filename"); } -if (! ($filename =~ /^$PROJROOT\/$pid\/.*/)) { - fatal("File $filename for must reside someplace in $PROJROOT/$pid\n"); -} open(FILE, "> $filename") or fatal("Could not create $filename: $!"); close(FILE) or diff --git a/www/dbdefs.php3.in b/www/dbdefs.php3.in index d4db57001c1bfc7a0d76ed15824c76824309bd52..34a584181dd2dcbc13f8d3b8ec33b0d7d1ca1c95 100644 --- a/www/dbdefs.php3.in +++ b/www/dbdefs.php3.in @@ -721,23 +721,23 @@ function TBImageIDAccessCheck($uid, $imageid, $access_type) return 1; } - # - # No GIDs yet. - # $query_result = - DBQueryFatal("SELECT pid,shared FROM images WHERE imageid='$imageid'"); + DBQueryFatal("SELECT pid,gid,shared,global FROM images ". + "WHERE imageid='$imageid'"); if (mysql_num_rows($query_result) == 0) { return 0; } $row = mysql_fetch_array($query_result); $shared = $row[shared]; + $global = $row["global"]; $pid = $row[pid]; + $gid = $row[gid]; # # Global ImageIDs can be read by anyone but written by Admins only. # - if ($shared) { + if ($global) { if ($access_type == $TB_IMAGEID_READINFO) { return 1; } @@ -749,12 +749,17 @@ function TBImageIDAccessCheck($uid, $imageid, $access_type) # if ($access_type == $TB_IMAGEID_READINFO) { $mintrust = $TBDB_TRUST_USER; + # + # Shared imageids are readable by anyone in the project. + # + if ($shared) + $gid = $pid; } else { $mintrust = $TBDB_TRUST_LOCALROOT; } - return TBMinTrust(TBProjTrust($uid, $pid), $mintrust); + return TBMinTrust(TBGrpTrust($uid, $pid, $gid), $mintrust); } # diff --git a/www/editimageid.php3 b/www/editimageid.php3 index 6afb15a995d7187bb782cdc6d5e062160f01e820..cd9871a0a579d446b0ef7121e509784c850c6fca 100644 --- a/www/editimageid.php3 +++ b/www/editimageid.php3 @@ -1,7 +1,7 @@ function SetPrefix(theform) { - var idx = theform['formfields[pid]'].selectedIndex; - var pid = theform['formfields[pid]'].options[idx].value; - - if (pid == '') { - theform['formfields[path]'].value = '/proj/'; + var pidx = theform['formfields[pid]'].selectedIndex; + var pid = theform['formfields[pid]'].options[pidx].value; + var gidx = theform['formfields[gid]'].selectedIndex; + var gid = theform['formfields[gid]'].options[gidx].value; + var shared = theform['formfields[shared]'].checked; + \n"; + if ($isadmin) + echo "var global = theform['formfields[global]'].checked;"; + else + echo "var global = 0;"; + + echo "if (pid == '') { + theform['formfields[path]'].value = '/proj'; } else if (theform['formfields[imagename]'].value == '') { theform['formfields[imagename]'].defaultValue = ''; - theform['formfields[path]'].value = - '/proj/' + pid + '/images/'; + + if (global) { + theform['formfields[path]'].value = + '/usr/testbed/images/'; + } + else if (gid == '' || gid == pid || shared) { + theform['formfields[path]'].value = + '/proj/' + pid + '/images/'; + } + else { + theform['formfields[path]'].value = + '/groups/' + pid + '/' + gid + '/'; + } } else if (theform['formfields[imagename]'].value != '') { - theform['formfields[path]'].value = - '/proj/' + pid + '/images/' + - theform['formfields[imagename]'].value + '.ndz'; + var filename = theform['formfields[imagename]'].value + + '.ndz'; + + if (global) { + theform['formfields[path]'].value = + '/usr/testbed/images/' + filename; + } + else if (gid == '' || gid == pid || shared) { + theform['formfields[path]'].value = + '/proj/' + pid + '/images/' + filename; + } + else { + theform['formfields[path]'].value = + '/groups/' + pid + '/' + gid + '/' + + filename; + } } } \n"; @@ -179,6 +211,38 @@ function SPITFORM($formfields, $errors) echo " \n"; + # + # Select a group + # + echo " + Group: + + + \n"; + # # Image Name: # @@ -311,20 +375,41 @@ function SPITFORM($formfields, $errors) \n"; + # + # Shared? + # + echo " + Shared?:
+ (available to all subgroups) + + Yes + + \n"; + if ($isadmin) { # - # Shared? + # Global? # echo " - Shared?:
+ Global?:
(available to all projects) Yes @@ -395,6 +480,32 @@ if (! $submit) { $defaults = array(); $defaults[loadpart] = "X"; $defaults[path] = "/proj/"; + + # + # For users that are in one project and one subgroup, it is usually + # the case that they should use the subgroup, and since they also tend + # to be in the clueless portion of our users, give them some help. + # + if (count($projlist) == 1) { + list($project, $grouplist) = each($projlist); + + if (count($grouplist) <= 2) { + $defaults[pid] = $project; + if (count($grouplist) == 1 || strcmp($project, $grouplist[0])) + $group = $grouplist[0]; + else { + $group = $grouplist[1]; + } + $defaults[gid] = $group; + + if (!strcmp($project, $group)) + $defaults[path] = "/proj/$project/images/"; + else + $defaults[path] = "/groups/$project/$group/"; + } + reset($projlist); + } + SPITFORM($defaults, 0); PAGEFOOTER(); return; @@ -526,6 +637,26 @@ else { $errors["Boot OS"] = "Invalid; Must be one of the partitions"; } +# +# Only admin types can set the global bit for an image. Ignore silently. +# +$global = 0; +if ($isadmin && + isset($formfields["global"]) && + strcmp($formfields["global"], "Yep") == 0) { + $global = 1; +} + +$shared = 0; +if (isset($formfields[shared]) && + strcmp($formfields[shared], "Yep") == 0) { + $shared = 1; +} +# Does not make sense to do this. +if ($global && $shared) { + $errors["Global"] = "Image declared both shared and global"; +} + # # The path must not contain illegal chars and it must be more than # the original /proj/$pid we gave the user. We allow admins to specify @@ -538,14 +669,20 @@ if (!isset($formfields[path]) || elseif (! ereg("^[-_a-zA-Z0-9\/\.+]+$", $formfields[path])) { $errors["Path"] = "Contains invalid characters"; } -else { - $pdef = "/proj/$formfields[pid]/"; - - if (strcmp($formfields[path], "$pdef") == 0) { - $errors["Path"] = "Incomplete Path"; +elseif (! $isadmin) { + $pdef = ""; + + if (!$shared && + isset($formfields[gid]) && + strcmp($formfields[gid], "") && + strcmp($formfields[gid], $formfields[pid])) { + $pdef = "/groups/" . $formfields[pid] . "/" . $formfields[gid] . "/"; + } + else { + $pdef = "/proj/" . $formfields[pid] . "/images/"; } - elseif (!$isadmin && - strcmp(substr($formfields[path], 0, strlen($pdef)), $pdef)) { + + if (strpos($formfields[path], $pdef) === false) { $errors["Path"] = "Invalid Path"; } } @@ -589,16 +726,6 @@ if (isset($formfields[node]) && $node = $formfields[node]; } -# -# If any errors, respit the form with the current values and the -# error messages displayed. Iterate until happy. -# -if (count($errors)) { - SPITFORM($formfields, $errors); - PAGEFOOTER(); - return; -} - # # Only admins have this option. Always on for mereusers, but default off # for admins. @@ -612,14 +739,13 @@ if (! $isadmin || } # -# Only admin types can set the shared bit for an image. Ignore silently. -# -$shared = 0; - -if ($isadmin && - isset($formfields[shared]) && - strcmp($formfields[shared], "Yep") == 0) { - $shared = 1; +# If any errors, respit the form with the current values and the +# error messages displayed. Iterate until happy. +# +if (count($errors)) { + SPITFORM($formfields, $errors); + PAGEFOOTER(); + return; } # @@ -627,11 +753,15 @@ if ($isadmin && # $description = addslashes($formfields[description]); $pid = $formfields[pid]; +$gid = $formfields[gid]; $imagename = $formfields[imagename]; $loadpart = $formfields[loadpart]; $loadlength = $formfields[loadlength]; $default_osid= $formfields[default_osid]; $path = $formfields[path]; +if (!isset($gid) || !strcmp($gid, "")) { + $gid = $pid; +} # # And insert the record! @@ -733,12 +863,12 @@ $query_result = DBQueryFatal("INSERT INTO images ". "(imagename, imageid, description, loadpart, loadlength, ". " part1_osid, part2_osid, part3_osid, part4_osid, ". - " default_osid, path, pid, shared, creator, created) ". + " default_osid, path, pid, shared,global, creator, created) ". "VALUES ". " ('$imagename', '$imageid', '$description', $loadpart, ". " $loadlength, ". " $part1_osid, $part2_osid, $part3_osid, $part4_osid, ". - " '$default_osid', '$path', '$pid', $shared, ". + " '$default_osid', '$path', '$pid', $shared, $global, ". " '$uid', now())"); if (!$isadmin || $makedefault) { @@ -790,7 +920,7 @@ if (isset($node)) { # # Grab the unix GID for running script. # - TBGroupUnixInfo($pid, $pid, $unix_gid, $unix_name); + TBGroupUnixInfo($pid, $gid, $unix_gid, $unix_name); echo "
Creating image using node '$node' ... diff --git a/www/newimageid_ez.php3 b/www/newimageid_ez.php3 index e4f2edc6b630091aa426a860057cd415ddb8083b..87616c19f78df0ff858adb7c62cab3fae6cb5b70 100644 --- a/www/newimageid_ez.php3 +++ b/www/newimageid_ez.php3 @@ -113,21 +113,53 @@ function SPITFORM($formfields, $errors) echo "\n"; @@ -162,6 +194,38 @@ function SPITFORM($formfields, $errors) echo " \n"; + # + # Select a group + # + echo " + Group: + + + \n"; + # # Image Name: # @@ -373,20 +437,41 @@ function SPITFORM($formfields, $errors) \n"; + # + # Shared? + # + echo " + Shared?:
+ (available to all subgroups) + + Yes + + \n"; + if ($isadmin) { # - # Shared? + # Global? # echo " - Shared?:
+ Global?:
(available to all projects) Yes @@ -470,6 +555,32 @@ if (! $submit) { $defaults[os_feature_ssh] = "checked"; $defaults[os_feature_ipod] = "checked"; $defaults[os_feature_isup] = "checked"; + + # + # For users that are in one project and one subgroup, it is usually + # the case that they should use the subgroup, and since they also tend + # to be in the clueless portion of our users, give them some help. + # + if (count($projlist) == 1) { + list($project, $grouplist) = each($projlist); + + if (count($grouplist) <= 2) { + $defaults[pid] = $project; + if (count($grouplist) == 1 || strcmp($project, $grouplist[0])) + $group = $grouplist[0]; + else { + $group = $grouplist[1]; + } + $defaults[gid] = $group; + + if (!strcmp($project, $group)) + $defaults[path] = "/proj/$project/images/"; + else + $defaults[path] = "/groups/$project/$group/"; + } + reset($projlist); + } + SPITFORM($defaults, 0); PAGEFOOTER(); return; @@ -490,9 +601,19 @@ if (!isset($formfields[pid]) || elseif (!TBValidProject($formfields[pid])) { $errors["Project"] = "No such project"; } +elseif (isset($formfields[gid]) && + strcmp($formfields[gid], "")) { + if (!TBValidGroup($formfields[pid], $formfields[gid])) { + $errors["Group"] = "No such group"; + } + elseif (!TBProjAccessCheck($uid, $formfields[pid], + $formfields[gid], $TB_PROJECT_MAKEIMAGEID)) { + $errors["Project/Group"] = "Not enough permission"; + } +} elseif (!TBProjAccessCheck($uid, $formfields[pid], $formfields[pid], $TB_PROJECT_MAKEIMAGEID)) { - $errors["Project"] = "No enough permission"; + $errors["Project/Group"] = "Not enough permission"; } # @@ -560,9 +681,32 @@ elseif (! ereg("^[-_a-zA-Z0-9\.]+$", $formfields[os_version])) { } # -# The path must not contain illegal chars and it must be more than -# the original /proj/$pid we gave the user. We allow admins to specify -# a path outside of /proj though. +# Only admin types can set the global bit for an image. Ignore silently. +# +$global = 0; +if ($isadmin && + isset($formfields["global"]) && + strcmp($formfields["global"], "Yep") == 0) { + $global = 1; +} + +# +# Image shared amongst subgroups +# +$shared = 0; +if (isset($formfields[shared]) && + strcmp($formfields[shared], "Yep") == 0) { + $shared = 1; +} +# Does not make sense to do this. +if ($global && $shared) { + $errors["Global"] = "Image declared both shared and global"; +} + +# +# The path must not contain illegal chars and it must start with +# /proj/$pid/images or /groups/$pid/$gid. Admins can do whatever +# they like of course. # if (!isset($formfields[path]) || strcmp($formfields[path], "") == 0) { @@ -571,14 +715,20 @@ if (!isset($formfields[path]) || elseif (! ereg("^[-_a-zA-Z0-9\/\.+]+$", $formfields[path])) { $errors["Path"] = "Contains invalid characters"; } -else { - $pdef = "/proj/$formfields[pid]/"; - - if (strcmp($formfields[path], "$pdef") == 0) { - $errors["Path"] = "Incomplete Path"; +elseif (! $isadmin) { + $pdef = ""; + + if (!$shared && + isset($formfields[gid]) && + strcmp($formfields[gid], "") && + strcmp($formfields[gid], $formfields[pid])) { + $pdef = "/groups/" . $formfields[pid] . "/" . $formfields[gid] . "/"; } - elseif (!$isadmin && - strcmp(substr($formfields[path], 0, strlen($pdef)), $pdef)) { + else { + $pdef = "/proj/" . $formfields[pid] . "/images/"; + } + + if (strpos($formfields[path], $pdef) === false) { $errors["Path"] = "Invalid Path"; } } @@ -651,14 +801,6 @@ if (isset($formfields[node]) && $node = $formfields[node]; } -# -# Wholedisk -# -if (isset($formfields[wholedisk]) && - strcmp($formfields[wholedisk], "Yep") == 0) { - $shared = 1; -} - if (isset($formfields[max_concurrent]) && strcmp($formfields[max_concurrent],"")) { @@ -681,28 +823,21 @@ if (count($errors)) { return; } -# -# Only admin types can set the shared bit for an image. Ignore silently. -# -$shared = 0; - -if ($isadmin && - isset($formfields[shared]) && - strcmp($formfields[shared], "Yep") == 0) { - $shared = 1; -} - # # For the rest, sanitize and convert to locals to make life easier. # $description = addslashes($formfields[description]); $pid = $formfields[pid]; +$gid = $formfields[gid]; $imagename = $formfields[imagename]; $bootpart = $formfields[loadpart]; $path = $formfields[path]; $os_name = $formfields[os_name]; $os_version = $formfields[os_version]; $op_mode = $formfields[op_mode]; +if (!isset($gid) || !strcmp($gid, "")) { + $gid = $pid; +} # # Special option. Whole disk image, but only one partition that actually @@ -743,12 +878,12 @@ if (TBValidImageID($imageid) || TBValidOSID($imageid)) { DBQueryFatal("INSERT INTO images ". "(imagename, imageid, ezid, description, loadpart, loadlength, ". " part" . "$bootpart" . "_osid, ". - " default_osid, path, pid, shared, creator, created, ". - " max_concurrent) ". + " default_osid, path, pid, global, creator, created, ". + " max_concurrent, gid, shared) ". "VALUES ". " ('$imagename', '$imageid', 1, '$description', $loadpart, ". - " $loadlen, '$imageid', '$imageid', '$path', '$pid', $shared, ". - " '$uid', now(), $max_concurrent)"); + " $loadlen, '$imageid', '$imageid', '$path', '$pid', $global, ". + " '$uid', now(), $max_concurrent, '$gid', $shared)"); DBQueryFatal("INSERT INTO os_info ". "(osname, osid, ezid, description, OS, version, path, magic, ". @@ -756,7 +891,7 @@ DBQueryFatal("INSERT INTO os_info ". "VALUES ". " ('$imagename', '$imageid', 1, '$description', '$os_name', ". " '$os_version', NULL, NULL, '$os_features', '$pid', ". - " '$uid', $shared, now(), '$op_mode')"); + " '$uid', $global, now(), '$op_mode')"); for ($i = 0; $i < count($mtypes_array); $i++) { DBQueryFatal("REPLACE INTO osidtoimageid ". @@ -802,7 +937,7 @@ if (isset($node)) { # # Grab the unix GID for running script. # - TBGroupUnixInfo($pid, $pid, $unix_gid, $unix_name); + TBGroupUnixInfo($pid, $gid, $unix_gid, $unix_name); echo "
Creating image using node '$node' ... diff --git a/www/showimageid_list.php3 b/www/showimageid_list.php3 index 07bab1dfddc9d0d225e0f300d9c7f0a20ac61a9f..ea3900465f59f32a72f4578aa502ef97170830dd 100644 --- a/www/showimageid_list.php3 +++ b/www/showimageid_list.php3 @@ -44,10 +44,18 @@ if ($isadmin) { $query_result = DBQueryFatal("SELECT * FROM images as i order by $order"); } else { + # + # User is allowed to view the list of all global images, and all images + # in his project. Include images in the subgroups too, since its okay + # for the all project members to see the descriptors. They need proper + # permission to use/modify the image/descriptor of course, but that is + # checked in the pages that do that stuff. In other words, ignore the + # shared flag in the descriptors. + # $query_result = DBQueryFatal("select distinct i.* from images as i ". "left join group_membership as g on g.pid=i.pid ". - "where g.uid='$uid' or i.shared order by $order"); + "where g.uid='$uid' or i.global order by $order"); } SUBPAGESTART(); diff --git a/www/showstuff.php3 b/www/showstuff.php3 index 7ec9fd7c5c9bcd9fa8238820aee24cc669a7763a..18367d96678d142e05ef3c0d32ab2f805eca59d8 100644 --- a/www/showstuff.php3 +++ b/www/showstuff.php3 @@ -893,6 +893,7 @@ function SHOWIMAGEID($imageid, $edit, $isadmin = 0) { $imagename = $row[imagename]; $pid = $row[pid]; + $gid = $row[gid]; $description = stripslashes($row[description]); $loadpart = $row[loadpart]; $loadlength = $row[loadlength]; @@ -904,6 +905,7 @@ function SHOWIMAGEID($imageid, $edit, $isadmin = 0) { $path = $row[path]; $loadaddr = $row[load_address]; $shared = $row[shared]; + $globalid = $row["global"]; $creator = $row[creator]; $created = $row[created]; @@ -949,6 +951,12 @@ function SHOWIMAGEID($imageid, $edit, $isadmin = 0) { $pid \n"; + echo " + Group: + + $gid + \n"; + echo " Creator: $creator @@ -1076,6 +1084,18 @@ function SHOWIMAGEID($imageid, $edit, $isadmin = 0) { echo " \n"; + echo " + Global?: + \n"; + + if ($globalid) + echo "Yes"; + else + echo "No"; + + echo " + \n"; + echo " Internal ID: $imageid