ionic
Version:
A tool for creating and developing Ionic Framework mobile apps.
467 lines (390 loc) • 12.9 kB
JavaScript
var fs = require('fs'),
path = require('path'),
parseUrl = require('url').parse,
request = require('request'),
argv = require('optimist').argv,
prompt = require('prompt'),
FormData = require('form-data'),
IonicProject = require('./project'),
IonicTask = require('./task').IonicTask,
IonicStats = require('./stats').IonicStats;
Task = require('./task').Task,
IonicAppLib = require('ionic-app-lib'),
Login = IonicAppLib.login,
LoginTask = require('./login');
// IonicLoginTask = require('./login').IonicTask;
var IonicTask = function() {};
IonicTask.prototype = new Task();
IonicTask.prototype.run = function(ionic, argv) {
var self = this;
self.ionic = ionic;
self.inputValues = {};
self.inputFiles = {};
self.useCmdArgs = false;
this.getCmdLineOptions();
Login.retrieveLogin()
.then(function(jar){
if (!jar) {
console.log('No previous login existed. Attempting to log in now.');
return LoginTask.login(argv);
}
return jar;
})
.then(function(jar) {
self.jar = jar;
if (argv._[1] && argv._[1].trim() == 'webhook_url') {
if (argv._[2]) {
self.set_webhook_url(self, argv._[2].trim());
} else {
console.log('You need to specify a webhook url!'.bold.red);
}
} else if (argv['google-api-key']) {
self.set_google_api_key(self, argv['google-api-key'].trim());
} else if (argv['send'] || argv.s) {
// Dev wants to send a push notification
self.send_push(self);
} else if (argv['ios-dev-cert'] || argv['ios-prod-cert'] || argv.d || argv.p) {
// Dev wants to upload an ios push cert
self.upload_cert(self);
} else if (argv['production-mode'] || argv.l) {
// Dev wants to switch between test/live mode
// this will look like --live-mode=[y/n]
// where y will put into live and n will put into dev
self.set_production_mode(self);
}
})
.catch(function(ex) {
console.log('An error occurred', ex);
})
};
IonicTask.prototype.set_webhook_url = function(self, webhook_url) {
var project = IonicProject.load();
if (!project.get('app_id')) {
console.log("You need to upload your app first!".bold.red);
return false;
}
var url = self.ionic.IONIC_DASH + self.ionic.IONIC_API + 'app/' + project.get('app_id') + '/push/webhook-url';
var params = parseUrl(url);
var form = new FormData();
form.append('csrfmiddlewaretoken', self.getCsrfToken(self.jar));
form.append('webhook_url', webhook_url);
form.submit({
protocol: params.protocol,
hostname: params.hostname,
port: params.port,
path: params.path,
headers: form.getHeaders({
cookie: self.jar.map(function(c) {
return c.key + "=" + encodeURIComponent(c.value);
}).join("; ")
})
},
function (err, response) {
response.on("data", function(data) {
if (err) {
return self.ionic.fail('Error setting Webhook URL: ' + err);
}
if (response.statusCode == '200') {
console.log("Webhook URL set to", webhook_url);
} else {
return self.ionic.fail('App not found');
}
})
}
);
return true;
};
IonicTask.prototype.set_google_api_key = function(self, google_api_key) {
var project = IonicProject.load();
if (!project.get('app_id')) {
console.log("You need to upload your app first!".bold.red);
return false;
}
var url = self.ionic.IONIC_DASH + self.ionic.IONIC_API + 'app/' + project.get('app_id') + '/push/google-api-key';
var params = parseUrl(url);
var form = new FormData();
form.append('csrfmiddlewaretoken', self.getCsrfToken(self.jar));
form.append('android_api_key', google_api_key);
form.submit({
protocol: params.protocol,
hostname: params.hostname,
port: params.port,
path: params.path,
headers: form.getHeaders({
cookie: self.jar.map(function(c) {
return c.key + "=" + encodeURIComponent(c.value);
}).join("; ")
})
},
function (err, response) {
response.on("data", function(data) {
if (err) {
return self.ionic.fail('Error setting Google API Key: ' + err);
}
if (response.statusCode == '200') {
console.log("Google API Key Saved".green);
} else {
return self.ionic.fail('App not found');
}
})
}
);
return true;
};
IonicTask.prototype.send_push = function(self) {
var project = IonicProject.load();
if (!project.get('app_id')) {
console.log("You need to upload your app first!".bold.red);
return false;
}
// So, we need the push API key to send notifications.
var promptProperties = {};
promptProperties['push-api-key'] = {
name: 'push-api-key',
description: 'Your private API key'.yellow.bold,
required: true,
isFile: false
};
promptProperties['device-token'] = {
name: 'device-token',
description: 'Device token'.yellow.bold,
required: true,
isFile: false
}
promptProperties['alert'] = {
name: 'alert',
description: 'Notification alert message'.yellow.bold,
required: false,
isFile: false
};
promptProperties['badge'] = {
name: 'badge',
description: 'Badge count'.yellow.bold,
required: false,
isFile: false
}
promptProperties['sound'] = {
name: 'sound',
description: 'Sound file name'.yellow.bold,
required: false,
isFile: false
}
prompt.start();
prompt.get({properties: promptProperties}, function(err, promptResult) {
if (err) {
return self.ionic.fail('Error: ' + err);
}
var api_key = promptResult['push-api-key'];
var notification = {
platform: 'ios',
tokens: [promptResult['device-token']],
notification: {
alert: promptResult['alert'],
ios: {
badge: promptResult['badge'],
sound: promptResult['sound']
}
}
}
var options = {
url: 'https://push.ionic.io/api/v1/push',
method: 'POST',
json: true,
headers: {
'X-Ionic-Application-Id': project.get('app_id'),
'authorization': 'Basic ' + new Buffer(api_key + ':').toString('base64')
},
body: notification
};
request(options, function(err, response, body) {
if (!err && response.statusCode == 202) {
console.log("Successfully queued push notification");
} else {
console.log("Error queueing push notification", err);
}
});
});
};
IonicTask.prototype.set_production_mode = function(self) {
var project = IonicProject.load();
if (!project.get('app_id')) {
console.log("You need to upload your app first!".bold.red);
return false;
}
if (self.inputValues['production-mode'] === true) {
console.log("You need to specify a value [y/n] to set the production mode!".bold.red);
return false;
}
self.inputValues['production-mode'] = self.inputValues['production-mode'].toLowerCase();
if (self.inputValues['production-mode'] != 'y' && self.inputValues['production-mode'] != 'n') {
console.log("You need to specify a value [y/n] to set the production mode!".bold.red);
return false;
}
var url = self.ionic.IONIC_DASH + self.ionic.IONIC_API + 'app/' + project.get('app_id') + '/push/set-production-mode';
var params = parseUrl(url);
var form = new FormData();
form.append('csrfmiddlewaretoken', self.getCsrfToken(self.jar));
form.append('production_mode', self.inputValues['production-mode']);
form.submit({
protocol: params.protocol,
hostname: params.hostname,
port: params.port,
path: params.path,
headers: form.getHeaders({
cookie: self.jar.map(function(c) {
return c.key + "=" + encodeURIComponent(c.value);
}).join("; ")
})
},
function (err, response) {
if (err) {
return self.ionic.fail('Error uploading certificate: ' + err);
}
response.setEncoding('utf8');
response.on("data", function(data) {
if (err) {
return self.ionic.fail('Error setting mode: ' + err);
}
try {
var d = JSON.parse(data);
if (d.errors && d.errors.length) {
for (var j = 0; j < d.errors.length; j++) {
console.log((d.errors[j]).bold.error);
}
return self.ionic.fail('Unable to set mode');
}
if (self.inputValues['production-mode'] == 'y') {
console.log("Successfully set production mode");
} else {
console.log("Successfully set development mode");
}
} catch (parseEx) {
return self.ionic.fail('Error response: ' + parseEx);
}
});
}
);
};
IonicTask.prototype.upload_cert = function(self) {
var project = IonicProject.load();
if (!project.get('app_id')) {
console.log("You need to upload your app first!".bold.red);
return false;
}
var promptProperties = {};
var prodCert = '0';
if (argv['ios-dev-cert']) {
promptProperties['ios-push-cert'] = {
name: 'ios-push-cert',
description: 'iOS Dev Push Certificate File (.p12)'.yellow.bold,
required: true,
conform: fileExists,
isFile: true
};
} else if (argv['ios-prod-cert']) {
promptProperties['ios-push-cert'] = {
name: 'ios-push-cert',
description: 'iOS Prod Push Certificate File (.p12)'.yellow.bold,
required: true,
conform: fileExists,
isFile: true
};
prodCert = '1';
}
prompt.start();
prompt.get({properties: promptProperties}, function(err, promptResult) {
if (err) {
return self.ionic.fail('Error: ' + err);
}
var url = self.ionic.IONIC_DASH + self.ionic.IONIC_API + 'app/' + project.get('app_id') + '/push/upload-push-cert';
var params = parseUrl(url);
var form = new FormData();
form.append('csrfmiddlewaretoken', self.getCsrfToken(self.jar));
try {
inputFile = promptResult['ios-push-cert'].replace(/\\ /g, ' ').trim();
form.append('ios_push_cert', fs.createReadStream( resolvePath(inputFile) ) );
} catch(e) {
return self.ionic.fail("Error loading " + resolvePath(inputFile));
}
// Set the flag for if this is a production or dev cert
form.append('prod_cert', prodCert);
form.submit({
protocol: params.protocol,
hostname: params.hostname,
port: params.port,
path: params.path,
headers: form.getHeaders({
cookie: self.jar.map(function(c) {
return c.key + "=" + encodeURIComponent(c.value);
}).join("; ")
})
},
function (err, response) {
if (err) {
return self.ionic.fail('Error uploading certificate: ' + err);
}
response.setEncoding('utf8');
response.on("data", function(data) {
if (err) {
return self.ionic.fail('Error uploading certificate: ' + err);
}
try {
var d = JSON.parse(data);
if (d.errors && d.errors.length) {
for (var j = 0; j < d.errors.length; j++) {
console.log((d.errors[j]).bold.error);
}
return self.ionic.fail('Unable to upload certificate');
}
console.log("Successfully uploaded certificate");
} catch (parseEx) {
return self.ionic.fail('Error response: ' + parseEx);
}
});
}
);
});
}
IonicTask.prototype.getCmdLineOptions = function() {
var self = this;
function getCmdArgValue(propertyName, shortName) {
var value = argv[propertyName] || argv[shortName];
if(value) {
self.inputValues[propertyName] = value;
self.useCmdArgs = true;
}
}
function getCmdArgFile(propertyName, shortName) {
var value = argv[propertyName] || argv[shortName];
if(value) {
if(!fileExists(value)) {
return self.ionic.fail("Unable to find file: " + argv[propertyName]);
}
self.inputFiles[propertyName] = value;
self.useCmdArgs = true;
}
}
getCmdArgValue('production-mode', 'l');
getCmdArgFile('ios-push-dev-cert', 'd');
getCmdArgFile('ios-push-prod-cert', 'p');
};
IonicTask.prototype.getCsrfToken = function(jar) {
for (var i = 0; i < jar.length; i++) {
if (jar[i].key == 'csrftoken') {
return jar[i].value;
}
}
return '';
}
function fileExists(filePath) {
// check if a file exists with a relative path or absolute path
filePath = filePath.replace(/\\ /g, ' ').trim();
return fs.existsSync(resolvePath(filePath));
}
function resolvePath (p) {
if (p.substr(0, 1) === '~') {
p = process.env.HOME + p.substr(1);
}
return path.resolve(p);
}
exports.IonicTask = IonicTask;