[LON-CAPA-cvs] cvs: doc /loncapafiles loncapafiles.lpml loncom/html/adm/help/tex Docs_Adding_External_Tool.tex loncom/html/res/adm/pages exttool.png loncom/interface londocs.pm

raeburn raeburn at source.lon-capa.org
Tue May 9 20:03:27 EDT 2017


raeburn		Wed May 10 00:03:27 2017 EDT

  Added files:                 
    /loncom/html/adm/help/tex	Docs_Adding_External_Tool.tex 
    /loncom/html/res/adm/pages	exttool.png 

  Modified files:              
    /loncom/interface	londocs.pm 
    /doc/loncapafiles	loncapafiles.lpml 
  Log:
  - Bug 6754. Make LON-CAPA an LTI Tool Consumer (LTI 1.1).
  - External Tool cannot be copied via Course Editor's Paste Buffer from one 
    course to another if course's domains are different.
  - Copying of an External Tool within a course creates new instance of the 
    tool.
  - Add documentation to Course Editor for External Tool.
  - Add icon specifically for External Tool.  
  
  
-------------- next part --------------
Index: loncom/interface/londocs.pm
diff -u loncom/interface/londocs.pm:1.626 loncom/interface/londocs.pm:1.627
--- loncom/interface/londocs.pm:1.626	Mon May  8 14:20:20 2017
+++ loncom/interface/londocs.pm	Wed May 10 00:03:08 2017
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Documents
 #
-# $Id: londocs.pm,v 1.626 2017/05/08 14:20:20 raeburn Exp $
+# $Id: londocs.pm,v 1.627 2017/05/10 00:03:08 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -761,8 +761,8 @@
                     $donechk = 1;
                 }
                 if ($url =~ m{^/uploaded/\Q$coursedom\E/\Q$coursenum\E/(default_\d+\.)(page|sequence)$}) {
-                    &contained_map_check($url,$folder,\%removefrommap,\%removeparam,
-                                         \%addedmaps,\%hierarchy,\%titles,$allmaps);
+                    &contained_map_check($url,$folder,$coursenum,$coursedom,\%removefrommap,
+                                        \%removeparam,\%addedmaps,\%hierarchy,\%titles,$allmaps);
                     $importuploaded = 1;
                 } elsif ($url =~ m{^/res/.+\.(page|sequence)$}) {
                     next if ($allmaps->{$url});
@@ -1213,8 +1213,8 @@
                 $subdir = $prefix;
             }
             my (%addedmaps,%removefrommap,%removeparam,%hierarchy,%titles,%allmaps);
-            &contained_map_check($url,$folder,\%removefrommap,\%removeparam,\%addedmaps,
-                                 \%hierarchy,\%titles,\%allmaps);
+            &contained_map_check($url,$folder,$coursenum,$coursedom,\%removefrommap,
+                                 \%removeparam,\%addedmaps,\%hierarchy,\%titles,\%allmaps);
             if (ref($hierarchy{$url}) eq 'HASH') {
                 my ($nested,$nestednames);
                 &recurse_uploaded_maps($url,$subdir,\%hierarchy,\%titles,\$nested,\$nestednames);
@@ -1326,11 +1326,16 @@
                         $is_uploaded_map = 1;
                     }
                 } elsif (($url =~ m{^/res/lib/templates/\w+\.problem$}) ||
-                         ($url =~ m{^/adm/($match_domain)/($match_username)/\d+/(bulletinboard|smppg)$})) {
+                         ($url =~ m{^/adm/($match_domain)/($match_username)/\d+/(bulletinboard|smppg|ext\.tool)$})) {
                     if ($cid ne $env{'request.course.id'}) {
                         my ($srcdom,$srcnum) = split(/_/,$cid);
                         if ($env{"user.priv.cm./$srcdom/$srcnum"} =~ /\Q:mdc&F\E/) {
-                            $othercrs = '<br />'.&mt('(from another course)');
+                            if (($is_exttool) && ($srcdom ne $coursedom)) {
+                                $canpaste = 0;
+                                $nopaste = &mt('Paste from another domain unavailable.');
+                            } else {
+                                $othercrs = '<br />'.&mt('(from another course)');
+                            }
                         } else {
                             $canpaste = 0;
                             $nopaste = &mt('Paste from another course unavailable.');
@@ -1342,10 +1347,13 @@
                 }  
             }
             my $buffer;
-            if (($is_external) || ($is_exttool)) {
+            if ($is_external) {
                 $buffer = &mt('External Resource').': '.
                     &LONCAPA::map::qtescape($env{'docs.markedcopy_title_'.$suffix}).' ('.
                     &LONCAPA::map::qtescape($url).')';
+            } elsif ($is_exttool) {
+                $buffer = &mt('External Tool').': '.
+                    &LONCAPA::map::qtescape($env{'docs.markedcopy_title_'.$suffix});
             } else {
                 my $icon = &Apache::loncommon::icon($extension);
                 if ($extension eq 'sequence' &&
@@ -1625,7 +1633,7 @@
         return();
     }
 
-    my (%msgs,%before,%after, at dopaste,%is_map,%notinsupp,%notincrs,%duplicate,
+    my (%msgs,%before,%after, at dopaste,%is_map,%notinsupp,%notincrs,%notindom,%duplicate,
         %prefixchg,%srcdom,%srcnum,%srcmapidx,%marktomove,$save_err,$lockerrors,$allresult);
 
     foreach my $suffix (@topaste) {
@@ -1654,7 +1662,8 @@
             $srcdom{$suffix} = $srcd;
             $srcnum{$suffix} = $srcn;
         } elsif (($url =~ m{^/res/lib/templates/\w+\.problem$}) ||
-                 ($url =~ m{^/adm/$match_domain/$match_username/\d+/(bulletinboard|smppg)$})) {
+                 ($url =~ m{^/adm/$match_domain/$match_username/\d+/(bulletinboard|smppg|ext\.tool)$})) {
+            my $srctype= $1;
             my ($srcd,$srcn) = split(/_/,$cid);
 # When paste buffer was populated using an active role in a different course
 # check for mdc privilege in the course from which the resource was pasted
@@ -1664,6 +1673,10 @@
                     next;
                 }
             }
+            if (($srctype eq 'ext.tool') && ($srcd ne $coursedom)) {
+                $notindom{$suffix} = 1;
+                next;
+            }
             $srcdom{$suffix} = $srcd;
             $srcnum{$suffix} = $srcn;
         }
@@ -1672,7 +1685,6 @@
         if ($url=~/\.(page|sequence)$/) {
             $is_map{$suffix} = 1; 
         }
-
         if ($url =~ m{^/uploaded/$match_domain/$match_courseid/([^/]+)}) {
             my $oldprefix = $1;
 # When pasting content from Main Content to Supplemental Content and vice versa 
@@ -1717,6 +1729,7 @@
     %msgs = &Apache::lonlocal::texthash (
                 notinsupp => 'Paste failed: content type is not supported within Supplemental Content',
                 notincrs  => 'Paste failed: Item is from a different course which you do not have rights to edit.',
+                notindom  => 'Paste failed: Item is an external tool from a course in a different donain.', 
                 duplicate => 'Paste failed: only one instance of a particular published sequence or page is allowed within each course.',
             );
 
@@ -1770,8 +1783,9 @@
         if ($is_map{$suffix}) {
 # If pasting a map, check if map contains other maps
             my (%hierarchy,%titles);
-            &contained_map_check($url,$folder,\%removefrommap,\%removeparam,
-                                 \%addedmaps,\%hierarchy,\%titles,$allmaps);
+            &contained_map_check($url,$folder,$coursenum,$coursedom,
+                                 \%removefrommap,\%removeparam,\%addedmaps,
+                                 \%hierarchy,\%titles,$allmaps);
             if ($url=~ m{^/uploaded/}) {
                 my $newurl;
                 unless ($env{'form.docs.markedcopy_options_'.$suffix} eq 'move') {
@@ -1824,7 +1838,7 @@
                 }
             }
         }
-        if ($url=~ m{/(bulletinboard|smppg)$}) {
+        if ($url=~ m{/(bulletinboard|smppg|ext\.tool)$}) {
             my $prefix = $1;
             my $fromothercrs; 
             #need to copy the db contents to a new one, unless this is a move.
@@ -1852,6 +1866,8 @@
                         $msg = &mt('Paste failed: An error occurred when copying the simple page.').' '.$errtext;
                     } elsif ($prefix eq 'bulletinboard') {
                         $msg = &mt('Paste failed: An error occurred when copying the discussion board.').' '.$errtext;
+                    } elsif ($prefix eq 'ext.tool') {
+                        $msg = &mt('Paste failed: An error occurred when copying the external tool.').' '.$errtext;
                     }
                     $results{$suffix} = $result;
                     $msgerrs{$suffix} = $msg;
@@ -2111,8 +2127,11 @@
     my ($url,$result,$errtext);
     if (ref($dbref) eq 'HASH') {
         $url = $dbref->{'src'};
-        if ($url =~ m{/(smppg|bulletinboard)$}) {
+        if ($url =~ m{/(smppg|bulletinboard|ext\.tool)$}) {
             my $prefix = $1;
+            if ($prefix eq 'ext.tool') {
+                $prefix = 'exttool';
+            }
             if (($dbref->{'cdom'} =~ /^$match_domain$/) && 
                 ($dbref->{'cnum'} =~ /^$match_courseid$/)) {
                 my $db_name;
@@ -2123,6 +2142,8 @@
                         &Apache::lonsimplepage::get_db_name($url,$marker,
                                                             $dbref->{'cdom'},
                                                             $dbref->{'cnum'});
+                } elsif ($dbref->{'src'} =~ m{/ext\.tool$}) {
+                    $db_name = 'exttool_'.$marker;
                 } else {
                     $db_name = 'bulletinpage_'.$marker;
                 }
@@ -2166,7 +2187,7 @@
                     $result=&Apache::lonnet::put($db_name,\%contents,
                                                  $coursedom,$coursenum);
                     if ($result eq 'ok') {
-                        $url =~ s{/(\d*)/(smppg|bulletinboard)$}{/$suffix/$2}x;
+                        $url =~ s{/(\d*)/(smppg|bulletinboard|ext\.tool)$}{/$suffix/$2}x;
                     }
                 }
                 if (($freedlock ne 'ok') && (ref($lockerrorsref) eq 'HASH')) {
@@ -2176,6 +2197,9 @@
                     if ($prefix eq 'smppg') {
                         $lockerrorsref->{$prefix} .=
                             ' '.&mt('This will prevent creation of additional simple pages in this course.');
+                    } elsif ($prefix eq 'exttool') {
+                        $lockerrorsref->{$prefix} .=
+                            ' '.&mt('This will prevent addition of more external tools to this course.');
                     } else {
                         $lockerrorsref->{$prefix} .= ' '.&mt('This will prevent creation of additional discussion boards in this course.');
                     }
@@ -2305,8 +2329,8 @@
 }
 
 sub contained_map_check {
-    my ($url,$folder,$removefrommap,$removeparam,$addedmaps,$hierarchy,$titles,
-        $allmaps) = @_;
+    my ($url,$folder,$coursenum,$coursedom,$removefrommap,$removeparam,$addedmaps,
+        $hierarchy,$titles,$allmaps) = @_;
     my $content = &Apache::lonnet::getfile($url);
     unless ($content eq '-1') {
         my $parser = HTML::TokeParser->new(\$content);
@@ -2316,7 +2340,13 @@
             if ($token->[1] eq 'resource') {
                 next if ($token->[2]->{'type'} eq 'zombie');
                 my $ressrc = $token->[2]->{'src'};
-                if ($folder =~ /^supplemental/) {
+                if ($ressrc =~ m{^/adm/($match_domain)/$match_courseid/\d+/ext\.tool$}) {
+                    my $srcdom = $1;
+                    unless ($srcdom eq $coursedom) {
+                        $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc;
+                        next;
+                    }
+                } elsif ($folder =~ /^supplemental/) {
                     unless (&supp_pasteable($ressrc)) {
                         $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc;
                         next;
@@ -2335,8 +2365,8 @@
                             $addedmaps->{$ressrc} = [$url];
                         }
                     }
-                    &contained_map_check($ressrc,$folder,$removefrommap,$removeparam,
-                                         $addedmaps,$hierarchy,$titles,$allmaps);
+                    &contained_map_check($ressrc,$folder,$coursenum,$coursedom,$removefrommap,
+                                         $removeparam,$addedmaps,$hierarchy,$titles,$allmaps);
                 }
             } elsif ($token->[1] eq 'param') {
                 if ($folder =~ /^supplemental/) {
@@ -5083,12 +5113,12 @@
 #
 # --------------------------------------------- Initialize help topics for this
     foreach my $topic ('Adding_Course_Doc','Main_Course_Documents',
-	               'Adding_External_Resource','Navigate_Content',
-	               'Adding_Folders','Docs_Overview', 'Load_Map',
-	               'Supplemental','Score_Upload_Form','Adding_Pages',
-	               'Importing_LON-CAPA_Resource','Importing_IMS_Course',
-                       'Uploading_From_Harddrive','Course_Roster','Web_Page',
-                       'Dropbox','Simple_Problem') {
+	               'Adding_External_Resource','Adding_External_Tool',
+                       'Navigate_Content','Adding_Folders','Docs_Overview',
+	               'Load_Map','Supplemental','Score_Upload_Form',
+	               'Adding_Pages','Importing_LON-CAPA_Resource',
+	               'Importing_IMS_Course','Uploading_From_Harddrive',
+                       'Course_Roster','Web_Page','Dropbox','Simple_Problem') {
 	$help{$topic}=&Apache::loncommon::help_open_topic('Docs_'.$topic);
     }
     # Composite help files
@@ -6239,7 +6269,7 @@
         );
         if (keys(%ltitools)) {
             push(@importdoc,
-                {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/extres.png" alt="'.$lt{extt}.'" onclick="toggleUpload(\'tool\');" />'=>$exttoolform},
+                {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/exttool.png" alt="'.$lt{extt}.'" onclick="toggleUpload(\'tool\');" />'=>$exttoolform},
         );
         }
         unless ($container eq 'page') {
@@ -6416,7 +6446,7 @@
             =>$supextform});
         if (keys(%ltitools)) {
             push(@supimportdoc,
-                {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/extres.png" alt="'.$lt{extt}.'" onclick="javascript:toggleUpload(\'supptool\')" />'
+                {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/exttool.png" alt="'.$lt{extt}.'" onclick="javascript:toggleUpload(\'supptool\')" />'
             =>$supexttoolform});
         }
         push(@supimportdoc, 
@@ -6911,7 +6941,7 @@
                         if ($hostname ne '') {
                             $backtourl = 'http://'.$hostname.$backtourl;
                         }
-                        $backtourl .= (($backtourl =~ /\?/) ? '&':'?').'usehttp=1';
+                        $backtourl .= (($backtourl =~ /\?/) ? '&':'?').'usehttp=1';
                     }
                 } elsif ($backtourl =~ m{^/adm/wrapper/ext/(?!https:)}) {
                     if (($ENV{'SERVER_PORT'} == 443) && ($hostname ne '')) {
Index: doc/loncapafiles/loncapafiles.lpml
diff -u doc/loncapafiles/loncapafiles.lpml:1.951 doc/loncapafiles/loncapafiles.lpml:1.952
--- doc/loncapafiles/loncapafiles.lpml:1.951	Mon Apr  3 02:01:31 2017
+++ doc/loncapafiles/loncapafiles.lpml	Wed May 10 00:03:27 2017
@@ -2,7 +2,7 @@
  "http://lpml.sourceforge.net/DTD/lpml.dtd">
 <!-- loncapafiles.lpml -->
 
-<!-- $Id: loncapafiles.lpml,v 1.951 2017/04/03 02:01:31 raeburn Exp $ -->
+<!-- $Id: loncapafiles.lpml,v 1.952 2017/05/10 00:03:27 raeburn Exp $ -->
 
 <!--
 
@@ -3503,6 +3503,7 @@
 Docs_About_Syllabus.tex;
 Docs_Adding_Course_Doc.tex;
 Docs_Adding_External_Resource.tex;
+Docs_Adding_External_Tool.tex;
 Docs_Adding_Folders.tex;
 Docs_Adding_Pages.tex;
 Docs_Adding_Syllabus.tex;
@@ -8199,6 +8200,7 @@
 emblem-readonly.png;
 emblem-system.png;
 extres.png;
+exttool.png;
 folder-new.png;
 folder-new-22x22.png;
 format-justify-fill.png;

Index: loncom/html/adm/help/tex/Docs_Adding_External_Tool.tex
+++ loncom/html/adm/help/tex/Docs_Adding_External_Tool.tex
\label{Docs_Adding_External_Tool}

External tools which support the LTI (Learning Tool Interoperability)
standard can be included within a LON-CAPA course.  Which tools are available,
as well as the options which can be set by a Coordinator when including 
one of the available tools within a course or community, are set by the Domain 
Coordinator at a domain level. 

The full range of options which may be available to the Coordinator in the course
or community are:

\begin{itemize}

\item Display type 
\begin{itemize}
\item iframe -- the tool will be launched within the standard interface, (i.e.,
inline menu including navigation controls, and links/icons)

\item tab -- a page containing a link to launch the tool will be displayed
in a separate web browser tab.

\item window -- a page containing a link to launch the tool will be displayed
in a separate web browser window.

\end{itemize}

\item Display options -- if display is tab or window, additional options may be available:

\begin{itemize}

\item Link Text -- the text used in the link which launches the tool
\item Explanation -- optional text block (HTML mark-up can be used)
displayed below the link
\item Width/Height -- if display is window, width and height of the new window
can be set by specifying the number of pixels to use for each. 

\end{itemize}

\item Course label -- e.g., institutional course code (sent on launch of tool)
\item Course title -- Course Title

\item Title -- title to use for tool instance on the Course Contents page.

\end{itemize}

If external LTI tools can be used in the course's domain, you will select the
name of the tool you wish to use from the ``Select'' drop-down list. Doing 
so will cause the options for the tool to be displayed. If display is in
an iframe, by default, but you are permitted to choose one of the other types,
then click tab or window will cause additional elements to be displayed.

Your domain coordinator can tell you what data are sent to the external tool
when it is displayed. Typically, though, this will include the username of the
user, as well as the user's current ``LTI'' role. LTI uses a more restricted
set of roles -- Instructor, Content Developer, Teaching Assistant or Learner --
than are available in LON-CAPA. Your domain coordinator will have decided on
the mapping to an LTI role to be used for each standard LON-CAPA role. At a minimum
you can expect that Course Coordinator (LON-CAPA) will map to Instructor (LTI),
Student (LON-CAPA) will map to Learner (LTI).

Under the LTI protocol, the user's identity, as well as the course context, will
be sent to the external tool in an encrypted form, and the tool (the LTI Provider)
will trust the user's identity and role sent from LON-CAPA (the LTI Consumer),
and then assign appropriate privileges to the user within the tool.


More information about the LON-CAPA-cvs mailing list