/*global define */
define(['jquery', 'underscore', 'backbone', 'models/LogsSearch', 'promise'],
function($, _, Backbone, LogsSearch, Promise) {
'use strict';
// Statistics Model
// ------------------
var Stats = Backbone.Model.extend(
/** @lends Stats.prototype */{
// This model contains all of the statistics in a user's or query's profile
defaults: {
query: "*:* ", //Show everything
postQuery: "", //An unencoded version of the query
metadataCount: 0,
dataCount: 0,
totalCount: 0,
metadataFormatIDs: [], //Uses same structure as Solr facet counts: ["text/csv", 5]
dataFormatIDs: [], //Uses same structure as Solr facet counts: ["text/csv", 5]
firstUpload: 0,
metadataUploads: null,
dataUploads: null,
metadataUploadDates: null,
dataUploadDates: null,
//Number of updates to content for each time period
firstUpdate: 0,
dataUpdateDates: null,
metadataUpdateDates: null,
firstBeginDate: 0,
temporalCoverage: 0,
coverageYears: 0,
hideMetadataAssessment: false,
mdqScoresImage: null,
//HTTP GET requests are typically limited to 2,083 characters. So query lengths
// should have this maximum before switching over to HTTP POST
maxQueryLength: 1958,
usePOST: false
},
//Some dated used for query creation
firstPossibleUpload: "2000-01-01T00:00:00Z", //The first possible date that an object could be uploaded (based on DataONE dates)
firstPossibleDataONEDownload: "2012-07-01T00:00:00Z", //The first possible download date from the DataONE CN
firstPossibleDataONEDate: "2012-07-01T00:00:00Z", //The first possible download date from the DataONE CN
firstPossibleDate: "1800-01-01T00:00:00Z", //The first possible date that data could have been collected in (based on DataONE dates)
initialize: function(){
//Add a function to parse ISO date strings for IE8 and other older browsers
(function(){
var D= new Date('2011-06-02T09:34:29+02:00');
if(!D || +D!== 1307000069000){
Date.fromISO= function(s){
var day, tz,
rx=/^(\d{4}\-\d\d\-\d\d([tT ][\d:\.]*)?)([zZ]|([+\-])(\d\d):(\d\d))?$/,
p= rx.exec(s) || [];
if(p[1]){
day= p[1].split(/\D/);
for(var i= 0, L= day.length; i<L; i++){
day[i]= parseInt(day[i], 10) || 0;
};
day[1]-= 1;
day= new Date(Date.UTC.apply(Date, day));
if(!day.getDate()) return NaN;
if(p[5]){
tz= (parseInt(p[5], 10)*60);
if(p[6]) tz+= parseInt(p[6], 10);
if(p[4]== '+') tz*= -1;
if(tz) day.setUTCMinutes(day.getUTCMinutes()+ tz);
}
return day;
}
return NaN;
}
}
else{
Date.fromISO= function(s){
return new Date(s);
}
}
})();
//Set the request type (GET or POST)
this.setRequestType();
this.on("change:query", this.setRequestType);
},
//This function serves as a shorthand way to get all of the statistics stored in the model
getAll: function(options){
if (typeof options === "undefined")
var options = {};
//Listen for our responses back from the server before we send requests that require info from the response
this.listenToOnce(this, 'change:firstBeginDate', this.getLastEndDate);
this.listenToOnce(this, 'change:lastEndDate', this.getCollectionYearFacets);
this.listenToOnce(this, 'change:dataCount', this.getDataFormatIDs);
this.listenToOnce(this, 'change:metadataCount', this.getMetadataFormatIDs);
this.listenToOnce(this, 'change:firstUpload', this.getUpdateDates);
this.getFirstBeginDate();
this.getFirstUpload();
this.getFormatTypes();
// Only get the MetaDIG scores if MetacatUI is configured to display metadata assesments
// AND this model has them enabled, too.
if ( !MetacatUI.appModel.get("hideSummaryMetadataAssessment") && !this.get("hideMetadataAssessment") ){
this.getMdqScores();
}
},
// Send a Solr query to get the earliest beginDate, latest endDate, and facets of data collection years
getFirstBeginDate: function(){
var model = this;
//Define a success callback when the query is successful
var successCallback = function(data, textStatus, xhr) {
if( !data.response.numFound ){
//There were no begin dates found
model.set('totalBeginDates', 0);
//Construct a query
var query = model.get('query') +
" AND endDate:[" + model.firstPossibleDate + " TO " + (new Date()).toISOString() + "]" + //Use date filter to weed out badly formatted data
" AND -obsoletedBy:*",
//Get one row only
rows = "1",
//Sort the results in ascending order
sort = "endDate asc",
//Return only the endDate field
fl = "endDate";
var successCallback = function(endDateData, textStatus, xhr) {
//If not endDates or beginDates are found, there is no temporal data in the index, so save falsey values
if(!endDateData.response.numFound){
model.set('firstBeginDate', null);
model.set('lastEndDate', null);
}
else{
model.set('firstBeginDate', new Date.fromISO(endDateData.response.docs[0].endDate));
}
}
if( model.get("usePOST") ){
var queryData = new FormData();
queryData.append("q", query);
queryData.append("rows", rows);
queryData.append("sort", sort);
queryData.append("fl", fl);
queryData.append("wt", "json");
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl'),
type: "POST",
contentType: false,
processData: false,
data: queryData,
dataType: "json",
success: successCallback
}
}
else{
//Find the earliest endDate if there are no beginDates
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl') + "q=" + query +
"&rows=" + rows + "&sort=" + sort + "&fl=" + fl + "&wt=json",
type: "GET",
dataType: "json",
success: successCallback
}
}
$.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings()));
}
else{
// Save the earliest beginDate and total found in our model
model.set('firstBeginDate', new Date.fromISO(data.response.docs[0].beginDate));
model.set('totalBeginDates', data.response.numFound);
model.trigger("change:firstBeginDate");
model.trigger("change:totalBeginDates");
}
}
//Construct a query
var specialQueryParams = " AND beginDate:[" + this.firstPossibleDate + " TO " + (new Date()).toISOString() + "] AND -obsoletedBy:* AND -formatId:*dataone.org/collections* AND -formatId:*dataone.org/portals*",
query = this.get("query") + specialQueryParams,
//Get one row only
rows = "1",
//Sort the results in ascending order
sort = "beginDate asc",
//Return only the beginDate field
fl = "beginDate";
if( this.get("usePOST") ){
//Get the unencoded query string
if( this.get("postQuery") ){
query = this.get("postQuery") + specialQueryParams;
}
else if( this.get("searchModel") ){
query = this.get("searchModel").getQuery(undefined, { forPOST: true });
this.set("postQuery", query);
query = query + specialQueryParams;
}
var queryData = new FormData();
queryData.append("q", query);
queryData.append("rows", rows);
queryData.append("sort", sort);
queryData.append("fl", fl);
queryData.append("wt", "json");
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl'),
type: "POST",
contentType: false,
processData: false,
data: queryData,
dataType: "json",
success: successCallback
}
}
else{
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl') + "q=" + query +
"&rows=" + rows +
"&fl=" + fl +
"&sort=" + sort +
"&wt=json",
type: "GET",
dataType: "json",
success: successCallback
}
}
//Send the query
$.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings()));
},
getLastEndDate: function(){
var model = this;
var now = new Date();
//Get the latest temporal data coverage year
var specialQueryParams = " AND endDate:[" + this.firstPossibleDate + " TO " + now.toISOString() + "]" + //Use date filter to weed out badly formatted data
" AND -obsoletedBy:* AND -formatId:*dataone.org/collections* AND -formatId:*dataone.org/portals*",
query = this.get('query') + specialQueryParams,
rows = 1,
fl = "endDate",
sort = "endDate desc",
wt = "json";
var successCallback = function(data, textStatus, xhr) {
if(typeof data == "string"){
data = JSON.parse(data);
}
if(!data.response.numFound){
//Save some falsey values if none are found
model.set('lastEndDate', null);
}
else{
// Save the earliest beginDate and total found in our model - but do not accept a year greater than this current year
var now = new Date();
if(new Date.fromISO(data.response.docs[0].endDate).getUTCFullYear() > now.getUTCFullYear()){
model.set('lastEndDate', now);
}
else{
model.set('lastEndDate', new Date.fromISO(data.response.docs[0].endDate));
}
model.trigger("change:lastEndDate");
}
}
if( this.get("usePOST") ){
//Get the unencoded query string
if( this.get("postQuery") ){
query = this.get("postQuery") + specialQueryParams;
}
else if( this.get("searchModel") ){
query = this.get("searchModel").getQuery(undefined, { forPOST: true });
this.set("postQuery", query);
query = query + specialQueryParams;
}
var queryData = new FormData();
queryData.append("q", query);
queryData.append("rows", rows);
queryData.append("sort", sort);
queryData.append("fl", fl);
queryData.append("wt", "json");
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl'),
type: "POST",
contentType: false,
processData: false,
data: queryData,
dataType: "json",
success: successCallback
}
}
else{
//Query for the latest endDate
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl') + "q=" + query +
"&rows=" + rows + "&fl=" + fl + "&sort=" + sort + "&wt=" + wt,
type: "GET",
dataType: "json",
success: successCallback
}
}
$.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings()));
},
/**
** getFormatTypes will send three Solr queries to get the formatTypes and formatID statistics and will update the model
**/
getFormatTypes: function(){
var model = this;
//Build the query to get the format types
var specialQueryParams = " AND (formatType:METADATA OR formatType:DATA) AND -obsoletedBy:* AND -formatId:*dataone.org/collections* AND -formatId:*dataone.org/portals*",
query = this.get('query') + specialQueryParams,
rows = "2",
group = true,
groupField = "formatType",
groupLimit = "0",
stats = true,
statsField = "size",
sort = "formatType desc",
wt = "json";
var successCallback = function(data, textStatus, xhr) {
var formats = data.grouped.formatType.groups;
if(formats.length == 1){ //Only one format type was found
if(formats[0].groupValue == "METADATA"){ //That one format type is metadata
model.set('dataCount', 0);
model.trigger("change:dataCount");
model.set('metadataCount', formats[0].doclist.numFound);
model.set('dataFormatIDs', ["", 0]);
}else{
model.set('dataCount', formats[0].doclist.numFound);
model.set('metadataCount', 0);
model.trigger("change:metadataCount");
model.set('metadataFormatIDs', ["", 0]);
}
}
//If no data or metadata objects were found, draw blank charts
else if(formats.length == 0){
//Store falsey data
model.set('dataCount', 0);
model.trigger("change:dataCount");
model.set("totalCount", 0);
model.trigger("change:totalCount");
model.set('metadataCount', 0);
model.trigger("change:metadataCount");
model.set('metadataFormatIDs', ["", 0]);
model.set('dataFormatIDs', ["", 0]);
return;
}
else{
//Extract the format types (because of filtering and sorting they will always return in this order)
model.set('metadataCount', formats[0].doclist.numFound);
model.set('dataCount', formats[1].doclist.numFound);
}
//Get the total size of all the files in the index
var totalSize = data.stats.stats_fields.size.sum;
model.set("totalSize", totalSize);
}
if( this.get("usePOST") ){
//Get the unencoded query string
if( this.get("postQuery") ){
query = this.get("postQuery") + specialQueryParams;
}
else if( this.get("searchModel") ){
query = this.get("searchModel").getQuery(undefined, { forPOST: true });
this.set("postQuery", query);
query = query + specialQueryParams;
}
var requestData = new FormData();
requestData.append("q", query);
requestData.append("rows", rows);
requestData.append("group", group);
requestData.append("group.field", groupField);
requestData.append("group.limit", groupLimit);
requestData.append("stats", stats);
requestData.append("stats.field", statsField);
requestData.append("sort", sort);
requestData.append("wt", wt);
//Request settings for POST requests
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl'),
data: requestData,
contentType: false,
processData: false,
type: "POST",
dataType: "json",
success: successCallback
}
}
else{
//Run the query
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl') +
"q=" + query +
"&rows=" + rows +
"&group=" + group +
"&group.field=" + groupField +
"&group.limit=" + groupLimit +
"&stats=" + stats +
"&stats.field=" + statsField +
"&sort=" + sort +
"&wt=" + wt,
type: "GET",
dataType: "json",
success: successCallback
}
}
$.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings()));
},
getDataFormatIDs: function(){
var model = this;
if( !this.get('dataCount') ){
return;
}
var specialQueryParams = " AND formatType:DATA AND -obsoletedBy:* AND -formatId:*dataone.org/collections* AND -formatId:*dataone.org/portals*",
query = this.get('query') + specialQueryParams,
facet = "true",
facetField = "formatId",
facetLimit = "-1",
facetMincount = "1",
rows = "0",
wt = "json";
var successCallback = function(data, textStatus, xhr) {
model.set('dataFormatIDs', data.facet_counts.facet_fields.formatId);
}
if( this.get("usePOST") ){
//Get the unencoded query string
if( this.get("postQuery") ){
query = this.get("postQuery") + specialQueryParams;
}
else if( this.get("searchModel") ){
query = this.get("searchModel").getQuery(undefined, { forPOST: true });
this.set("postQuery", query);
query = query + specialQueryParams;
}
var queryData = new FormData();
queryData.append("q", query);
queryData.append("facet", facet);
queryData.append("facet.field", facetField);
queryData.append("facet.limit", facetLimit);
queryData.append("facet.mincount", facetMincount);
queryData.append("rows", rows);
queryData.append("wt", wt);
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl'),
type: "POST",
contentType: false,
processData: false,
data: queryData,
dataType: "json",
success: successCallback
}
}
else{
//Now get facet counts of the data format ID's
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl') + "q=" + query +
"&facet=" + facet + "&facet.field=" + facetField +
"&facet.limit=" + facetLimit + "&facet.mincount=" + facetMincount +
"&rows=" + rows + "&wt=" + wt,
type: "GET",
dataType: "json",
success: successCallback
}
}
$.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings()));
},
getMetadataFormatIDs: function(){
if( !this.get('metadataCount') ){
return;
}
var model = this;
var specialQueryParams = " AND formatType:METADATA AND -obsoletedBy:* AND -formatId:*dataone.org/collections* AND -formatId:*dataone.org/portals*",
query = this.get("query") + specialQueryParams,
facet = "true",
facetField = "formatId",
facetLimit = "-1",
facetMincount = "1",
rows = "0",
wt = "json";
var successCallback = function(data, textStatus, xhr) {
model.set('metadataFormatIDs', data.facet_counts.facet_fields.formatId);
}
if( this.get("usePOST") ){
//Get the unencoded query string
if( this.get("postQuery") ){
query = this.get("postQuery") + specialQueryParams;
}
else if( this.get("searchModel") ){
query = this.get("searchModel").getQuery(undefined, { forPOST: true });
this.set("postQuery", query);
query = query + specialQueryParams;
}
var queryData = new FormData();
queryData.append("q", query);
queryData.append("facet", facet);
queryData.append("facet.field", facetField);
queryData.append("facet.limit", facetLimit);
queryData.append("facet.mincount", facetMincount);
queryData.append("rows", rows);
queryData.append("wt", wt);
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl'),
type: "POST",
contentType: false,
processData: false,
data: queryData,
dataType: "json",
success: successCallback
}
}
else{
//Now get facet counts of the metadata format ID's
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl') + "q=" + query +
"&facet=" + facet + "&facet.field=" + facetField +
"&facet.limit=" + facetLimit + "&facet.mincount=" + facetMincount +
"&rows=" + rows + "&wt=" + wt,
type: "GET",
dataType: "json",
success: successCallback
}
}
$.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings()));
},
/*
* getUpdateDates will get the number of newest-version science metadata and data
* objects uploaded in each month
*/
getUpdateDates: function(){
var model = this;
var now = new Date();
var metadataQueryParams = " AND -obsoletedBy:* AND formatType:METADATA AND -formatId:*dataone.org/collections* AND -formatId:*dataone.org/portals*";
var metadataQuery = this.get('query') + metadataQueryParams;
var firstPossibleUpdate = MetacatUI.nodeModel.isCN(MetacatUI.nodeModel.get("currentMemberNode"))?
this.firstPossibleDataONEDate : model.get("firstUpload");
if( !firstPossibleUpdate ){
firstPossibleUpdate = new Date();
firstPossibleUpdate.setYear( firstPossibleUpdate.getYear() - 100 );
firstPossibleUpdate = firstPossibleUpdate.toISOString();
}
var rows = "1",
sort = "dateUploaded asc",
facet = "true",
facetMissing = "true", //Include months that have 0 uploads
facetLimit = "-1",
facetRange = "dateUploaded",
facetRangeStart = firstPossibleUpdate,
facetRangeEnd = now.toISOString(),
wt = "json";
var dataSuccessCallback = function(data, textStatus, xhr) {
if( !data.response.numFound ){
model.set("dataUpdateDates", []);
}
else{
//Get the array of dateUploaded facets
var updateDates = data.facet_counts.facet_ranges.dateUploaded.counts;
//Remove all the empty facet counts at the beginning of the array
while(updateDates[1] == 0){
updateDates.splice(0, 2);
}
//Save the dateUploaded facets for data objects
model.set("dataUpdateDates", updateDates);
// Save the earliest dateUploaded and total found in our model
if(updateDates[0] < model.get("firstUpdate"))
model.set('firstUpdate', updateDates[0]);
}
}
var metadataSuccessCallback = function(data, textStatus, xhr) {
if( !data.response.numFound ){
model.set('firstUpdate', null);
model.set("metadataUpdateDates", []);
}
else{
//Get the array of dateUploaded facets
var updateDates = data.facet_counts.facet_ranges.dateUploaded.counts;
//Remove all the empty facet counts at the beginning of the array
while(updateDates[1] == 0){
updateDates.splice(0, 2);
}
//Save the dateUploaded facets for metadata objects
model.set("metadataUpdateDates", updateDates);
// Save the earliest dateUploaded and total found in our model
model.set('firstUpdate', updateDates[0]);
}
var dataQueryParams = " AND -obsoletedBy:* AND formatType:DATA",
dataQuery = model.get("query") + dataQueryParams;
if( model.get("usePOST") ){
//Get the unencoded query string
if( model.get("postQuery") ){
dataQuery = model.get("postQuery") + dataQueryParams;
}
else if( model.get("searchModel") ){
dataQuery = this.get("searchModel").getQuery(undefined, { forPOST: true });
this.set("postQuery", query);
dataQuery = dataQuery + dataQueryParams;
}
var queryData = new FormData();
queryData.append("q", dataQuery);
queryData.append("sort", sort);
queryData.append("facet", facet);
queryData.append("facet.missing", facetMissing);
queryData.append("facet.limit", facetLimit);
queryData.append("facet.range", facetRange);
queryData.append("facet.range.start", facetRangeStart);
queryData.append("facet.range.end", facetRangeEnd);
queryData.append("facet.range.gap", "+1MONTH");
queryData.append("rows", rows);
queryData.append("wt", wt);
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl'),
type: "POST",
contentType: false,
processData: false,
data: queryData,
dataType: "json",
success: dataSuccessCallback
}
}
else{
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl') + "q=" + dataQuery +
"&sort=" + sort + "&rows=" + rows + "&facet=" + facet +
"&facet.missing=" + facetMissing + "&facet.limit=" + facetLimit +
"&facet.range=" + facetRange + "&facet.range.start=" + facetRangeStart +
"&facet.range.end=" + facetRangeEnd + "&facet.range.gap=" + "%2B1MONTH" +
"&wt=" + wt,
type: 'GET',
dataType: "json",
success: dataSuccessCallback
}
}
$.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings()));
}
if( this.get("usePOST") ){
//Get the unencoded query string
if( this.get("postQuery") ){
metadataQuery = this.get("postQuery") + metadataQueryParams;
}
else if( this.get("searchModel") ){
metadataQuery = this.get("searchModel").getQuery(undefined, { forPOST: true });
this.set("postQuery", metadataQuery);
metadataQuery = metadataQuery + metadataQueryParams;
}
var queryData = new FormData();
queryData.append("q", metadataQuery);
queryData.append("sort", sort);
queryData.append("facet", facet);
queryData.append("facet.missing", facetMissing);
queryData.append("facet.limit", facetLimit);
queryData.append("facet.range", facetRange);
queryData.append("facet.range.start", facetRangeStart);
queryData.append("facet.range.end", facetRangeEnd);
queryData.append("facet.range.gap", "+1MONTH");
queryData.append("rows", rows);
queryData.append("wt", wt);
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl'),
type: "POST",
contentType: false,
processData: false,
data: queryData,
dataType: "json",
success: metadataSuccessCallback
}
}
else{
//Run the query
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl') + "q=" + metadataQuery +
"&sort=" + sort + "&rows=" + rows + "&facet=" + facet +
"&facet.missing=" + facetMissing + "&facet.limit=" + facetLimit +
"&facet.range=" + facetRange + "&facet.range.start=" + facetRangeStart +
"&facet.range.end=" + facetRangeEnd + "&facet.range.gap=" + "%2B1MONTH" +
"&wt=" + wt,
dataType: "json",
type: "GET",
success: metadataSuccessCallback
}
}
$.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings()));
},
/*
* Gets the earliest dateUploaded from the solr index
*/
getFirstUpload: function(){
var now = new Date(),
model = this,
firstPossibleUpload = new Date();
firstPossibleUpload.setYear( firstPossibleUpload.getYear() - 100 );
firstPossibleUpload = firstPossibleUpload.toISOString();
//Get the earliest upload date
var specialQueryParams = " AND formatType:(METADATA OR DATA)" + //Weeds out resource maps and annotations
" AND dateUploaded:[" + firstPossibleUpload + " TO " + now.toISOString() + "]" + //Weeds out badly formatted dates
" AND -obsoletes:* AND -formatId:*dataone.org/collections* AND -formatId:*dataone.org/portals*", //Only count one version of a revision chain
query = this.get('query') + specialQueryParams,
fl = "dateUploaded",
rows = "1",
sort = "dateUploaded asc",
wt = "json";
var successCallback = function(data, textStatus, xhr) {
if(!data.response.numFound){
//Save some falsey values if none are found
model.set('totalUploads', 0);
model.trigger("change:totalUploads");
model.set('firstUpload', null);
model.set("dataUploads", 0);
model.set("metadataUploads", 0);
model.set('metadataUploadDates', []);
model.set('dataUploadDates', []);
}
else{
// Save the earliest dateUploaded and total found in our model
model.set('firstUpload', data.response.docs[0].dateUploaded);
model.set('totalUploads', data.response.numFound);
}
}
if( this.get("usePOST") ){
//Get the unencoded query string
if( this.get("postQuery") ){
query = this.get("postQuery") + specialQueryParams;
}
else if( this.get("searchModel") ){
query = this.get("searchModel").getQuery(undefined, { forPOST: true });
this.set("postQuery", query);
query = query + specialQueryParams;
}
var requestData = new FormData();
requestData.append("q", query);
requestData.append("rows", rows);
requestData.append("fl", fl);
requestData.append("sort", sort);
requestData.append("wt", wt);
//Request settings for POST requests
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl'),
data: requestData,
processData: false,
contentType: false,
type: "POST",
dataType: "json",
success: successCallback
}
}
else{
//Request settings for GET requests
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl') + "q=" + query +
"&rows=" + rows + "&fl=" + fl + "&wt=" + wt + "&sort=" + sort,
type: "GET",
dataType: "json",
success: successCallback
}
}
$.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings()));
},
/* getTemporalCoverage
* Get the temporal coverage of this query/user from Solr
*/
getCollectionYearFacets: function(){
var model = this;
//How many years back should we look for temporal coverage?
var lastYear = this.get('lastEndDate') ? this.get('lastEndDate').getUTCFullYear() : new Date().getUTCFullYear(),
firstYear = this.get('firstBeginDate')? this.get('firstBeginDate').getUTCFullYear() : new Date().getUTCFullYear(),
totalYears = lastYear - firstYear,
today = new Date().getUTCFullYear(),
now = new Date(),
yearsFromToday = {
fromBeginning: today - firstYear,
fromEnd: today - lastYear
};
//Determine our year bin size so that no more than 10 facet.queries are being sent at a time
var binSize = 1;
if((totalYears > 10) && (totalYears <= 20)){
binSize = 2;
}
else if((totalYears > 20) && (totalYears <= 50)){
binSize = 5;
}
else if((totalYears > 50) && (totalYears <= 100)){
binSize = 10;
}
else if(totalYears > 100){
binSize = 25;
}
//Construct our facet.queries for the beginDate and endDates, starting with all years before this current year
var allFacetQueries = [],
key = "";
for(var yearsAgo = yearsFromToday.fromBeginning; yearsAgo >= yearsFromToday.fromEnd; yearsAgo -= binSize){
// The query logic here is: If the beginnning year is anytime before or
// during the last year of the bin AND the ending year is anytime after
// or during the first year of the bin, it counts.
if(binSize == 1){
//Querying for just the current year needs to be treated a bit differently
// and won't be caught in our for loop
if((yearsAgo == 0) && (lastYear == today)){
var oneYearFromNow = new Date();
oneYearFromNow.setFullYear( oneYearFromNow.getFullYear() + 1 );
var now = new Date();
allFacetQueries.push("{!key=" + lastYear + "}(beginDate:[* TO " +
oneYearFromNow.toISOString() + "/YEAR] AND endDate:[" +
now.toISOString() + "/YEAR TO *])");
}
else{
key = today - yearsAgo;
var beginDateLimit = new Date();
beginDateLimit.setFullYear( beginDateLimit.getFullYear() - (yearsAgo-1) );
var endDateLimit = new Date();
endDateLimit.setFullYear( endDateLimit.getFullYear() - yearsAgo );
allFacetQueries.push("{!key=" + key + "}(beginDate:[* TO " +
beginDateLimit.toISOString() + "/YEAR] AND endDate:[" +
endDateLimit.toISOString() + "/YEAR TO *])");
}
}
else if (yearsAgo <= binSize){
key = (today - yearsAgo) + "-" + lastYear;
var beginDateLimit = new Date();
beginDateLimit.setFullYear( beginDateLimit.getFullYear() - yearsFromToday.fromEnd );
var endDateLimit = new Date();
endDateLimit.setFullYear( endDateLimit.getFullYear() - yearsAgo );
allFacetQueries.push("{!key=" + key + "}(beginDate:[* TO " +
beginDateLimit.toISOString() +"/YEAR] AND endDate:[" +
endDateLimit.toISOString() + "/YEAR TO *])");
}
else{
key = (today - yearsAgo) + "-" + (today - yearsAgo + binSize-1);
var beginDateLimit = new Date();
beginDateLimit.setFullYear( beginDateLimit.getFullYear() - (yearsAgo - binSize-1) );
var endDateLimit = new Date();
endDateLimit.setFullYear( endDateLimit.getFullYear() - yearsAgo );
allFacetQueries.push("{!key=" + key + "}(beginDate:[* TO " +
beginDateLimit.toISOString() + "/YEAR] AND endDate:[" +
endDateLimit.toISOString() + "/YEAR TO *])");
}
}
var now = new Date();
//The full query
var specialQueryParams = " AND beginDate:[" + this.firstPossibleDate + " TO " + now.toISOString() + "] AND -obsoletedBy:* AND -formatId:*dataone.org/collections* AND -formatId:*dataone.org/portals*",
query = this.get('query') + specialQueryParams,
rows = "0",
facet = "true",
facetLimit = "30000", //Put some reasonable limit here so we don't wait forever for this query
facetMissing = "true", //We want to retrieve years with 0 results
wt = "json";
var successCallback = function(data, textStatus, xhr) {
model.set('temporalCoverage', data.facet_counts.facet_queries);
}
if( this.get("usePOST") ){
//Get the unencoded query string
if( this.get("postQuery") ){
query = this.get("postQuery") + specialQueryParams;
}
else if( this.get("searchModel") ){
query = this.get("searchModel").getQuery(undefined, { forPOST: true }) + specialQueryParams;
}
var requestData = new FormData();
requestData.append("q", query);
requestData.append("rows", rows);
requestData.append("wt", wt);
requestData.append("facet", facet);
requestData.append("facet.limit", facetLimit);
requestData.append("facet.missing", facetMissing);
_.each(allFacetQueries, function(facetQuery){
requestData.append("facet.query", facetQuery);
});
//Request settings for POST requests
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl'),
data: requestData,
processData: false,
contentType: false,
type: "POST",
dataType: "json",
success: successCallback
}
}
else{
var requestSettings = {
url: MetacatUI.appModel.get('queryServiceUrl') + "q=" + query +
"&rows=" + rows + "&facet=" + facet + "&facet.limit=" + facetLimit +
"&facet.missing=" + facetMissing + "&wt=" + wt +
"&facet.query=" + allFacetQueries.join("&facet.query="),
dataType: "json",
success: successCallback
}
}
$.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings()));
},
imgLoad: function(url) {
// Create new promise with the Promise() constructor;
// This has as its argument a function with two parameters, resolve and reject
var model = this;
return new Promise(function (resolve, reject) {
// Standard XHR to load an image
var request = new XMLHttpRequest();
request.open('GET', url);
request.responseType = 'blob';
// When the request loads, check whether it was successful
request.onload = function () {
if (request.status === 200) {
// If successful, resolve the promise by passing back the request response
resolve(request.response);
} else {
// If it fails, reject the promise with a error message
reject(new Error('Image didn\'t load successfully; error code:' + request.statusText));
model.set('mdqScoresError', request.statusText);
}
};
request.onerror = function () {
console.log("onerror");
// Also deal with the case when the entire request fails to begin with
// This is probably a network error, so reject the promise with an appropriate message
reject(new Error('There was a network error.'));
};
// Send the request
request.send();
});
},
getMdqScores: function(){
try{
var myImage = new Image();
var model = this;
myImage.crossOrigin = ""; // or "anonymous"
if(MetacatUI.appView.currentView === null) return;
// Call the function with the URL we want to load, but then chain the
// promise then() method on to the end of it. This contains two callbacks
var serviceUrl = MetacatUI.appModel.get('mdqScoresServiceUrl');
if( !serviceUrl ){
this.set("mdqScoresImage", this.defaults.mdqScoresImage);
this.trigger("change:mdqScoresImage");
return;
}
if( Array.isArray(MetacatUI.appModel.get('mdqAggregatedSuiteIds')) && MetacatUI.appModel.get('mdqAggregatedSuiteIds').length ){
var suite = MetacatUI.appModel.get('mdqAggregatedSuiteIds')[0];
var id = MetacatUI.appView.currentView.model.get("id");
var url = serviceUrl + "?collection=" + id + "&suite=" + suite;
this.imgLoad(url).then(function (response) {
// The first runs when the promise resolves, with the request.reponse specified within the resolve() method.
var imageURL = window.URL.createObjectURL(response);
myImage.src = imageURL;
model.set('mdqScoresImage', myImage);
// The second runs when the promise is rejected, and logs the Error specified with the reject() method.
}, function (Error) {
console.error(Error);
});
}
else{
this.set("mdqScoresImage", this.defaults.mdqScoresImage);
}
}
catch(e){
this.set("mdqScoresImage", this.defaults.mdqScoresImage);
this.trigger("change:mdqScoresImage");
console.error("Cannot get the Metadata Quality scores: ", e);
}
},
setRequestType: function(){
if( MetacatUI.appModel.get("disableQueryPOSTs") ){
this.set("usePOST", false);
}
else{
if( this.get("query") && this.get("query").length > this.get("maxQueryLength") ){
this.set("usePOST", true);
}
}
}
});
return Stats;
});