Commit e2d24242 authored by Leigh Stoller's avatar Leigh Stoller

Add user/project dashboard pages. The red-dot view adds an admin section

that has nothing in it (yet), and a link to the Emulab page until we have
something in the admin section.
parent a2a114a7
<?php
#
# Copyright (c) 2000-2016 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
function ExperimentList($which, $target)
{
global $urn_mapping, $TBBASE;
global $this_user;
if ($which == "user") {
$target_uuid = $target->uuid();
$whereclause = "where a.creator_uuid='$target_uuid'";
}
else {
$target_pid = $target->pid();
$whereclause = "where a.pid='$target_pid'";
}
$results = array();
$query_result =
DBQueryFatal("select a.*,s.expires,s.hrn,u.email, ".
" (UNIX_TIMESTAMP(now()) > ".
" UNIX_TIMESTAMP(s.expires)) as expired, ".
" truncate(a.physnode_count * ".
" ((UNIX_TIMESTAMP(now()) - ".
" UNIX_TIMESTAMP(a.created)) / 3600.0),2) as phours, ".
" IFNULL(aggs.count,0) as aggrows, ".
" agg.aggregate_urn as aggrow_urn".
" from apt_instances as a ".
"left join (".
" select uuid, COUNT(*) AS count ".
" from apt_instance_aggregates group by uuid) AS aggs ".
" on aggs.uuid=a.uuid ".
"left join apt_instance_aggregates as agg ".
" on agg.uuid=a.uuid ".
"left join geni.geni_slices as s on ".
" s.uuid=a.slice_uuid ".
"left join geni.geni_users as u on u.uuid=a.creator_uuid ".
"$whereclause");
while ($row = mysql_fetch_array($query_result)) {
$profile_id = $row["profile_id"];
$version = $row["profile_version"];
$uuid = $row["uuid"];
$name = $row["name"];
$status = $row["status"];
$canceled = $row["canceled"];
$created = DateStringGMT($row["created"]);
$expires = DateStringGMT($row["expires"]);
$creator_idx = $row["creator_idx"];
$profile_name = "$profile_id:$version";
$creator_uid = $row["creator"];
$pid = $row["pid"];
$pcount = $row["physnode_count"];
$vcount = $row["virtnode_count"];
$lockdown = $row["admin_lockdown"] || $row["user_lockdown"] ? 1 : 0;
$phours = $row["phours"];
$email = $row["email"];
$blob = array();
# If a guest user, use email instead.
if (isset($email)) {
$blob["creator"] = $email;
}
elseif (ISADMIN() || $which == "project") {
$blob["creator"] =
"<a href='user-dashboard.php?user=$creator_uid'>".
"$creator_uid</a>";
}
else {
$blob["creator"] = $creator_uid;
}
if ($row["expired"]) {
$status = "expired";
}
elseif ($canceled) {
$status = "canceled";
}
$blob["status"] = $status;
$profile = Profile::Lookup($profile_id, $version);
if ($profile) {
$blob["profile_name"] = $profile->name();
$blob["profile_uuid"] = $profile->uuid();
}
else {
$blob["profile_name"] = $profile_name;
}
#
# If arows non-zero, then we use that for aggregate_urn,
# and if its more then 1, we need to consume the extras rows
# to get the rest of the aggregate urns.
#
if ($row["aggrows"] > 0) {
$cluster = $urn_mapping[$row["aggrow_urn"]];
for ($i = 1; $i < $row["aggrows"]; $i++) {
$row = mysql_fetch_array($result);
$cluster .= "," . $urn_mapping[$row["aggrow_urn"]];
}
}
else {
$cluster = $urn_mapping[$row["aggregate_urn"]];
}
$blob["cluster"] = $cluster;
if (ISADMIN() || ISFOREIGN_ADMIN() || $which == "project") {
$blob["name"] = "<a href='status.php?uuid=$uuid'>$name</a>";
}
else {
$blob["name"] = $name;
}
if (ISADMIN() || $which == "user") {
$blob["project"] = "<a href='show-project.php?project=$pid'>".
"$pid</a>";
}
else {
$blob["project"] = $pid;
}
$blob["pcount"] = $pcount;
$blob["phours"] = $phours;
$blob["vcount"] = $vcount;
$blob["created"] = $created;
$blob["expires"] = $expires;
$blob["lockdown"] = $lockdown;
$results["$pid:$name"] = $blob;
}
return $results;
}
function ProfileList($which, $target)
{
global $urn_mapping, $TBBASE;
global $this_user;
if ($which == "user") {
$target_idx = $target->uid_idx();
$whereclause = "where v.creator_idx='$target_idx'";
}
else {
$target_idx = $target->pid_idx();
$whereclause = "where v.pid_idx='$target_idx'";
}
$results = array();
$query_result =
DBQueryFatal("select p.*,v.*,DATE(v.created) as created ".
" from apt_profiles as p ".
"left join apt_profile_versions as v on ".
" v.profileid=p.profileid and ".
" v.version=p.version ".
"$whereclause");
while ($row = mysql_fetch_array($query_result)) {
$idx = $row["profileid"];
$uuid = $row["uuid"];
$version = $row["version"];
$name = $row["name"];
$pid = $row["pid"];
$desc = $row["description"];
$created = DateStringGMT($row["created"]);
$public = $row["public"];
$listed = $row["listed"];
$creator = $row["creator"];
$rspec = $row["rspec"];
$privacy = ($public ? "Public" : "Project");
$desc = "";
$parsed_xml = simplexml_load_string($rspec);
if ($parsed_xml &&
$parsed_xml->rspec_tour && $parsed_xml->rspec_tour->description) {
$desc = $parsed_xml->rspec_tour->description;
# Convert to array to get the one element.
$desc = (array)$desc;
$desc = $desc[0];
}
$blob = array();
$blob["profile_name"] = $name;
$blob["profile_uuid"] = $uuid;
$blob["privacy"] = $privacy;
$blob["description"] = $desc;
$blob["created"] = $created;
$blob["listed"] = ($listed ? "Yes" : "No");
$blob["created"] = $created;
$blob["project"] = $pid;
$blob["creator"] = $creator;
if (ISADMIN() ||
($which == "user" && $creator == $target->uid()) ||
($which == "project" && $creator == $this_user->uid())) {
$blob["link"] =
"<a href='manage_profile.php?action=edit&uuid=$uuid'>$name</a>";
}
else {
$blob["link"] =
"<a href='show-profile.php?uuid=$uuid'>$name</a>";
}
$results["$pid:$name"] = $blob;
}
return $results;
}
# Local Variables:
# mode:php
# End:
?>
require(window.APT_OPTIONS.configObject,
['underscore', 'js/quickvm_sup', 'moment',
'js/lib/text!template/show-project.html',
'js/lib/text!template/experiment-list.html',
'js/lib/text!template/profile-list.html',
'js/lib/text!template/member-list.html',
],
function (_, sup, moment, mainString,
experimentString, profileString, memberString)
{
'use strict';
var mainTemplate = _.template(mainString);
function initialize()
{
window.APT_OPTIONS.initialize(sup);
// Generate the main template.
var html = mainTemplate({
emulablink : window.EMULAB_LINK,
isadmin : window.ISADMIN,
target_project : window.TARGET_PROJECT,
});
$('#main-body').html(html);
LoadExperimentTab();
LoadProfileTab();
LoadMembersTab();
}
function LoadExperimentTab()
{
var callback = function(json) {
console.info(json);
if (json.code) {
console.info(json.value);
return;
}
if (json.value.length == 0) {
$('#experiments_loading').addClass("hidden");
$('#experiments_noexperiments').removeClass("hidden");
return;
}
var template = _.template(experimentString);
$('#experiments_content')
.html(template({"experiments" : json.value,
"showCreator" : true,
"showProject" : false}));
// Format dates with moment before display.
$('#experiments_table .format-date').each(function() {
var date = $.trim($(this).html());
if (date != "") {
$(this).html(moment($(this).html()).format("ll"));
}
});
var table = $('#experiments_table')
.tablesorter({
theme : 'green',
});
}
var xmlthing = sup.CallServerMethod(null,
"show-project", "ExperimentList",
{"pid" : window.TARGET_PROJECT});
xmlthing.done(callback);
}
function LoadProfileTab()
{
var callback = function(json) {
console.info(json);
if (json.code) {
console.info(json.value);
return;
}
if (json.value.length == 0) {
$('#profiles_noprofiles').removeClass("hidden");
return;
}
var template = _.template(profileString);
$('#profiles_content')
.html(template({"profiles" : json.value,
"showCreator" : true,
"showProject" : false}));
// Format dates with moment before display.
$('#profiles_table .format-date').each(function() {
var date = $.trim($(this).html());
if (date != "") {
$(this).html(moment($(this).html()).format("ll"));
}
});
// Display the topo.
$('.showtopo_modal_button').click(function (event) {
event.preventDefault();
ShowTopology($(this).data("profile"));
});
var table = $('#profiles_table')
.tablesorter({
theme : 'green',
});
}
var xmlthing = sup.CallServerMethod(null,
"show-project", "ProfileList",
{"pid" : window.TARGET_PROJECT});
xmlthing.done(callback);
}
function ShowTopology(profile)
{
var profile;
var index;
var callback = function(json) {
if (json.code) {
alert("Failed to get rspec for topology viewer: " + json.value);
return;
}
sup.ShowModal("#quickvm_topomodal");
$("#quickvm_topomodal").one("shown.bs.modal", function () {
sup.maketopmap('#showtopo_nopicker',
json.value.rspec, false, !window.ISADMIN);
});
};
var $xmlthing = sup.CallServerMethod(null,
"myprofiles",
"GetProfile",
{"uuid" : profile});
$xmlthing.done(callback);
}
function LoadMembersTab()
{
var callback = function(json) {
console.info(json);
if (json.code) {
console.info(json.value);
return;
}
if (json.value.length == 0) {
return;
}
var template = _.template(memberString);
$('#members_content')
.html(template({"members" : json.value}));
// Format dates with moment before display.
$('#members_table .format-date').each(function() {
var date = $.trim($(this).html());
if (date != "") {
$(this).html(moment($(this).html()).format("ll"));
}
});
var table = $('#members_table')
.tablesorter({
theme : 'green',
});
}
var xmlthing = sup.CallServerMethod(null,
"show-project", "MemberList",
{"pid" : window.TARGET_PROJECT});
xmlthing.done(callback);
}
$(document).ready(initialize);
});
require(window.APT_OPTIONS.configObject,
['underscore', 'js/quickvm_sup', 'moment',
'js/lib/text!template/user-dashboard.html',
'js/lib/text!template/experiment-list.html',
'js/lib/text!template/profile-list.html',
'js/lib/text!template/project-list.html',
'js/lib/text!template/myaccount-table.html',
],
function (_, sup, moment, mainString,
experimentString, profileString, projectString, myaccountString)
{
'use strict';
var mainTemplate = _.template(mainString);
function initialize()
{
window.APT_OPTIONS.initialize(sup);
// Generate the main template.
var html = mainTemplate({
emulablink : window.EMULAB_LINK,
isadmin : window.ISADMIN,
target_user : window.TARGET_USER,
});
$('#main-body').html(html);
LoadExperimentTab();
// Should we do these on demand?
LoadProfileTab();
LoadProjectsTab();
LoadMyProfileTab();
}
function LoadExperimentTab()
{
var callback = function(json) {
console.info(json);
if (json.code) {
console.info(json.value);
return;
}
if (json.value.length == 0) {
$('#experiments_loading').addClass("hidden");
$('#experiments_noexperiments').removeClass("hidden");
return;
}
var template = _.template(experimentString);
$('#experiments_content')
.html(template({"experiments" : json.value,
"showCreator" : false,
"showProject" : true}));
// Format dates with moment before display.
$('#experiments_table .format-date').each(function() {
var date = $.trim($(this).html());
if (date != "") {
$(this).html(moment($(this).html()).format("ll"));
}
});
var table = $('#experiments_table')
.tablesorter({
theme : 'green',
});
}
var xmlthing = sup.CallServerMethod(null,
"user-dashboard", "ExperimentList",
{"uid" : window.TARGET_USER});
xmlthing.done(callback);
}
function LoadProfileTab()
{
var callback = function(json) {
console.info(json);
if (json.code) {
console.info(json.value);
return;
}
if (json.value.length == 0) {
$('#profiles_noprofiles').removeClass("hidden");
return;
}
var template = _.template(profileString);
$('#profiles_content')
.html(template({"profiles" : json.value,
"showCreator" : false,
"showProject" : true}));
// Format dates with moment before display.
$('#profiles_table .format-date').each(function() {
var date = $.trim($(this).html());
if (date != "") {
$(this).html(moment($(this).html()).format("ll"));
}
});
// Display the topo.
$('.showtopo_modal_button').click(function (event) {
event.preventDefault();
ShowTopology($(this).data("profile"));
});
var table = $('#profiles_table')
.tablesorter({
theme : 'green',
});
}
var xmlthing = sup.CallServerMethod(null,
"user-dashboard", "ProfileList",
{"uid" : window.TARGET_USER});
xmlthing.done(callback);
}
function ShowTopology(profile)
{
var profile;
var index;
var callback = function(json) {
if (json.code) {
alert("Failed to get rspec for topology viewer: " + json.value);
return;
}
sup.ShowModal("#quickvm_topomodal");
$("#quickvm_topomodal").one("shown.bs.modal", function () {
sup.maketopmap('#showtopo_nopicker',
json.value.rspec, false, !window.ISADMIN);
});
};
var $xmlthing = sup.CallServerMethod(null,
"myprofiles",
"GetProfile",
{"uuid" : profile});
$xmlthing.done(callback);
}
function LoadProjectsTab()
{
var callback = function(json) {
console.info(json);
if (json.code) {
console.info(json.value);
return;
}
if (json.value.length == 0) {
return;
}
var template = _.template(projectString);
$('#membership_content')
.html(template({"projects" : json.value}));
var table = $('#projects_table')
.tablesorter({
theme : 'green',
});
}
var xmlthing = sup.CallServerMethod(null,
"user-dashboard", "ProjectList",
{"uid" : window.TARGET_USER});
xmlthing.done(callback);
}
function LoadMyProfileTab()
{
var callback = function(json) {
console.info(json.value);
if (json.code) {
console.info(json.value);
return;
}
if (json.value.length == 0) {
return;
}
var template = _.template(myaccountString);
$('#myprofile_content')
.html(template({"fields" : json.value}));
}
var xmlthing = sup.CallServerMethod(null,
"user-dashboard", "AccountDetails",
{"uid" : window.TARGET_USER});
xmlthing.done(callback);
}
$(document).ready(initialize);
});
<?php
#
# Copyright (c) 2000-2015 University of Utah and the Flux Group.
# Copyright (c) 2000-2016 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -198,7 +198,7 @@ function SPITROWS($showall, $name, $result)
$creator = $email;
}
elseif (ISADMIN()) {
$creator = "<a href='$TBBASE/showuser.php3?user=$creator_idx'>".
$creator = "<a href='user-dashboard.php?user=$creator_uid'>".
"$creator_uid</a>";
}
else {
......@@ -259,7 +259,7 @@ function SPITROWS($showall, $name, $result)
echo "<td>$creator</td>";
}
if (ISADMIN()) {
echo " <td><a href='$TBBASE/showproject.php3?pid=$pid'>".
echo " <td><a href='show-project.php?pid=$pid'>".
"$pid</a></td>";
}
else {
......
......@@ -168,8 +168,30 @@ $routing = array("myprofiles" =>
array("file" => "myaccount.ajax",
"guest" => false,
"methods" => array("update" =>
"Do_Update")),
);
"Do_Update")),
"user-dashboard" =>
array("file" => "user-dashboard.ajax",
"guest" => false,
"methods" => array("ExperimentList" =>
"Do_ExperimentList",
"ProjectList" =>
"Do_ProjectList",
"ProfileList" =>
"Do_ProfileList",
"AccountDetails" =>
"Do_AccountDetails")),
"show-project" =>
array("file" => "show-project.ajax",
"guest" => false,
"methods" => array("ExperimentList" =>
"Do_ExperimentList",
"ProfileList" =>
"Do_ProfileList",
"MemberList" =>
"Do_MemberList",
"ProjectDetails" =>
"Do_ProjectDetails")),
);
#
# Redefine this so we return XML instead of html for all errors.
......
<?php
#
# Copyright (c) 2000-2016 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
chdir("..");
chdir("apt");
include_once("profile_defs.php");
include_once("instance_defs.php");
include_once("ajax-routines.ajax");
# We set this in CheckPageArgs
$target_project = null;
#
# Need to check the permission, since we allow admins to mess with
# other accounts.
#
function CheckPageArgs()
{
global $this_user, $target_project;
global $ajax_args;
global $TB_PROJECT_READINFO;
if (!isset($ajax_args["pid"])) {
SPITAJAX_ERROR(-1, "Missing target pid");
return -1;
}
$pid = $ajax_args["pid"];
if (!TBvalid_pid($pid)) {
SPITAJAX_ERROR(-1, "Invalid target pid");
return -1;
}
$target_project = Project::Lookup($pid);
if (!$target_project) {
sleep(2);
SPITAJAX_ERROR(-1, "Unknown target pid");
return -1;
}
if (!ISADMIN() &&
!$target_project->AccessCheck($this_user, $TB_PROJECT_READINFO)) {
SPITAJAX_ERROR(-1, "Not enough permission");
return -1;
}
return 0;
}