balena-cli/lib/utils/patterns.coffee
2017-01-25 19:33:43 +01:00

174 lines
4.8 KiB
CoffeeScript

###
Copyright 2016 Resin.io
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
###
_ = require('lodash')
Promise = require('bluebird')
form = require('resin-cli-form')
visuals = require('resin-cli-visuals')
resin = require('resin-sdk-preconfigured')
chalk = require('chalk')
validation = require('./validation')
messages = require('./messages')
exports.authenticate = (options) ->
return form.run [
message: 'Email:'
name: 'email'
type: 'input'
validate: validation.validateEmail
,
message: 'Password:'
name: 'password'
type: 'password'
],
override: options
.then(resin.auth.login)
.then(resin.auth.twoFactor.isPassed)
.then (isTwoFactorAuthPassed) ->
return if isTwoFactorAuthPassed
return form.ask
message: 'Two factor auth challenge:'
name: 'code'
type: 'input'
.then(resin.auth.twoFactor.challenge)
.catch (error) ->
resin.auth.logout().then ->
if error.name is 'ResinRequestError' and error.statusCode is 401
throw new Error('Invalid two factor authentication code')
throw error
exports.askLoginType = ->
return form.ask
message: 'How would you like to login?'
name: 'loginType'
type: 'list'
choices: [
name: 'Web authorization (recommended)'
value: 'web'
,
name: 'Credentials'
value: 'credentials'
,
name: 'Authentication token'
value: 'token'
,
name: 'I don\'t have a Resin account!'
value: 'register'
]
exports.selectDeviceType = ->
resin.models.device.getSupportedDeviceTypes().then (deviceTypes) ->
return form.ask
message: 'Device Type'
type: 'list'
choices: deviceTypes
exports.confirm = (yesOption, message) ->
Promise.try ->
return true if yesOption
return form.ask
message: message
type: 'confirm'
default: false
.then (confirmed) ->
if not confirmed
throw new Error('Aborted')
exports.selectApplication = (filter) ->
resin.models.application.hasAny().then (hasAnyApplications) ->
if not hasAnyApplications
throw new Error('You don\'t have any applications')
return resin.models.application.getAll()
.filter(filter or _.constant(true))
.then (applications) ->
return form.ask
message: 'Select an application'
type: 'list'
choices: _.map applications, (application) ->
return {
name: "#{application.app_name} (#{application.device_type})"
value: application.app_name
}
exports.selectOrCreateApplication = ->
resin.models.application.hasAny().then (hasAnyApplications) ->
return if not hasAnyApplications
resin.models.application.getAll().then (applications) ->
applications = _.map applications, (application) ->
return {
name: "#{application.app_name} (#{application.device_type})"
value: application.app_name
}
applications.unshift
name: 'Create a new application'
value: null
return form.ask
message: 'Select an application'
type: 'list'
choices: applications
.then (application) ->
return application if application?
form.ask
message: 'Choose a Name for your new application'
type: 'input'
validate: validation.validateApplicationName
exports.awaitDevice = (uuid) ->
resin.models.device.getName(uuid).then (deviceName) ->
spinner = new visuals.Spinner("Waiting for #{deviceName} to come online")
poll = ->
resin.models.device.isOnline(uuid).then (isOnline) ->
if isOnline
spinner.stop()
console.info("The device **#{deviceName}** is online!")
return
else
# Spinner implementation is smart enough to
# not start again if it was already started
spinner.start()
return Promise.delay(3000).then(poll)
console.info("Waiting for #{deviceName} to connect to resin...")
poll().return(uuid)
exports.inferOrSelectDevice = (preferredUuid) ->
resin.models.device.getAll()
.filter (device) ->
device.is_online
.then (onlineDevices) ->
if _.isEmpty(onlineDevices)
throw new Error('You don\'t have any devices online')
return form.ask
message: 'Select a device'
type: 'list'
default: if preferredUuid in _.map(onlineDevices, 'uuid') then preferredUuid else onlineDevices[0].uuid
choices: _.map onlineDevices, (device) ->
return {
name: "#{device.name or 'Untitled'} (#{device.uuid.slice(0, 7)})"
value: device.uuid
}
exports.printErrorMessage = (message) ->
console.error(chalk.red(message))
console.error(chalk.red("\n#{messages.getHelp}\n"))