#!/usr/bin/env perl # # list Lessons pages, using SOAP methods added by EDIA # # $Id$ use strict; use warnings; use open qw(:std :utf8); use SOAP::Lite; #use SOAP::Lite +trace => [ 'all' ]; use File::Path qw(make_path); use Data::Dumper; $Data::Dumper::Indent = 1; use XML::LibXML; use XML::LibXML::XPathContext; use Getopt::Std; use open ':std', ':encoding(UTF-8)'; # support UTF-8 output #--- parameter specification: ---# # my %opt; getopts( 'H:P:hp:u:N?', \%opt ) or die "Cannot parse command line\n"; HELP_MESSAGE() if $opt{h} || $opt{'?'}; my $rx = do { my $regex = @ARGV ? join( ' ', @ARGV ) : ''; qr($regex) or die "invalid argument, not a regular expression: $regex\n"; }; my $user = $opt{u} // $ENV{SAKAI_USER} // 'admin'; my $password = $opt{p} // $ENV{SAKAI_PASSWORD} // 'minda'; my $host = $opt{H} // $ENV{SAKAI_HOST} // 'sakai2.win.tue.nl'; my $port = $opt{P} // $ENV{SAKAI_PORT} // ( $opt{N} ? 80 : 443 ); my $http = $opt{N} ? 'http' : ( $ENV{SAKAI_PROTOCOL} // 'https' ); my $server = "$http://$host:$port/"; my $ns_uri = 'http://webservices.sakaiproject.org/'; #--- Usage ---# # sub HELP_MESSAGE { print STDERR <uri($ns_uri)->proxy($proxy)->on_action( sub { return '' } ) or die "No SOAP login object for service $proxy\n"; } sub method { SOAP::Data->name( "ns1:" . $_[0] )->attr( { 'xmlns:ns1' => $ns_uri } ); } sub soap_data_name { #warn sprintf("SOAP parameter: %s => %s\n", @_); SOAP::Data->name(@_)->type('string') # assessmentIds are strings! } sub param { # feed the arguments pairwise to SOAP::Data->name() map { soap_data_name( $_[$_], $_[ $_ + 1 ] ) } grep { !( $_ % 2 ) } ( 0 .. $#_ ); } sub call { my ( $service, $method, @params ) = @_; $service->call( method($method), param(@params) ) or die sprintf( "failed call %s(%s)\n", $method, join( ', ', @params ) ); } #--- for deconstructing output: ---# # my $xml_parser = new XML::LibXML( line_numbers => 1, load_ext_dtd => 0, # disables validation, says the documentation no_blanks => 1, clean_namespaces => 1, no_network => 1, pedantic_parser => 1 ) or die "cannot create the XML parser\n"; my $xpath_context = new XML::LibXML::XPathContext; sub xmldoc { if ( my $doc = eval { $xml_parser->parse_string( $_[0] ) } ) { $doc->getDocumentElement; } else { warn "cannot parse SOAP result: $@\n"; undef # ! EDIA's SOAP methods can return an empty document } } sub xpath { my ( $xpr, $node ) = @_; if ( !defined $node ) { return ( wantarray ? () : undef ); } ref($node) and $node->can('findnodes') or die "bug: xpath() called with wrong argument(s)\n"; my @nodes = $xpath_context->findnodes(@_)->get_nodelist; wantarray() ? @nodes : $nodes[0]; } #sub assessment_title #{ # my ($xmldoc) = @_; # # if ( $format eq 'QTI_1_2' ) # { # my @assmt = xpath( '//assessment', $xmldoc ) # // die "cannot find assessment, malformed QTI?\n"; # my $title = $assmt[0]->getAttribute('title') # // die "cannot find assessment title, malformed QTI?\n"; # $title; # } # else # { # die "sorry, cannot determine assessment title for format $format\n"; # } #} #--- here we go ---# # my $login_service = service('login'); #my $login = $login_service->loginToServer(id=>$user, pw=>$password) my $login = call( $login_service, 'loginToServer', 'id' => $user, 'pw' => $password ); my ( $session, $server_direct ) = split( /,/, $login->result ) or die "Cannot log in as $user to site $server\n"; #warn "session is: $session\n"; my $sites = call( service('sakai'), 'getAllSitesForCurrentUser', 'sessionid' => $session ); #print $sites->result; # returns texttext my %siteid2title; foreach my $site ( xpath( '//list/item', xmldoc( $sites->result ) ) ) { my ($id) = xpath( 'siteId', $site )->textContent; my ($title) = xpath( 'siteTitle', $site )->textContent; if ( $title =~ /$rx/ ) { $siteid2title{$id} = $title; } } my @siteids = sort { $siteid2title{$a} cmp $siteid2title{$b} } keys %siteid2title; my $lessons_service = service('lessons'); sub site2pages # given a site id, # returns the list of its pages { my ($site_id) = @_; my $pages = call( $lessons_service, 'getPagesForSite', 'sessionId' => $session, 'siteId' => $site_id ) or die "cannot call lessons.getPagesForSite()\n"; print $pages->result, "\n"; # example output for a page with 1 text item and 1 embedded video: # # 45d49a9a1-ab5d-4855-9f15-08e68f12abc4Lessons40f4ce4d-8932-469e-94bf-3a812c7410f7false1651The first item is a text item.

# ]]>
1772 <iframe width="560" height="315" src="https://www.youtube.com/embed/SfWwmJZOwZg" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>1admin
my @content_attrs = qw(id type sequence html); #my @items; warn "in site [$siteid2title{$site_id}],\n"; my @pages = xpath( '/pages/page', xmldoc( $pages->result ) ); warn " there are no Lessons pages\n" if !@pages; foreach my $page ( xpath( '/pages/page', xmldoc( $pages->result ) ) ) { my $pageId = xpath( 'pageId', $page )->textContent; warn " Lessons page $pageId has\n"; my @items = xpath( 'contents/content', $page ); warn " no items\n" if !@items; foreach my $content (@items) { my @values = map { xpath( $_, $content )->textContent } @content_attrs; my @direct_attrs = map { $content_attrs[$_] . ': ' . $values[$_] } 0 .. $#content_attrs; my @attributes = xpath( 'attributes/*', $content ); # there may be 0 of these my @attr_attrs = map { 'attrs/' . $_->nodeName . ': ' . $_->textContent } @attributes; my $values = join( ', ', @direct_attrs, @attr_attrs ); warn " an item [$values]\n"; } } # @items; } foreach my $id (@siteids) { site2pages($id); } #my @assmts = site2assessments($site_id); #warn sprintf( "%d assessments in site %s\n", scalar(@assmts), $sitename ); #warn join( ' ', 'with ids:', map { $_->{id} } @assmts ), "\n";