Custom System Reporting In Learn 9.1 Reporting overview. Learn 9.1 has many reports build into the products to track user and content usage. The 3 main types of reports are System Reports: These are accessed though the system admin tab and are available to system administrator. 1. Administrator Panel 2. System Reporting 3. Reports Course Reports: These are for reporting on an individual course. These are available for the teachers 1. Evaluation 2. Course Reports Content Reports: These are reports on a specific content type such as item tracking in a course or content system. Format: All reports can be run and downloaded as Word, Excel or PDF. Excel is the most useful if you want to do additional data manipulation of the data. PDF is perfect for reports you want to share. Default Course Reports: Each report is created using a BIRT template. The reports included in the Learn can be found on the local server under \blackboard\content\reporting\reportdefs\blackboard.ls.statistics\reports Course reports start with ls_course like ls_course_forum.rptdesign. This is the course discussion board report. You can see the sql used to create this report in the <xml-property name="queryText"> attribute. <xml-property name="queryText"><![CDATA[select DISTINCT (crs.course_id), crs.course_name, aa.course_pk1, crs.pk1, aa.content_pk1, cc.title, cc.start_date, cc.end_date from course_main crs, activity_accumulator aa, course_contents cc where aa.data='/webapps/assessment/take/submitted.jsp' and crs.pk1=aa.course_pk1 and cc.pk1=aa.content_pk1]]></xml-property> System reports use ls_system and content reports use ls_item. Data Learn reports all have access to the bblearn schema. The most common table for running reports against is the activity accumulator table (AA table). We use this for storing user interaction with courses. When creating your own custom reporting or just checking what data the default reports using you can use the Open Database Schema. As part of Blackboard commitment to openness the full database schema can be found here: https://behind.blackboard.com/SystemAdministrator/Learn/documentation/details.aspx?documentid=3886 Software Pre Requisites. Eclipse J2EE BIRT Tools for Eclipse Blackboard B2 Plugin for Eclipse A Database client. ( The follow 2 are the most popular) SQL developer MSSQL Management Studio Installing Eclipse and the Blackboard Plugin. Follow the instructional video from here to get your Eclipse up and running. Add in the Blackboard B2 Plugin. This can be manually added from fibbba.blackboard.com/eclipse http://www.edugarage.com/display/BBDN/Your+first+Building+Blocks+project+using+Eclipse Add the BIRT tool to Eclispe 1. From the “Help” menu > Select “Install New Software” > Search for “BIRT” >Install Packages BIRT Basics Terminology Data Source: BIRT reports use a data source element to connect to a database or other data provider. BIRT uses a data set element to retrieve data from the data provider. Think of the data source as a connection, and the data set as a query. When first Building a report we will create a link to our database using JDBC drivers so the report can be tested inside Eclipse. Once we are happy with the report we set the Report to use the Data Set to the Blackboard Connector (COMMON.BBLEARN_DAT_SOURCE) Data Sets: Data sets contain the SQL you will use with the Data Source. If you think as the data source as the where this is the what. Report: The BIRT report contains a mapping to the Data Set. This is where you display the results from the data set. My First Custom Report (Hello Word) Scenario: In this example we will create a report to say hello to all the users. When creating a report the first thing we need to find is the data in the database we would like to use. Using the open database schema in our example we would like a list of all users on the system. From the user table we can select what columns we are instead in. In this example from the user table we will use: firstname, lastname You can directly add the SQL to eclipse and see the results or use an SQL client. Building more complex SQL queries is best done first in your favorite SQL client. This allows you to change the query fast and make sure if performs well. select firstname, lastname from users Creating a BIRT B2 Project. In Eclipse set new project > other > Building Block Project Select Next. Use the Project Template BIRT Report Sample. Set your Perspective to Report Design. Window > Open Perspective > Report Design Rename the sample report (Hits per day) to Hello Users in the navigator window. Data Source Create a Data Source to your database, Oracle or MSSQL: In the data explorer right click the Data Source and add new > JDBC Data Source > Give this a meaningful name Oracle example MSSQL If you are missing the Oracle or MSSQL driver class these can be added. See reference section at the end of this article. Use the test connection to ensure this is working correctly. Data Set Create a Data set to get the result of your SQL query: Remove the data set called Data Set. This is for the example created by the B2 installer. Right click on data sets and add new > Select the Data Source as your JDBC database connection you set above. Give the Data Set name as Users You can then add the query and select finish. If the SQL was correct then the next screen will show you the Columns and the type of data held in there. In our example these are strings. Select Preview results to check you data. This will only show the first 500 records. The Report Adding the data to the report: In the design window using the layout tab you will see a table already created. We will remove this table and create our own. Select the bottom of this table > right click and delete. The fastest way to add our data to the report is too drag and drop the whole data set to the report. This gives you a table with 2 columns and auto fills it with our data set. This report is ready for its first run. Run > view report > as html ( Say yes to any message about errors) Working with the data: The BIRT designer comes with an expression builder. This allows us to use java script, operators and BIRT functions on the data we get form the database. In this example we want to add the word Hello before the user first name. Double click the firstname in the details row of the table (Middle row). The default expression is dataSetRow["FIRSTNAME"] for this column. Select the Fx button to open the expression Builder. The expression we will use is "Hello " + dataSetRow["FIRSTNAME"] + " " +dataSetRow["LASTNAME"] This will give us Hello First Name, space, Last Name. All text must be in quotes including the space we use between the first and last name. Now we have both first and last name in the one column we can remove the second column in the table Formatting the Report: In the Property Editor you can use Fonts alignments and Borders. As this is a simple example we will loft align the data set and add a title. The Palette is used for adding tables, grids Text (HTML) and Images. In this report add a Text Item to the top of the page and select HTML. Add in the text Hello World in the formatting of your choice. In the header field of your table change the header to List Of Users and left align. This is the final report preview before we package this up. Packaging the Report Into a B2 B2 Data Source: The data source now need to be set in Blackboards Internal Data Connector. Double click on the Data Set users > Data Source > Select Data Source > BBLEARN_data_source You will see an error “Cannot open the connection for this driver”. This is normal as the Data source only working from within Blackbord. Manifest.xml: The manifest contain the Title or the report and the name of the BIRT XML file. Modify they manifest to look like this. <package provider="BIRT" name="Hello World"> <source>Blackboard, Inc.</source> <definition name=" Hello World " file="reports/hello users.rptdesign" version="1.0.0.0" provider="BIRT" parameterHandler="blackboard.platform.reporting.service.birt.BirtPromptBuilder "> <title> Hello World </title> <description>This is an example of hello world</description> <type>system.statistics</type> </definition> </package> Set your Report Type: system.statistics – add to system course.statistics – add to course course.content – add to content ParameterHandler: This is used to tell Blackboard to use the Prompt Builder when using input Paramaters BB-Manifest Set the BB-manifest.xml for your B2: The full XML look like this <?xml version="1.0" encoding="ISO-8859-1"?> <manifest> <!-- core extension information --> <plugin> <name value= "BIRT Hellow World"/> <handle value= "My-first-Report"/> <description value= "BIRT Hello World"/> <version value= "1.0.0"/> <requires> <bbversion value="9.1"/> </requires> <vendor> <id value="bbbb"/> <name value="Blacbord Support"/> <url value="http://www.myinstitution.edu/" /> <description value="This is my first birt report" /> </vendor> <http-actions /> <reports> <report-package file-name="reports.zip" /> </reports> <permissions> <permission type="java.util.PropertyPermission" name="*" actions="read,write" /> <permission type="java.net.SocketPermission" name="*" actions="connect" /> <permission type="attribute" name="user.personalinfo" actions="get" /> <permission type="attribute" name="user.authinfo" actions="get" /> <permission type="attribute" name="user.cardnumber" actions="get" /> <permission type="attribute" name="Group" actions="get" /> <permission type="attribute" name="GroupMembership" actions="get" /> <permission type="persist" name="Content" actions="create,modify,delete" /> <permission type="persist" name="ContentHandler" actions="create,modify,delete" /> </permissions> </plugin> </manifest> Build the B2. The Blackboard plugin comes with a built in ant script to build your B2. 1. Use save all 2. In the deisgn view of hello users.reptdesign select xml Source Edit : <report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.22" id="1"> To <report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.17" id="1"> 3. 4. 5. 6. Save Right click Build.xml > run as ant build In the console you may see In the console view you may see BUILD FAILED C:\Users\ahulme\workspace\BIRT\bbbb-My-first-Report\build.xml:11: java.net.ConnectException: Connection timed out: connect This is because we did not specify a test instance to connect to. This can be ignored 7. Install the B2 onto your system. Success: BIRT Hello World installed. No components found in this Building Block. 8. Make this available and run from the admin panel > System Reporting > Reports > Hello World Advanced Expressions. (YouTube Reporting) Scenario: You have been asked to create a report of YouTube mashups for all courses in your Institution including the URL and title of the YouTube video. You are running MSSQL on Windows so can use the main_data field form the table course_contents. This is a ntext filed containing the URL, title and embed codes so you will have to setup a Expression in the Expression Builder to filter out the data you want. Data Set: select cc.pk1, cm.pk1, cm.course_name, cc.main_data, cm.course_id from course_contents cc, course_main cm where cnthndlr_handle='resource/x-bb-youtube-mashup' and cm.pk1=cc.crsmain_pk1 order by cm.course_name Add the Course Name, Course Id Title and URL to a report. The main data contains the Title and URL and a lot of html we do not want. <div style="margin-top:15px; word-wrap: break-word;"> <div style="float:left; width:150px; border-style:solid; border-width:1px; bordercolor: #bbbbbb"> <div style="text-align: center;"> <a lb:options="{'contents':{'id':'myYouTubee8690c7b86634cad82443d3578b6ba6a','stripComments':true},'closeOnBodyClick':false}" class="lb" href="http://www.youtube.com/watch?v=qQra4baNwP8" title="Interactive Teaching Methods"><img src="http://i.ytimg.com/vi/qQra4baNwP8/1.jpg" alt="Watch Video" width="120"></a> </div> <div style="background-image: url(/images/ci/ng/rumble_button_back.gif);background-position: center; padding: 2px; text-decoration: none; color: #333333; text-align: center;"> <a lb:options="{'contents':{'id':'myYouTubee8690c7b86634cad82443d3578b6ba6a','stripComments':true},'closeOnBodyClick':false}" class="lb" style="text-decoration: none; color: #333333;" href="http://www.youtube.com/watch?v=qQra4baNwP8" title="Interactive Teaching Methods">Watch Video</a> </div> </div> <div style="margin-left: 160px; font-size: 15px; font-weight: bold; margin-bottom: 5px;">Interactive Teaching Methods</div> <div style="margin-left: 160px; font-size: 11px; margin-bottom: 5px;"> <strong>Duration: (3:49)</strong><br /> <strong>User:</strong> jeremylevy - <strong>Added:</strong> 8/27/07<br /> </div> <div id="myYouTubee8690c7b86634cad82443d3578b6ba6a" style="display: none;"><!-- <div style="margin: 10px;"><div class="u_controlsWrapper"><a href="#" class="button-4" id="openYtControlse8690c7b86634cad82443d3578b6ba6a">Player Controls</a></div><div id="controlse8690c7b86634cad82443d3578b6ba6a" class="liveArea-slim playerControls" style="display:none"><h2 class="hideoff">Video Player Controls: Interactive Teaching Methods</h2><a aria-live="off" id="playVideoe8690c7b86634cad82443d3578b6ba6a" href="#" class="button-4">Play</a><a id="stopVideoe8690c7b86634cad82443d3578b6ba6a" href="#" class="button-4">Stop</a><a id="volUpe8690c7b86634cad82443d3578b6ba6a" href="#" class="button-4">Volume Up</a><a id="volDowne8690c7b86634cad82443d3578b6ba6a" href="#" class="button-4">Volume Down</a><a aria-live="off" id="mutee8690c7b86634cad82443d3578b6ba6a" href="#" class="button-4">Mute</a><a href="#" class="close" id="closeYtControlse8690c7b86634cad82443d3578b6ba6a"><img src="/images/ci/ng/close_mini.gif" alt="Close Player Controls"/></a></div><h2 class="hideoff">Embedded Video Player: Interactive Teaching Methods</h2><div style="word-wrap: breakword;"><div class="previewDiv" style="height:344px;width:425px"><object id="ytObjecte8690c7b86634cad82443d3578b6ba6a" width="425" height="344" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" title="Interactive Teaching Methods"><param name="movie" value="http://www.youtube.com/v/qQra4baNwP8&fs=1&rel=0&enablejsapi=1&playerapiid=ytEmbede8690c7b86634cad82443d3578b6ba6a" ></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed id="ytEmbede8690c7b86634cad82443d3578b6ba6a" src="http://www.youtube.com/v/qQra4baNwP8&fs=1&rel=0&enablejsapi=1&playerapiid=ytEmbede8690c7b86634cad82443d3578b6ba6a" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344" alt="Interactive Teaching Methods"><noembed>Interactive Teaching Methods</noembed></embed></object><a href="#close" onclick="lightbox.closeCurrentLightbox(); return false;" class="hideoff">Close</a></div><div id="stripe8690c7b86634cad82443d3578b6ba6a" class="liveArea-slim playerControls" style="display:none"><h2 class="hideoff">Video Status: Interactive Teaching Methods</h2><span arialive="off" id="currentStatuse8690c7b86634cad82443d3578b6ba6a"></span> <strong>Interactive Teaching Methods</strong> (<strong arialive="off" id="currentTimee8690c7b86634cad82443d3578b6ba6a"></strong> of <strong>3:49</strong>)</div></div></div> --></div> <div style="clear:both"></div> </div> <br/> <div> &nbsp; </div> <br> To filter out the URL we create the following BIRT expression. This finds the total length of the string and count up to the http. Then removes everything up to that point. It then will do the same for the end point of the URL. There are many way this can be done var testing = BirtStr.charLength(dataSetRow["main_data"]) var spaceCharPosition = BirtStr.indexOf( "http", dataSetRow["main_data"] ); var comb = testing - spaceCharPosition; var ddddd = BirtStr.right(dataSetRow["main_data"], comb); var stringPatternPosition = BirtStr.search(" ", ddddd) -1; displayString1 = BirtStr.left(ddddd,stringPatternPosition ); To Filter out the title. var testing = BirtStr.charLength(dataSetRow["main_data"]) var spaceCharPosition = BirtStr.indexOf( "title", dataSetRow["main_data"] ); var comb = testing - spaceCharPosition - 7; var ddddd = BirtStr.right(dataSetRow["main_data"], comb); var stringPatternPosition = BirtStr.search("src", ddddd) -7 ; displayString1 = BirtStr.left(ddddd,stringPatternPosition ); View the report. This can then be packaged the same way as for our first example. Input Parameters and Global Variables. Scenario: This question was asked don the bb-admin list server. An admin has been asked for a report of the percentage of active courses and the percentage of active courses on the system. Active in this case means a specific action and a minimum threshold. This could be hard coded into the SQL statement but these threshold and user actively may change over time. Input Create you Parameters: This report will have 2 input parameters, Event Type and Threshold. Event Type In order to get a full list of the type of events on our system we start by creating a query to being back all types form the AA tables. Data Set (EVENT_TYPE) select distinct (event_type) from activity_accumulator Some of these are not relevant and can be filtered at this stage using the Filers options. For example we can remove Module Access as this is not used in a course. Create a Report Parameter from the Data Explorer called param#event#type. The inclusion of param# lets Blackboard know to use blackboard.platform.reporting.service.birt.BirtPromptBuilder This is a dynamic parameter and gets its values from the Data Set EVENT_TYPE into a list box. This Prompt text can contain the text displayed to the screen or use param#event#type if you want to create a language pack for this report. Threshold Parameter Create a new parameter that is a simple text box that takes the inputted value and assigns it to the parameter param#total#count Active courses Data Set: select DISTINCT(course_pk1), count(course_pk1) as "Total Page View" from activity_accumulator where event_type=? group by course_pk1 having count(course_pk1) > ? The question marks mean use a parameter. We set the parameters in the parameter option of the Data Set. The fist Parameter is the event type and we link that using the Linked to Report Parameter option to link it to param#event#type. This will load in our option we select in the GUI of the event type. The second parameter will be linked to the param#total#count. When you have parameters in the Data Set the Preview option will not return any results. We also will want to add a Computed Colum to this Data Set to count the total amount of result returned so not only we will have the list of active courses but a total count as well. We will use this when working out the percentages. Report: Add the Course Pk1 and the Total Page View to the report and check it is working. Select the Page Access and the Threshold. In this case I have used 3 as this is a testing system with not much usage. Global Variables: In order to get the percentage of active course to the full course list we need to first get the total count of courses and the active count. We have the active count already from the Computed Column. This can be added as a footer to the table with the full active course list. This total active courses value can then be passed to a Global variable called mygvar. Create a script on the onCreate function of the active courses table with the following in. This is done by selecting the table and then selecting Script > onCreate myvar = this.getRowData().getColumnValue("Total"); reportContext.setGlobalVariable("mygvar" , myvar); Create a new data set to find the full count of all courses on the system using the SQL select count(*) from course_main Add this to a new table with the header Percentage of Active courses. With the expression Builder we can retrieve this global variable and calculate the percentage of the Active Courses against the Full course count. var Total_Active = parseInt(reportContext.getGlobalVariable("mygvar")); var Total_Course = dataSetRow["COUNT(*)"]; var percentage = ( Total_Active / Total_Course) * 100; percentage +"%" If we like we can now hide the table with the course PK1 list by setting the Display on the Table to No Display or use the Pk1’s to lookup the course Id’ and Name. Course Reports. To set a report to appear in a course you will need to set the report manifest XML to know it is to be used in a course. <package provider="BIRT" name="Course Report"> <source>Blackboard, Inc.</source> <definition name=" Hello World " file="reports/course report.rptdesign" version="1.0.0.0" provider="BIRT" parameterHandler="blackboard.platform.reporting.service.birt.BirtPromptBuilder "> <title> Hello course </title> <description>This is a course report</description> <type>course.statistics</type> </definition> </package> With the BIRT integration, the application can now render prompts directly from the parameters in the report. This is useful for passing in the course pk1 of the course you are in. Loading the Add Parameter Binding: “beforeFactory The beforeFactory event executes prior to beginning the generation phase.” To do this in your report use the Outline view And select on your report name. Select the before Factory in the Script tab and add the following. BlackboardFunctions.AddParameterBinding(reportContext); Create the Parameter to use the course PK1: Create a report parameter and set the name to param#course#id You can now use this parameter in a data set for example to get the entire user in that course. Data Set lstAllUsers select u.pk1 user_pk1, u.lastname, u.firstname, u.title, u.suffix, u.middlename, u.othername, u.user_id from users u, course_users cu where cu.users_pk1 = u.pk1 and cu.crsmain_pk1 = ? and u.row_status = 0 and cu.row_status = 0 Set a parameter in this data set to PCourseId and bind it to your param#course#id. This will then use the course PK1 in the SQL. Reporting on One user in a course. We can use the above example to generate a list of users that can be passed into a parameter so when running the report you can select just one or many users via the GUI. The sql above gives us all the users id details. To be able to provide a better GUI experience we can use each columns first,. Name last name etc to create a more friendly name. In the Data Set lstAllUsers create a Computated Colum called user and use the expression var result; result = bbUtil.formatNameWithId( row["USER_ID"], row["FIRSTNAME"], row["MIDDLENAME"], row["LASTNAME"], row["TITLE"], row["OTHERNAME"], row["SUFFIX"], 'SHORT_SURNAME' ); result == null ? "????" : result This will give a much more friendly name for the user. Create a new parameter called param#listall#users. We will use the List Box function and dynamically use the lstAllUsers to populate it via the above SQL. Set the select Column Value to the user pk1. This is the Value we will pass to anther data set. This is not very friendly though or useful to the end use. So select the display text to the Computed Column of user. You can chose to sort on the user name if you wish. Create a new Data set and use a new parameter blinded the dynamic param#listall#users. The report will look creation screen will look like this. Selecting the user will pass this user pk1 to any data set you would like to use it with. . Using Dates in a Course Report: In order to use dates in a course report you will need to create a report parameter with date set as the Data Type and select the format you prefer to use. In this example I have used a custom format of mm/dd/yyyy. Use 2 report parameters one for the end date and one for the start date. Once deployed into Learn you will be able to user the calendar widget to select your dates. Using Course Search in a System Report: In order to search for a specific course in a system report you will need to create a report parameter called param#select#course#id of Integer type. You must then setup a dataset parameter of type integer linked to the report parameter param#select#course#id. Parameter types must be integers as the search is based on the course_main.PK1 field and not the course_main.courseID field. Once deployed into Learn you will be able to search for a course using the standard course search tool.