/* globals window, URL, localStorage */
var FieldDBObject = require("./../FieldDBObject").FieldDBObject;
var Diacritics = require("diacritics");
/**
* @class Corpus connections by default define a set of web services which are used by that corpus,
* generally on one server. However, over time and use the user might move their audio data to
* different servers etc making it more conveint to provide a configuration object which by
* convention is the same server, but can be overriden and read by any of the client apps or
* webservices. The central authority for a users" corpus is in the user's details on the
* user's authentication server.
*
* This class contains basic functions to manipulate CorpusConection json and schema,
* can be used as a shared model between clients and servers
*
*
*
* @param {Connection} optionalRequestedConnection a object with minimally a dbname
*
* @param {string} dbname a name space for the database also a url friendly permanent
* datbase name (composed of a username and an identifier)
*
* @param {string} corpusid a uuid of the corpus doc within the database which defines the corpus
* @param {string} dbname @deprecated use dbname instead
* @param {string} protocol @deprecated [https:, http] use corpusUrls instead
* @param {string} domain @deprecated use corpusUrls instead
* @param {string} port @deprecated use corpusUrls instead
* @param {string} path @deprecated use corpusUrls instead was used for McGill server
*
* @param {string} userFriendlyServerName a server name that represents where (most of) the user's resources are
* for this corpus [Default, Beta, Original, Mcgill Prosody, Localhost, etc]
*
* @param {array} clientUrls an array of objects {"userFriendlyClientName" :
* [Spreadsheet, Prototype Online, Localhost Chrome App, Public Url, Acivity Feed, etc],
* url": completeUrlThatCouldBringSomeoneStraightToThisCorpus}
* @param {array} corpusUrls an array of urls which could "compose" this corpus either by overllapping
* or by union (for the users who want to have meta corpora which combine multiple
* smaller corpora, or users with large corpora who would like to shard it across servers)
* @param {array} audioUrls an array of audio/video/speech webservice urls which can be used with
* this corpus, could be youtube, sound cloud or other storage with or
* without a one-to-one mapping of namespace with this corpus
* @param {array} activityUrls an array of activity feed urls where this corpus"s activities should
* be stored (usually only one, but oculd have the active one in
* position 0 and other older ones afterwards)
*
* @param {array} authUrls an array of strings indicating where a user could login to get to this corpus
* @param {array} lexiconUrls an array of lexicon urls which can be used with this corpus
* @param {array} searchUrls an array of search urls which can be used with this corpus
*
* @name Connection
* @extends FieldDBObject
* @constructs
*/
var Connection = function Connection(options) {
if (!this._fieldDBtype) {
this._fieldDBtype = "Connection";
}
this.debug("Constructing Connection ", options);
if (options) {
var cleanDefaultValues = ["dbname", "pouchname", "title", "titleAsUrl"];
cleanDefaultValues.map(function(cleanMe) {
if (options[cleanMe] === "default") {
options[cleanMe] = "";
}
});
}
FieldDBObject.apply(this, arguments);
};
Connection.DEFAULT_LOCALHOST_CONNECTION = function(options) {
return {
"corpusid": "TBA",
"dbname": options.dbname,
"protocol": "https://",
"domain": "localhost",
"port": "3183",
"path": "",
"userFriendlyServerName": "Localhost",
"authUrls": ["https://localhost:3182"],
"clientUrls": [{
"userFriendlyClientName": "Spreadsheet",
"url": "chrome-extension://pcflbgejbbgijjbmaodhhbibegdfecjc/index.html"
}, {
"userFriendlyClientName": "Prototype Online",
"url": "https://localhost:6984/" + options.dbname + "/_design/data/corpus.html"
}, {
"userFriendlyClientName": "Localhost Chrome App",
"url": "chrome-extension://kaaemcdklbfiiaihlnkmknkgbnkamcbh/user.html#corpus/" + options.dbname
}, {
"userFriendlyClientName": "Public Url",
"url": "https://localhost:3182/" + options.username + "/" + options.corpusidentifier + "/" + options.dbname
}, {
"userFriendlyClientName": "Activity Feed",
"url": "https://localhost:6984/" + options.dbname + "-activity_feed/_design/activity/activity_feed.html"
}],
"corpusUrls": ["https://localhost:6984/" + options.dbname],
"lexiconUrls": ["https://localhost:3185/train/lexicon/" + options.dbname],
"searchUrls": ["https://localhost:3195/search/" + options.dbname],
"audioUrls": ["https://localhost:3184/" + options.dbname + "/utterances"],
"activityUrls": ["https://localhost:6984/" + options.dbname + "-activity_feed"]
};
};
Connection.prototype = Object.create(FieldDBObject.prototype, /** @lends Connection.prototype */ {
constructor: {
value: Connection
},
INTERNAL_MODELS: {
value: {
corpusid: FieldDBObject.DEFAULT_STRING,
titleAsUrl: FieldDBObject.DEFAULT_STRING,
dbname: FieldDBObject.DEFAULT_STRING,
pouchname: FieldDBObject.DEFAULT_STRING,
protocol: FieldDBObject.DEFAULT_STRING,
domain: FieldDBObject.DEFAULT_STRING,
port: FieldDBObject.DEFAULT_STRING,
path: FieldDBObject.DEFAULT_STRING,
userFriendlyServerName: FieldDBObject.DEFAULT_STRING,
authUrls: FieldDBObject.DEFAULT_ARRAY,
clientUrls: FieldDBObject.DEFAULT_ARRAY,
corpusUrls: FieldDBObject.DEFAULT_ARRAY,
lexiconUrls: FieldDBObject.DEFAULT_ARRAY,
searchUrls: FieldDBObject.DEFAULT_ARRAY,
audioUrls: FieldDBObject.DEFAULT_ARRAY,
websiteUrls: FieldDBObject.DEFAULT_ARRAY,
activityUrls: FieldDBObject.DEFAULT_ARRAY
}
},
guessDbType: {
value: function(value) {
if (!value) {
return;
}
var dbType;
if (value.indexOf("activity_feed") > -1) {
if (value.split("-").length >= 3) {
dbType = "corpus_activity_feed";
} else {
dbType = "user_activity_feed";
}
} else {
dbType = "corpus";
}
return dbType;
}
},
dbname: {
get: function() {
if (this.parent && this.parent.dbname) {
return this.parent.dbname;
}
return this._dbname;
},
set: function(value) {
if (value === this._dbname) {
return;
}
if (!value) {
delete this._dbname;
return;
} else {
if (typeof value.trim !== "function") {
return;
}
value = value.trim();
if (value !== "default") {
var pieces = value.split("-");
var username = pieces.shift();
var corpusidentifier = pieces.join("-");
username = Connection.validateUsername(username);
corpusidentifier = Connection.validateIdentifier(corpusidentifier);
if (username.changes && username.changes.length > 0) {
this.warn(username.changes.join("; "), username.originalIdentifier);
}
if (corpusidentifier.changes && corpusidentifier.changes.length > 0) {
this.warn(corpusidentifier.changes.join("; "), corpusidentifier.originalIdentifier);
}
value = username.identifier + "-" + corpusidentifier.identifier;
}
}
this._dbname = value;
}
},
owner: {
get: function() {
if (!this.dbname) {
return;
}
var pieces = this.dbname.split("-");
// if (pieces.length !== 2 && this.dbname.indexOf("-activity_feed") !== (this.dbname.length - "-activity_feed".length) ){
// throw new Error("Database names should be composed of a username-datbaseidentifier " + this.dbname);
// }
var username = pieces[0];
return username;
}
},
gravatar: {
get: function() {
if (this.parent && this.parent.gravatar) {
this._gravatar = this.parent.gravatar;
// } else if (this.parent.team.gravatar) { // Dont use team gravatars for corpus connection gravatars anymore
// this._gravatar = this.parent.team.gravatar;
} else if (!this._gravatar && this.dbname && this.parent.team && typeof this.parent.team.buildGravatar === "function") {
this._gravatar = this.parent.team.buildGravatar(this.dbname);
}
return this._gravatar;
},
set: function(value) {
if (value === this._gravatar) {
return;
}
if (!value) {
delete this._gravatar;
return;
} else {
if (typeof value.trim === "function") {
value = value.trim();
}
}
this._gravatar = value;
}
},
corpusid: {
get: function() {
if (!this._corpusid && this.parent && this.parent.id && this.parent.rev && typeof this.parent.normalizeFieldWithExistingCorpusFields === "function") {
this._corpusid = this.parent.id;
}
return this._corpusid;
},
set: function(value) {
if (value === this._corpusid) {
return;
}
if (!value) {
delete this._corpusid;
return;
} else {
if (typeof value.trim === "function") {
value = value.trim();
}
}
this._corpusid = value;
}
},
description: {
get: function() {
if (this.parent && this.parent.description) {
this._description = this.parent.description;
if (this._description.length > 220) {
this._description = this._description.substring(0, 200) + "...";
}
this.debug("returned this.parent.description", this.parent.id);
}
return this._description;
},
set: function(value) {
if (value === this._description) {
return;
}
if (!value) {
delete this._description;
return;
} else {
if (typeof value.trim === "function") {
value = value.trim();
}
}
this._description = value;
}
},
title: {
get: function() {
if (this.parent && this.parent.title) {
this._title = this.parent.title;
this.debug("returned this.parent.title", this.parent.id);
}
if (!this._title && this.dbname) {
this._title = this.dbname.replace(this.owner + "-", "");
}
return this._title;
},
set: function(value) {
if (value === this._title) {
return;
}
if (!value) {
delete this._title;
return;
} else {
if (typeof value.trim === "function") {
value = value.trim();
}
}
this._title = value;
this._titleAsUrl = "";
}
},
titleAsUrl: {
get: function() {
if (this.parent && this.parent.titleAsUrl) {
this._titleAsUrl = this.parent.titleAsUrl;
}
if (!this._titleAsUrl) {
if (this.title) {
this._titleAsUrl = this.sanitizeStringForFileSystem(this.title, "_").toLowerCase();
} else {
if (this.dbname) {
this._title = this._titleAsUrl = this.dbname.replace(this.owner + "-", "");
}
}
}
return this._titleAsUrl;
},
set: function(value) {
if (value === this._titleAsUrl) {
return;
}
if (!value) {
delete this._titleAsUrl;
return;
} else {
if (typeof value.trim === "function") {
value = value.trim();
}
}
this._titleAsUrl = value;
}
},
authUrl: {
get: function() {
if (this.authUrls && this.authUrls[0]) {
return this.authUrls[0];
}
return "";
},
set: function(value) {
if (this.authUrls && value === this.authUrls[0]) {
return;
}
if (!value) {
return;
} else {
if (typeof value.trim === "function") {
value = value.trim();
}
value = value.replace(/[^.\/]*.fieldlinguist.com:3183/g, "auth.lingsync.org");
}
if (!this.authUrls) {
this.authUrls = [value];
} else if (this.authUrls.length === 0) {
this.authUrls.unshift(value);
} else {
var alreadyKnown = this.authUrls.indexOf(value);
if (alreadyKnown > -1) {
this.authUrls.splice(alreadyKnown, 1);
}
this.authUrls.unshift(value);
}
}
},
domain: {
get: function() {
return this._domain || "";
},
set: function(value) {
if (value === this._domain) {
return;
}
if (!value) {
delete this._domain;
return;
} else {
if (typeof value.trim === "function") {
value = value.trim();
value = value.replace(/ifielddevs.iriscouch.com/g, "corpus.lingsync.org");
}
}
this._domain = value;
}
},
corpusUrl: {
get: function() {
var corpusurl;
this.corpusUrls = Connection.cleanCorpusUrls(this.corpusUrls);
if (this.corpusUrls && this.corpusUrls[0]) {
corpusurl = this.corpusUrls[0];
if (this.dbname && corpusurl.indexOf(this.dbname) === -1) {
// if its a couchdb, use the dbname in the url
if (corpusurl.indexOf("984") > -1 || corpusurl.indexOf("https://corpusdev.") > -1 || corpusurl.indexOf("https://corpus.") > -1) {
corpusurl = corpusurl + "/" + this.dbname;
}
}
return corpusurl;
}
if (!this.domain || !this.dbname) {
return "";
}
corpusurl = this.protocol + this.domain;
if (this.port && this.port !== "443" && this.port !== "80") {
corpusurl = corpusurl + ":" + this.port;
}
var path = this.path || "";
if (path) {
path = "/" + path;
}
corpusurl = corpusurl + path;
corpusurl = corpusurl + "/" + this.dbname;
corpusurl = corpusurl.replace("http://localhost:5984", "https://localhost:6984");
/*
* For debugging cors #838: Switch to use the corsproxy corpus service instead
* of couchdb directly
*/
// corpusurl = corpusurl.replace(/https/g,"http").replace(/6984/g,"3186");
this.corpusUrls = [corpusurl];
return corpusurl;
},
set: function(value) {
if (this.corpusUrls && value === this.corpusUrls[0]) {
return;
}
if (!value) {
return;
} else {
if (typeof value.trim === "function") {
value = value.trim();
value = value.replace("http://localhost:5984", "https://localhost:6984");
}
}
if (!this.corpusUrls) {
this.corpusUrls = [value];
} else if (this.corpusUrls.length === 0) {
this.corpusUrls.unshift(value);
} else {
this.corpusUrls = Connection.cleanCorpusUrls(this.corpusUrls);
var alreadyKnown = this.corpusUrls.indexOf(value);
if (alreadyKnown > -1) {
this.corpusUrls.splice(alreadyKnown, 1);
}
this.corpusUrls.unshift(value);
}
}
},
websiteUrl: {
get: function() {
if (this.websiteUrls && this.websiteUrls[0]) {
return this.websiteUrls[0];
}
},
set: function(value) {
if (this.websiteUrls && value === this.websiteUrls[0]) {
return;
}
if (!value) {
return;
} else {
if (typeof value.trim === "function") {
value = value.trim();
}
}
if (!this.websiteUrls) {
this.websiteUrls = [value];
} else if (this.websiteUrls.length === 0) {
this.websiteUrls.unshift(value);
} else {
var alreadyKnown = this.websiteUrls.indexOf(value);
if (alreadyKnown > -1) {
this.websiteUrls.splice(alreadyKnown, 1);
}
this.websiteUrls.unshift(value);
}
}
},
website: {
get: function() {
return this.websiteUrl;
},
set: function(value) {
this.websiteUrl = value;
}
},
brand: {
get: function() {
return this.userFriendlyServerName;
},
set: function(value) {
this.userFriendlyServerName = value;
}
},
brandLowerCase: {
get: function() {
return this._brandLowerCase || this.serverLabel || "";
},
set: function(value) {
this._brandLowerCase = value;
}
},
replicatedCorpusUrls: {
get: function() {
return this._replicatedCorpusUrls || FieldDBObject.DEFAULT_COLLECTION;
},
set: function(value) {
if (value === this._replicatedCorpusUrls) {
return;
}
if (!value) {
delete this._replicatedCorpusUrls;
return;
}
this._replicatedCorpusUrls = value;
}
},
olacExportConnections: {
get: function() {
return this._olacExportConnections || FieldDBObject.DEFAULT_COLLECTION;
},
set: function(value) {
if (value === this._olacExportConnections) {
return;
}
if (!value) {
delete this._olacExportConnections;
return;
}
this._olacExportConnections = value;
}
},
toJSON: {
value: function(includeEvenEmptyAttributes, removeEmptyAttributes) {
this.debug("Customizing toJSON ", includeEvenEmptyAttributes, removeEmptyAttributes);
includeEvenEmptyAttributes = true;
this.debug(" forcing corpusUrls to be defined ", this.corpusUrl);
this.corpusUrls = Connection.cleanCorpusUrls(this.corpusUrls);
this.brandLowerCase = this.brandLowerCase;
var json = FieldDBObject.prototype.toJSON.apply(this, arguments);
delete json.dateCreated;
delete json.dateModified;
delete json.database;
// TODO eventually dont include the label and hint but now include it for backward compaitibilty
json.pouchname = json.dbname = this.dbname || "";
json.title = this.title || json.dbname;
json.titleAsUrl = this.titleAsUrl || json.dbname;
json.fieldDBtype = this.fieldDBtype;
delete json._type;
this.debug(json);
return json;
}
}
});
/*
* This function is the same in all webservicesconfig, now any couchapp can
* login to any server, and register on the corpus server which matches its
* origin.
*/
Connection.knownConnections = {
localhost: new Connection({
protocol: "https://",
domain: "localhost",
port: "6984",
dbname: "default",
path: "",
serverLabel: "localhost",
authUrls: ["https://localhost:3183"],
websiteUrls: ["https://localhost:3182"],
corpusUrls: ["https://localhost:6984"],
userFriendlyServerName: "Localhost"
}),
beta: new Connection({
protocol: "https://",
domain: "corpusdev.lingsync.org",
port: "443",
dbname: "default",
path: "",
serverLabel: "beta",
brandLowerCase: "lingsync_beta",
authUrls: ["https://authdev.lingsync.org"],
websiteUrls: ["http://lingsync.org"],
corpusUrls: ["https://corpusdev.lingsync.org"],
userFriendlyServerName: "LingSync Beta"
}),
lingsync: new Connection({
protocol: "https://",
domain: "corpus.lingsync.org",
port: "443",
dbname: "default",
path: "",
serverLabel: "production",
brandLowerCase: "lingsync",
authUrls: ["https://auth.lingsync.org"],
websiteUrls: ["http://lingsync.org"],
corpusUrls: ["https://corpus.lingsync.org"],
userFriendlyServerName: "LingSync.org"
}),
mcgill: new Connection({
protocol: "https://",
domain: "corpus.lingsync.org",
port: "443",
dbname: "default",
path: "",
serverLabel: "mcgill",
authUrls: ["https://auth.lingsync.org"],
websiteUrls: ["http://lingsync.org"],
corpusUrls: ["https://corpus.lingsync.org"],
userFriendlyServerName: "McGill ProsodyLab"
}),
concordia: new Connection({
protocol: "https://",
domain: "corpus.lingsync.org",
port: "443",
dbname: "default",
path: "",
serverLabel: "concordia",
authUrls: ["https://auth.lingsync.org"],
websiteUrls: ["http://lingsync.org"],
corpusUrls: ["https://corpus.lingsync.org"],
userFriendlyServerName: "Concordia Linguistics"
})
};
Connection.knownConnections.production = Connection.knownConnections.lingsync;
Connection.knownConnections.development = Connection.knownConnections.beta;
// Connection.knownConnections.test = Connection.knownConnections.beta;
/**
* Set otherwise to be the default connection of this app.
*
* By Default, apps will try to contact NODE_ENV,
* if in a browser they will try to contact beta unless you specify Connection.otherwise
*/
Connection.otherwise = null;
Connection.defaultConnection = function(optionalHREF, passAsReference) {
/*
* If its a couch app, it can only contact databases on its same origin, so
* modify the domain to be that origin. the chrome extension can contact any
* authorized server that is authorized in the chrome app's manifest
*/
var connection;
var otherwise;
try {
otherwise = process.env.NODE_ENV;
} catch (e) {
}
if (!otherwise) {
try {
otherwise = localStorage.getItem("serverLabel");
} catch (e) {
// not running in node nor normal browser environment.
}
}
if (FieldDBObject.application && FieldDBObject.application.serverLabel) {
otherwise = FieldDBObject.application.serverLabel;
}
otherwise = otherwise || Connection.otherwise || "beta";
if (!Connection.knownConnections[otherwise]){
FieldDBObject.bug("I dont know how to connect to " + otherwise + " please report this.");
throw new Error("I dont know how to connect to " + otherwise + " please report this.");
}
/* Ensuring at least the localhost connection is known */
if (!Connection.knownConnections) {
Connection.knownConnections = {};
}
if (!Connection.knownConnections.localhost) {
Connection.knownConnections.localhost = new Connection({
protocol: "https://",
domain: "localhost",
port: "6984",
dbname: "default",
path: "",
serverLabel: "localhost",
brandLowerCase: "localhost",
authUrls: ["https://localhost:3183"],
corpusUrls: ["https://localhost:6984"],
userFriendlyServerName: "Localhost"
});
}
if (!optionalHREF && FieldDBObject.application && FieldDBObject.application.connection) {
connection = FieldDBObject.application.connection;
optionalHREF = connection.serverLabel;
}
if (!optionalHREF) {
try {
if (window && window.location) {
optionalHREF = window.location.href;
} else {
connection = Connection.knownConnections[otherwise];
optionalHREF = connection.authUrls[0];
}
} catch (e) {
connection = Connection.knownConnections[otherwise];
// if they specified an otherwise that doesnt exist correct it
// to use beta
if (!connection) {
FieldDBObject.bug("I dont know how to connect to " + otherwise + " please report this.");
throw new Error("I dont know how to connect to " + otherwise + " please report this.");
}
optionalHREF = connection.authUrls[0];
}
}
if (Connection.knownConnections[optionalHREF]) {
connection = Connection.knownConnections[optionalHREF];
} else if (optionalHREF.indexOf("_design/") > -1) {
if (optionalHREF.indexOf("corpusdev.lingsync.org") >= 0) {
connection = Connection.knownConnections.beta;
} else if (optionalHREF.indexOf("lingsync.org") >= 0) {
connection = Connection.knownConnections.production;
} else if (optionalHREF.indexOf("prosody.linguistics.mcgill") >= 0) {
connection = Connection.knownConnections.mcgill;
} else if (optionalHREF.indexOf("localhost") >= 0) {
connection = Connection.knownConnections.localhost;
}
} else {
if (optionalHREF.indexOf("jlbnogfhkigoniojfngfcglhphldldgi") >= 0) {
connection = Connection.knownConnections.mcgill;
} else if (optionalHREF === "LingSync Beta") {
connection = Connection.knownConnections.beta;
} else if (optionalHREF === "LingSync Testing") {
connection = Connection.knownConnections.beta;
} else if (optionalHREF === "LingSync") {
connection = Connection.knownConnections.production;
} else if (optionalHREF === "Localhost") {
connection = Connection.knownConnections.localhost;
} else if (optionalHREF === "McGill ProsodyLab") {
connection = Connection.knownConnections.mcgill;
} else if (optionalHREF === "Concordia") {
connection = Connection.knownConnections.concordia;
} else if (optionalHREF.indexOf("eeipnabdeimobhlkfaiohienhibfcfpa") >= 0) {
connection = Connection.knownConnections.beta;
} else if (optionalHREF.indexOf("ocmdknddgpmjngkhcbcofoogkommjfoj") >= 0) {
connection = Connection.knownConnections.production;
} else if (optionalHREF.indexOf("dev.lingsync.org") >= 0) {
connection = Connection.knownConnections.beta;
} else if (optionalHREF.indexOf("lingsync.org") >= 0) {
connection = Connection.knownConnections.production;
} else if (optionalHREF.indexOf("prosody.linguistics.mcgill") >= 0) {
connection = Connection.knownConnections.mcgill;
} else if (optionalHREF.indexOf("linguistics.concordia") >= 0) {
connection = Connection.knownConnections.concordia;
} else if (optionalHREF.indexOf("lingsync") >= 0) {
connection = Connection.knownConnections.production;
} else if (optionalHREF.indexOf("localhost") >= 0) {
connection = Connection.knownConnections.localhost;
} else if (optionalHREF.indexOf("chrome-extension") === 0) {
connection = Connection.knownConnections[otherwise];
} else if (optionalHREF.indexOf("file") === 0) {
connection = Connection.knownConnections[otherwise];
}
}
if (!connection) {
console.warn("The user is trying to use a server which is unknown to the system. Attempting to construct its connection. ", optionalHREF);
var connectionUrlObject;
try {
if (!Connection.URLParser) {
Connection.URLParser = URL;
}
} catch (e) {
console.log("Cant figure out what the URL parser is");
Connection.URLParser = {
parse: function(url) {
console.warn("Not parsing this url", url);
return {};
}
};
}
try {
connectionUrlObject = new Connection.URLParser(optionalHREF);
} catch (e) {
if (e.message.indexOf("Invalid URL") === -1) {
connectionUrlObject = Connection.URLParser.parse(optionalHREF);
}
// console.log("Cant use new Connection.URLParser() in this environment.", connectionUrlObject);
}
if (!connectionUrlObject || !connectionUrlObject.hostname) {
console.warn("There was no way to deduce the HREF, probably we are in Node or loading from a file://. Using " + otherwise + " instead. ", optionalHREF);
connection = Connection.knownConnections[otherwise];
} else {
var domainName = connectionUrlObject.hostname.split(".");
while (domainName.length > 2) {
domainName.shift();
}
domainName = domainName.join(".");
connection = new Connection({
protocol: connectionUrlObject.protocol + "//",
domain: connectionUrlObject.hostname,
port: connectionUrlObject.port,
dbname: "default",
path: connectionUrlObject.pathname.replace("/", ""),
serverLabel: domainName.substring(0, domainName.lastIndexOf(".")),
brandLowerCase: domainName.substring(0, domainName.lastIndexOf(".")),
authUrls: [optionalHREF],
userFriendlyServerName: domainName
});
Connection.knownConnections[connection.serverLabel] = connection;
}
}
if (!passAsReference) {
// console.log("connection is", connection);
return connection.clone();
}
return connection;
};
/**
* Ensures that dbnames can be used inside of corpus identifiers, which are couchdb database names.
*
* @param {string} originalIdentifier the desired dbname or username
* @return {object} the resulting dbname or username, the original dbname, and the changes that were applied.
*/
Connection.validateIdentifier = function(originalIdentifier, username) {
if (!originalIdentifier) {
return {
changes: ["Identifier was empty"]
};
}
var identifier = originalIdentifier.toString();
var changes = [];
if (identifier.toLowerCase() !== identifier) {
changes.push("The identifier has to be lowercase so that it can be used in your CouchDB database names.");
identifier = identifier.toLowerCase();
}
if (identifier.split("-").length > 1) {
if (username) {
identifier = identifier.replace(/-/g, "");
changes.push("We are using - as a reserved symbol in database URIs (Uniform Resource Identifiers), so you can't use it in your username.");
} else {
// permit the all - which might be in the username or the database
// identifier = identifier.replace("-", ":::").replace(/-/g, "_").replace(":::", "-");
}
}
if (Diacritics.remove(identifier) !== identifier) {
changes.push("You have to use ascii characters in your identifiers because your identifier is used in your in web urls, so its better if you can use something more web friendly.");
identifier = Diacritics.remove(identifier);
}
if (identifier.replace(/[^a-z0-9_-]/g, "_") !== identifier) {
changes.push("You have some characters which web servers wouldn't trust in your identifier.");
if (username) {
identifier = identifier.replace(/[^a-z0-9_-]/g, "");
} else {
identifier = identifier.replace(/[^a-z0-9_-]/g, "_");
}
}
if (identifier.length < 2) {
changes.push("Your identifier is really too short.");
}
if (changes.length > 0) {
changes.unshift("You asked to use " + originalIdentifier + " but we would reccomend using this instead: " + identifier + " the following are a list of reason's why.");
}
return {
"identifier": identifier,
"original": originalIdentifier,
"changes": changes
};
};
Connection.validateUsername = function(originalIdentifier) {
return Connection.validateIdentifier(originalIdentifier, "username");
};
Connection.cleanCorpusUrls = function(corpusUrls) {
if (!corpusUrls || !corpusUrls.length) {
return corpusUrls;
}
var defaultUrls = [];
for (var connection in Connection.knownConnections) {
if (!Connection.knownConnections.hasOwnProperty(connection)) {
continue;
}
defaultUrls = defaultUrls.concat(Connection.knownConnections[connection].corpusUrls);
}
while (corpusUrls.length && defaultUrls.indexOf(corpusUrls[0]) > -1) {
corpusUrls.shift();
}
return corpusUrls;
};
/**
* This is the base schema of a corpus connection, other fields may be added.
* This schema is used by the API docs, it should be updated as the above newConnection changes.
*
* @type {Object}
*/
Connection.baseSchema = {
"id": "Connection",
"properties": {
"corpusid": {
"type": "string"
},
"dbname": {
"type": "string"
},
"pouchname": {
"type": "string"
},
"protocol": {
"type": "string"
},
"domain": {
"type": "string"
},
"port": {
"type": "string"
},
"path": {
"type": "string"
},
"authUrl": {
"items": {
"$ref": "string"
},
"type": "Array"
},
"clientUrls": {
"items": {
"$ref": "ClientApp"
},
"type": "Array"
},
"corpusUrls": {
"items": {
"$ref": "string"
},
"type": "Array"
},
"lexiconUrls": {
"items": {
"$ref": "string"
},
"type": "Array"
},
"searchUrls": {
"items": {
"$ref": "string"
},
"type": "Array"
},
"audioUrls": {
"items": {
"$ref": "string"
},
"type": "Array"
}
}
};
exports.Connection = Connection;