Remove all the wizard step logic from setup
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
// create main application module
|
||||
var app = angular.module('Application', ['ngRoute', 'ngAnimate', 'angular-md5', 'ui-notification']);
|
||||
var app = angular.module('Application', ['angular-md5', 'ui-notification']);
|
||||
|
||||
app.directive('ngEnter', function () {
|
||||
return function (scope, element, attrs) {
|
||||
@@ -17,267 +17,123 @@ app.directive('ngEnter', function () {
|
||||
};
|
||||
});
|
||||
|
||||
// setup all major application routes
|
||||
app.config(['$routeProvider', function ($routeProvider) {
|
||||
$routeProvider.when('/', {
|
||||
redirectTo: '/step1'
|
||||
}).when('/step1', {
|
||||
controller: 'StepController',
|
||||
templateUrl: 'views/setup/step1.html'
|
||||
}).when('/step2', {
|
||||
controller: 'StepController',
|
||||
templateUrl: 'views/setup/step2.html'
|
||||
}).when('/step3', {
|
||||
controller: 'StepController',
|
||||
templateUrl: 'views/setup/step3.html'
|
||||
}).when('/step4', {
|
||||
controller: 'FinishController',
|
||||
templateUrl: 'views/setup/step4.html'
|
||||
}).otherwise({ redirectTo: '/'});
|
||||
}]);
|
||||
// app.service('Wizard', [ function () {
|
||||
// var instance = null;
|
||||
|
||||
app.service('Wizard', [ function () {
|
||||
var instance = null;
|
||||
// function Wizard() {
|
||||
// this.username = '';
|
||||
// this.email = '';
|
||||
// this.password = '';
|
||||
// this.displayName = '';
|
||||
// this.setupToken = null;
|
||||
// this.provider = null;
|
||||
// this.apiServerOrigin = null;
|
||||
// this.createAppstoreAccount = true;
|
||||
// this.dnsConfig = null;
|
||||
// }
|
||||
|
||||
function Wizard() {
|
||||
this.username = '';
|
||||
this.email = '';
|
||||
this.password = '';
|
||||
this.displayName = '';
|
||||
this.setupToken = null;
|
||||
this.provider = null;
|
||||
this.apiServerOrigin = null;
|
||||
this.createAppstoreAccount = true;
|
||||
this.availableAvatars = [{
|
||||
file: null,
|
||||
data: null,
|
||||
url: '/img/avatars/avatar_0.png',
|
||||
}, {
|
||||
file: null,
|
||||
data: null,
|
||||
url: '/img/avatars/rubber-duck.png'
|
||||
}, {
|
||||
file: null,
|
||||
data: null,
|
||||
url: '/img/avatars/carrot.png'
|
||||
}, {
|
||||
file: null,
|
||||
data: null,
|
||||
url: '/img/avatars/cup.png'
|
||||
}, {
|
||||
file: null,
|
||||
data: null,
|
||||
url: '/img/avatars/football.png'
|
||||
}, {
|
||||
file: null,
|
||||
data: null,
|
||||
url: '/img/avatars/owl.png'
|
||||
}, {
|
||||
file: null,
|
||||
data: null,
|
||||
url: '/img/avatars/space-rocket.png'
|
||||
}, {
|
||||
file: null,
|
||||
data: null,
|
||||
url: '/img/avatars/armchair.png'
|
||||
}, {
|
||||
file: null,
|
||||
data: null,
|
||||
url: '/img/avatars/cap.png'
|
||||
}, {
|
||||
file: null,
|
||||
data: null,
|
||||
url: '/img/avatars/pan.png'
|
||||
}, {
|
||||
file: null,
|
||||
data: null,
|
||||
url: '/img/avatars/meat.png'
|
||||
}, {
|
||||
file: null,
|
||||
data: null,
|
||||
url: '/img/avatars/umbrella.png'
|
||||
}, {
|
||||
file: null,
|
||||
data: null,
|
||||
url: '/img/avatars/jar.png'
|
||||
}];
|
||||
this.avatar = {};
|
||||
this.avatarBlob = null;
|
||||
this.dnsConfig = null;
|
||||
}
|
||||
// instance = new Wizard();
|
||||
// return instance;
|
||||
// }]);
|
||||
|
||||
Wizard.prototype.setPreviewAvatar = function (avatar) {
|
||||
var that = this;
|
||||
// app.controller('StepController', ['$scope', '$route', '$location', 'Wizard', function ($scope, $route, $location, Wizard) {
|
||||
// $scope.wizard = Wizard;
|
||||
|
||||
this.avatar = avatar;
|
||||
// $scope.next = function (bad) {
|
||||
// if (bad) return;
|
||||
|
||||
// scale image and get the blob now. do not use the previewAvatar element here because it is not updated yet
|
||||
var img = document.createElement('img');
|
||||
img.src = avatar.data || avatar.url;
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = 256;
|
||||
canvas.height = 256;
|
||||
// var current = $location.path();
|
||||
// var next = '';
|
||||
|
||||
var imageDimensionRatio = img.width / img.height;
|
||||
var canvasDimensionRatio = canvas.width / canvas.height;
|
||||
var renderableHeight, renderableWidth, xStart, yStart;
|
||||
// if (current === '/step1') {
|
||||
// next = '/step2';
|
||||
// } else if (current === '/step2') {
|
||||
// if (Wizard.dnsConfig === null) next = '/step4';
|
||||
// else next = '/step3';
|
||||
// } else if (current === '/step3') {
|
||||
// next = '/step4';
|
||||
// } else {
|
||||
// next = '/step1';
|
||||
// }
|
||||
|
||||
if (imageDimensionRatio > canvasDimensionRatio) {
|
||||
renderableHeight = canvas.height;
|
||||
renderableWidth = img.width * (renderableHeight / img.height);
|
||||
xStart = (canvas.width - renderableWidth) / 2;
|
||||
yStart = 0;
|
||||
} else if (imageDimensionRatio < canvasDimensionRatio) {
|
||||
renderableWidth = canvas.width;
|
||||
renderableHeight = img.height * (renderableWidth / img.width);
|
||||
xStart = 0;
|
||||
yStart = (canvas.height - renderableHeight) / 2;
|
||||
} else {
|
||||
renderableHeight = canvas.height;
|
||||
renderableWidth = canvas.width;
|
||||
xStart = 0;
|
||||
yStart = 0;
|
||||
}
|
||||
// $location.path(next);
|
||||
// };
|
||||
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.drawImage(img, xStart, yStart, renderableWidth, renderableHeight);
|
||||
// $scope.focusNext = function (elemId, bad) {
|
||||
// if (!bad) $('#' + elemId).focus();
|
||||
// };
|
||||
// }]);
|
||||
|
||||
canvas.toBlob(function (blob) {
|
||||
that.avatarBlob = blob;
|
||||
});
|
||||
};
|
||||
// app.controller('FinishController', ['$scope', '$location', '$http', 'Wizard', 'Client', function ($scope, $location, $http, Wizard, Client) {
|
||||
// $scope.wizard = Wizard;
|
||||
|
||||
instance = new Wizard();
|
||||
return instance;
|
||||
}]);
|
||||
// function setDnsConfigIfNeeded(callback) {
|
||||
// if ($scope.wizard.dnsConfig === null) return callback(null);
|
||||
|
||||
app.controller('StepController', ['$scope', '$route', '$location', 'Wizard', function ($scope, $route, $location, Wizard) {
|
||||
$scope.wizard = Wizard;
|
||||
// Client.setDnsConfig($scope.wizard.dnsConfig, callback);
|
||||
// }
|
||||
|
||||
$scope.next = function (bad) {
|
||||
if (bad) return;
|
||||
|
||||
var current = $location.path();
|
||||
var next = '';
|
||||
|
||||
if (current === '/step1') {
|
||||
next = '/step2';
|
||||
} else if (current === '/step2') {
|
||||
if (Wizard.dnsConfig === null) next = '/step4';
|
||||
else next = '/step3';
|
||||
} else if (current === '/step3') {
|
||||
next = '/step4';
|
||||
} else {
|
||||
next = '/step1';
|
||||
}
|
||||
|
||||
$location.path(next);
|
||||
};
|
||||
|
||||
$scope.focusNext = function (elemId, bad) {
|
||||
if (!bad) $('#' + elemId).focus();
|
||||
};
|
||||
|
||||
$scope.$on('$viewContentLoaded', function () {
|
||||
if ($location.path() === '/step2') {
|
||||
if (Wizard.requireEmail) $('#inputEmail').focus();
|
||||
else $('#inputDisplayName').focus();
|
||||
} else {
|
||||
$('a[autofocus]').focus();
|
||||
$('input[autofocus]').focus();
|
||||
}
|
||||
});
|
||||
|
||||
$scope.showCustomAvatarSelector = function () {
|
||||
$('#avatarFileInput').click();
|
||||
};
|
||||
|
||||
// cheap way to detect if we are in avatar and name selection step
|
||||
if ($route.current.templateUrl === 'views/setup/step1.html') {
|
||||
$('#avatarFileInput').get(0).onchange = function (event) {
|
||||
var fr = new FileReader();
|
||||
fr.onload = function () {
|
||||
$scope.$apply(function () {
|
||||
var tmp = {
|
||||
file: event.target.files[0],
|
||||
data: fr.result,
|
||||
url: null
|
||||
};
|
||||
|
||||
$scope.wizard.availableAvatars.push(tmp);
|
||||
$scope.wizard.setPreviewAvatar(tmp);
|
||||
});
|
||||
};
|
||||
fr.readAsDataURL(event.target.files[0]);
|
||||
};
|
||||
|
||||
// ensure image got loaded before setting the preview avatar
|
||||
var image = document.createElement('img');
|
||||
var randomIndex = Math.floor(Math.random() * $scope.wizard.availableAvatars.length);
|
||||
image.onload = function() {
|
||||
$scope.$apply(function () { $scope.wizard.setPreviewAvatar($scope.wizard.availableAvatars[randomIndex]); });
|
||||
image = null;
|
||||
};
|
||||
image.src = $scope.wizard.availableAvatars[randomIndex].data || $scope.wizard.availableAvatars[randomIndex].url;
|
||||
} else if ($route.current.templateUrl === 'views/setup/step3.html' && Wizard.dnsConfig === null) {
|
||||
$location.path('/step4'); // not using custom domain
|
||||
}
|
||||
|
||||
}]);
|
||||
|
||||
app.controller('FinishController', ['$scope', '$location', '$http', 'Wizard', 'Client', function ($scope, $location, $http, Wizard, Client) {
|
||||
$scope.wizard = Wizard;
|
||||
|
||||
function setDnsConfigIfNeeded(callback) {
|
||||
if ($scope.wizard.dnsConfig === null) return callback(null);
|
||||
|
||||
Client.setDnsConfig($scope.wizard.dnsConfig, callback);
|
||||
}
|
||||
|
||||
function registerAppstoreAccountIfNeeded(callback) {
|
||||
if (!Wizard.createAppstoreAccount) return callback(null);
|
||||
if (Wizard.provider === 'caas') return callback(null);
|
||||
|
||||
$http.post(Wizard.apiServerOrigin + '/api/v1/users', { email: Wizard.email, password: Wizard.password }).success(function (data, status) {
|
||||
if (status !== 201) return callback({ status: status, data: data });
|
||||
|
||||
Client.setAppstoreConfig({ userId: data.userId, token: data.accessToken }, callback);
|
||||
}).error(function (data, status) {
|
||||
callback({ status: status, data: data });
|
||||
});
|
||||
}
|
||||
|
||||
Client.createAdmin(Wizard.username, Wizard.password, Wizard.email, Wizard.displayName, Wizard.setupToken, function (error) {
|
||||
if (error) {
|
||||
console.error('Internal error', error);
|
||||
$location.path('/step2').search('error', error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
Client.changeCloudronAvatar($scope.wizard.avatarBlob, function (error) {
|
||||
if (error) return console.error('Unable to set avatar.', error);
|
||||
|
||||
setDnsConfigIfNeeded(function (error) {
|
||||
if (error) return console.error('Unable to set dns config.', error);
|
||||
|
||||
registerAppstoreAccountIfNeeded(function (error) {
|
||||
if (error) console.error('Unable to create appstore account.', error); // this is not fatal
|
||||
|
||||
window.location.href = '/';
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}]);
|
||||
|
||||
app.controller('SetupController', ['$scope', '$location', 'Client', 'Wizard', function ($scope, $location, Client, Wizard) {
|
||||
$scope.initialized = false;
|
||||
$scope.wizard = Wizard;
|
||||
// }]);
|
||||
|
||||
app.controller('SetupController', ['$scope', '$http', 'Client', function ($scope, $http, Client) {
|
||||
// Stupid angular location provider either wants html5 location mode or not, do the query parsing on my own
|
||||
var search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.split('='); }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
|
||||
|
||||
$scope.initialized = false;
|
||||
$scope.busy = false;
|
||||
$scope.account = {
|
||||
email: '',
|
||||
displayName: '',
|
||||
requireEmail: false,
|
||||
username: '',
|
||||
password: ''
|
||||
};
|
||||
$scope.error = null;
|
||||
$scope.provider = '';
|
||||
$scope.apiServerOrigin = '';
|
||||
$scope.setupToken = '';
|
||||
$scope.createAppstoreAccount = true;
|
||||
$scope.showDNSSetup = false;
|
||||
|
||||
$scope.activateCloudron = function () {
|
||||
$scope.busy = true;
|
||||
|
||||
function registerAppstoreAccountIfNeeded(callback) {
|
||||
if (!$scope.createAppstoreAccount) return callback(null);
|
||||
|
||||
$http.post($scope.apiServerOrigin + '/api/v1/users', { email: $scope.account.email, password: $scope.account.password }).success(function (data, status) {
|
||||
if (status !== 201) return callback({ status: status, data: data });
|
||||
|
||||
Client.setAppstoreConfig({ userId: data.userId, token: data.accessToken }, callback);
|
||||
}).error(function (data, status) {
|
||||
callback({ status: status, data: data });
|
||||
});
|
||||
}
|
||||
|
||||
Client.createAdmin($scope.account.username, $scope.account.password, $scope.account.email, $scope.account.displayName, $scope.setupToken, function (error) {
|
||||
if (error) {
|
||||
console.error('Internal error', error);
|
||||
$scope.error = error;
|
||||
$scope.busy = false;
|
||||
return;
|
||||
}
|
||||
|
||||
registerAppstoreAccountIfNeeded(function (error) {
|
||||
if (error) console.error('Unable to create appstore account.', error); // this is not fatal
|
||||
|
||||
$scope.busy = false;
|
||||
|
||||
// for caas we are done here
|
||||
if ($scope.provider === 'caas') {
|
||||
window.location.href = '/';
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.showDNSSetup = true;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Client.getStatus(function (error, status) {
|
||||
if (error) {
|
||||
window.location.href = '/error.html';
|
||||
@@ -300,16 +156,15 @@ app.controller('SetupController', ['$scope', '$location', 'Client', 'Wizard', fu
|
||||
return;
|
||||
}
|
||||
|
||||
Wizard.setupToken = search.setupToken;
|
||||
$scope.setupToken = search.setupToken;
|
||||
$scope.createAppstoreAccount = false;
|
||||
}
|
||||
|
||||
Wizard.email = search.email;
|
||||
Wizard.displayName = search.displayName;
|
||||
Wizard.requireEmail = !search.email;
|
||||
Wizard.provider = status.provider;
|
||||
Wizard.apiServerOrigin = status.apiServerOrigin;
|
||||
|
||||
$location.path('/step1');
|
||||
$scope.account.email = search.email || $scope.account.email;
|
||||
$scope.account.displayName = search.displayName || $scope.account.displayName;
|
||||
$scope.account.requireEmail = !search.email;
|
||||
$scope.provider = status.provider;
|
||||
$scope.apiServerOrigin = status.apiServerOrigin;
|
||||
|
||||
$scope.initialized = true;
|
||||
});
|
||||
|
||||
@@ -15,17 +15,12 @@
|
||||
<!-- jQuery-->
|
||||
<script src="3rdparty/js/jquery.min.js"></script>
|
||||
|
||||
<!-- toBlob() polyfill-->
|
||||
<script src="3rdparty/js/canvas-to-blob.min.js"></script>
|
||||
|
||||
<!-- Bootstrap Core JavaScript -->
|
||||
<script src="3rdparty/js/bootstrap.min.js"></script>
|
||||
|
||||
<!-- Angularjs scripts -->
|
||||
<script src="3rdparty/js/angular.min.js"></script>
|
||||
<script src="3rdparty/js/angular-loader.min.js"></script>
|
||||
<script src="3rdparty/js/angular-route.min.js"></script>
|
||||
<script src="3rdparty/js/angular-animate.min.js"></script>
|
||||
<script src="3rdparty/js/angular-md5.min.js"></script>
|
||||
<script src="3rdparty/js/angular-ui-notification.min.js"></script>
|
||||
<script src="3rdparty/js/autofill-event.js"></script>
|
||||
@@ -37,18 +32,67 @@
|
||||
|
||||
<body class="setup" ng-app="Application" ng-controller="SetupController">
|
||||
|
||||
<center ng-show="wizard.provider === 'caas' && !wizard.setupToken">
|
||||
<center ng-show="provider === 'caas' && !setupToken">
|
||||
<h1> <i class="fa fa-frown-o fa-fw text-danger"></i> No setup token provided. </h1>
|
||||
Please use the setup link for this cloudron.
|
||||
</center>
|
||||
|
||||
<div class="main-container">
|
||||
<div class="row" ng-show="initialized && !busy && !(wizard.provider === 'caas' && !wizard.setupToken)">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="main-container" ng-hide="provider === 'caas' && !setupToken">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<div class="card" style="max-width: none; padding: 20px;">
|
||||
<form role="form" name="setup_form" novalidate>
|
||||
<div ng-view id="ng-view"></div>
|
||||
</form>
|
||||
<div ng-show="busy">
|
||||
<i class="fa fa-spinner fa-pulse fa-5x"></i>
|
||||
</div>
|
||||
<div ng-show="!showDNSSetup && !busy">
|
||||
<form role="form" name="setupForm" ng-submit="activateCloudron()" novalidate>
|
||||
<div class="row">
|
||||
<div class="col-md-12 text-center">
|
||||
<h1>Welcome to your Cloudron</h1>
|
||||
<h3>Create an Admin Account</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-md-offset-4 text-center">
|
||||
<div class="form-group" ng-class="{ 'has-error': setupForm.displayName.$dirty && setupForm.displayName.$invalid }">
|
||||
<input type="text" class="form-control" ng-model="account.displayName" id="inputDisplayName" name="displayName" placeholder="Display Name" required autocomplete="off" autofocus>
|
||||
</div>
|
||||
<div ng-show="account.requireEmail" class="form-group" ng-class="{ 'has-error': setupForm.email.$dirty && setupForm.email.$invalid }">
|
||||
<input type="email" class="form-control" ng-model="account.email" id="inputEmail" name="email" placeholder="Email" required autocomplete="off">
|
||||
</div>
|
||||
<div class="form-group" ng-class="{ 'has-error': setupForm.username.$dirty && setupForm.username.$invalid }">
|
||||
<input type="text" class="form-control" ng-model="account.username" id="inputUsername" name="username" placeholder="Username" ng-maxlength="512" ng-minlength="3" required autocomplete="off">
|
||||
</div>
|
||||
<div class="form-group" ng-class="{ 'has-error': setupForm.password.$dirty && setupForm.password.$invalid }">
|
||||
<input type="password" class="form-control" ng-model="account.password" id="inputPassword" name="password" placeholder="Password" ng-pattern="/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9])(?!.*\s).{8,30}$/" required autocomplete="off">
|
||||
<div class="control-label" ng-show="setupForm.password.$dirty && setupForm.password.$invalid">
|
||||
<small ng-show="setupForm.password.$dirty && setupForm.password.$invalid">Password must be 8-30 character with at least one uppercase, one numeric and one special character</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" ng-hide="provider === 'caas'">
|
||||
<div class="col-md-12 text-center">
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="createAppstoreAccount"> Create <a href="https://cloudron.io" target="_blank">Cloudron Store</a> account
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12 text-center">
|
||||
<input type="submit" class="btn btn-primary" ng-hide="provider === 'caas'" ng-disabled="setupForm.$invalid || busy" value="Next">
|
||||
<input type="submit" class="btn btn-primary" ng-show="provider === 'caas'" ng-disabled="setupForm.$invalid || busy" value="Done">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div ng-show="showDNSSetup && !busy">
|
||||
Now do DNS setup
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user