diff --git a/gulpfile.js b/gulpfile.js index 835993e76..ad1990392 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -129,6 +129,15 @@ gulp.task('js-login', function () { .pipe(gulp.dest('dist/js')); }); +gulp.task('js-setupaccount', function () { + return gulp.src(['src/js/setupaccount.js']) + .pipe(ejs({ oauth: oauth, appstore: appstore }, {}, { ext: '.js' })) + .pipe(sourcemaps.init()) + .pipe(concat('setupaccount.js', { newLine: ';' })) + .pipe(sourcemaps.write()) + .pipe(gulp.dest('dist/js')); +}); + gulp.task('js-setup', function () { return gulp.src(['src/js/setup.js', 'src/js/client.js']) .pipe(ejs({ oauth: oauth, appstore: appstore }, {}, { ext: '.js' })) @@ -156,7 +165,7 @@ gulp.task('js-restore', function () { .pipe(gulp.dest('dist/js')); }); -gulp.task('js', gulp.series([ 'js-index', 'js-logs', 'js-terminal', 'js-login', 'js-setup', 'js-setupdns', 'js-restore' ])); +gulp.task('js', gulp.series([ 'js-index', 'js-logs', 'js-terminal', 'js-login', 'js-setupaccount', 'js-setup', 'js-setupdns', 'js-restore' ])); // -------------- // HTML @@ -224,6 +233,7 @@ gulp.task('watch', function (done) { gulp.watch(['src/js/logs.js', 'src/js/client.js'], gulp.series(['js-logs'])); gulp.watch(['src/js/terminal.js', 'src/js/client.js'], gulp.series(['js-terminal'])); gulp.watch(['src/js/login.js'], gulp.series(['js-login'])); + gulp.watch(['src/js/setupaccount.js'], gulp.series(['js-setupaccount'])); gulp.watch(['src/js/index.js', 'src/js/client.js', 'src/js/main.js', 'src/views/*.js'], gulp.series(['js-index'])); gulp.watch(['src/3rdparty/**/*'], gulp.series(['3rdparty'])); done(); diff --git a/src/js/setupaccount.js b/src/js/setupaccount.js new file mode 100644 index 000000000..23a7f3bb9 --- /dev/null +++ b/src/js/setupaccount.js @@ -0,0 +1,54 @@ +'use strict'; + +/* global angular, $ */ + +// create main application module +var app = angular.module('Application', []); + +app.controller('SetupAccountController', ['$scope', '$http', function ($scope, $http) { + // 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.indexOf('=') === -1 ? [item, true] : [item.slice(0, item.indexOf('=')), item.slice(item.indexOf('=')+1)]; }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {}); + + var API_ORIGIN = '<%= oauth.apiOrigin %>' || window.location.origin; + + $scope.busy = false; + $scope.error = false; + + $scope.existingUsername = !!search.username; + $scope.username = search.username || ''; + $scope.displayName = ''; + $scope.password = ''; + $scope.passwordRepeat = ''; + + $scope.onSubmit = function () { + $scope.busy = true; + + var data = { + resetToken: search.resetToken, + email: search.email, + username: $scope.username, + displayName: $scope.displayName, + password: $scope.password + }; + + function error(status) { + console.log('error', status) + $scope.busy = false; + + if (status === 401) $scope.error = 'Invalid reset token'; + else if (status === 409) $scope.error = 'Ask your admin for an invite link first'; + else $scope.error = 'Unknown error'; + } + + $http.post(API_ORIGIN + '/api/v1/cloudron/password_reset', data).success(function (data, status) { + if (status !== 202) return error(status); + + // set token to autologin + localStorage.token = data.accessToken; + + $scope.mode = 'newPasswordDone'; + }).error(function (data, status) { + error(status); + }); + }; +}]); diff --git a/src/setupaccount.html b/src/setupaccount.html new file mode 100644 index 000000000..c0615ddba --- /dev/null +++ b/src/setupaccount.html @@ -0,0 +1,112 @@ + + + + + + + + Cloudron Account Setup + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+
+
+ +
+

Cloudron Account Setup

+
+
+
+
+
+

Invalid Credentials

+
+
+
+
+
+ + +
+ + +
+
+ +
+ The username is too short + The username is too long + Not a valid username +
+ +
+ +
+ + +
+ +
+ +
+ Password must be atleast 8 characters +
+ +
+ +
+ +
+ Passwords don't match +
+ +
+ + +
+
+
+
+
+ + + +
+ + +