cartodb-4.29/lib/assets/javascripts/dashboard/data/visualization-model.js
2020-06-15 10:58:47 +08:00

254 lines
7.0 KiB
JavaScript

const Backbone = require('backbone');
const _ = require('underscore');
const LikeModel = require('dashboard/data/like-model');
const UserModel = require('dashboard/data/user-model');
const PermissionModel = require('dashboard/data/permission-model');
const MapModel = require('dashboard/data/map-model');
const VisualizationOrderModel = require('dashboard/data/visualization-order-model');
const SlideTransition = require('dashboard/data/slide-transition-model');
const MapUrlModel = require('dashboard/data/map-url-model');
const DatasetUrlModel = require('dashboard/data/dataset-url-model');
const CartoTableMetadata = require('dashboard/views/public-dataset/carto-table-metadata');
const checkAndBuildOpts = require('builder/helpers/required-opts');
const REQUIRED_OPTS = [
'configModel'
];
const PRIVACY_OPTIONS = {
public: 'PUBLIC',
link: 'LINK',
private: 'PRIVATE',
password: 'PASSWORD'
};
const VisualizationModel = Backbone.Model.extend({
defaults: {
bindMap: true
},
INHERIT_TABLE_ATTRIBUTES: [
'name', 'description', 'privacy'
],
initialize: function (attrs, opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
this.map = new MapModel({ configModel: this._configModel });
this.permission = new PermissionModel(this.get('permission'), { configModel: this._configModel });
this.order = new VisualizationOrderModel({ visualization: this });
this.transition = new SlideTransition(this.get('transition_options'), { parse: true });
this.like = LikeModel.newByVisData({
vis_id: this.id,
liked: this.get('liked'),
likes: this.get('likes'),
config: this._configModel
});
if (this.get('bindMap')) this._bindMap();
this._initBinds();
},
_initBinds: function () {
this.permission.acl.bind('reset', function () {
// Sync the local permission object w/ the raw data, so vis.save don't accidentally overwrites permissions changes
this.set('permission', this.permission.attributes, { silent: true });
this.trigger('change:permission', this);
}, this);
// Keep permission model in sync, e.g. on vis.save
this.bind('change:permission', function () {
this.permission.set(this.get('permission'));
}, this);
},
_bindMap: function () {
this.on('change:map_id', this._fetchMap, this);
this.map.bind('change:id', function () {
this.set('map_id', this.map.id);
}, this);
this.map.set('id', this.get('map_id'));
},
url: function (method) {
var version = this._configModel.urlVersion('visualization', method);
var base = '/api/' + version + '/viz';
if (this.isNew()) {
return base;
}
return base + '/' + this.id;
},
parse: function (data) {
if (this.transition && data.transition_options) {
this.transition.set(this.transition.parse(data.transition_options));
}
if (this.like) {
this.like.set({
vis_id: this.id,
likes: this.get('likes'),
liked: this.get('liked')
});
}
if (this.owner) {
this.owner = new UserModel(this.owner);
}
return data;
},
toJSON: function () {
var attr = _.clone(this.attributes);
delete attr.bindMap;
delete attr.stats;
delete attr.related_tables;
delete attr.children;
attr.transition_options = this.transition.toJSON();
return attr;
},
getLikesModel: function () {
return this.like;
},
/**
* Create a copy of the visualization model
*/
copy: function (attrs, options) {
attrs = attrs || {};
options = options || {};
var vis = new VisualizationModel(
_.extend({
source_visualization_id: this.id
},
attrs
),
{ configModel: this._configModel }
);
vis.save(null, options);
return vis;
},
/**
* Fetch map information
*/
_fetchMap: function () {
this.map
.set('id', this.get('map_id'))
.fetch();
},
/**
* Get the URL for current instance.
* @param {Object} currentUser (Optional) Get the URL from the perspective of the current user, necessary to
* correctly setup URLs to tables.
* @return {Object} instance of cdb.common.Url
*/
viewUrl: function (currentUser) {
const owner = this.permission.owner;
let userUrl = this.permission.owner.viewUrl();
// the undefined check is required for backward compability, in some cases (e.g. dependant visualizations) the type
// is not available on the attrs, if so assume the old behavior (e.g. it's a visualization/derived/map).
if (this.isVisualization() || _.isUndefined(this.get('type'))) {
let id = this.get('id');
if (currentUser && currentUser.id !== owner.id && this.permission.hasAccess(currentUser)) {
userUrl = currentUser.viewUrl();
id = owner.get('username') + '.' + id;
}
return new MapUrlModel({
base_url: userUrl.urlToPath('viz', id)
});
} else {
if (currentUser && this.permission.hasAccess(currentUser)) {
userUrl = currentUser.viewUrl();
}
return new DatasetUrlModel({
base_url: userUrl.urlToPath('tables', this.tableMetadata().getUnquotedName())
});
}
},
// return: Array of entities (user or organizations) this vis is shared with
sharedWithEntities: function () {
return _.map((this.permission.acl.toArray() || []), function (aclItem) {
return aclItem.get('entity');
});
},
/**
* Is this model a true visualization?
*/
isVisualization: function () {
return this.get('type') === 'derived' || this.get('type') === 'slide';
},
/**
* Get table metadata related to this vis.
* Note that you might need to do a {metadata.fetch()} to get full data.
*
* @returns {CartoTableMetadata} if this vis represents a table
* TODO: when and when isn't it required to do a fetch really?
*/
tableMetadata: function () {
if (!this._metadata) {
this._metadata = new CartoTableMetadata(this.get('table'), { configModel: this._configModel });
}
return this._metadata;
},
getTableModel: function () {
if (!this._metadata) {
this._metadata = new CartoTableMetadata(this.get('table'), { configModel: this._configModel });
}
return this._metadata;
},
privacyOptions: function () {
const privacyOptions = _.values(PRIVACY_OPTIONS);
if (this.isVisualization()) {
return privacyOptions;
} else {
return _.filter(privacyOptions, option => option !== 'PASSWORD');
}
},
isRaster: function () {
return this.get('kind') === 'raster';
},
getPermissionModel: function () {
return this.permission;
},
getSynchronizationModel: function () {
return this._synchronizationModel;
},
mapcapsURL: function () {
var baseUrl = this._configModel.get('base_url');
return baseUrl + '/api/v3/viz/' + this.id + '/mapcaps';
}
}, {
isPubliclyAvailable: function (privacyStatus) {
return privacyStatus === PRIVACY_OPTIONS.password ||
privacyStatus === PRIVACY_OPTIONS.link ||
privacyStatus === PRIVACY_OPTIONS.public;
}
});
module.exports = VisualizationModel;