浏览代码

Added change password feature, Closes #1455

Torkel Ödegaard 11 年之前
父节点
当前提交
47c6c6e1b7

+ 1 - 0
pkg/api/api.go

@@ -50,6 +50,7 @@ func Register(r *macaron.Macaron) {
 			r.Get("/accounts", GetUserAccounts)
 			r.Post("/stars/dashboard/:id", StarDashboard)
 			r.Delete("/stars/dashboard/:id", UnstarDashboard)
+			r.Put("/password", bind(m.ChangeUserPasswordCommand{}), ChangeUserPassword)
 		})
 
 		// account

+ 31 - 0
pkg/api/user.go

@@ -4,6 +4,7 @@ import (
 	"github.com/grafana/grafana/pkg/bus"
 	"github.com/grafana/grafana/pkg/middleware"
 	m "github.com/grafana/grafana/pkg/models"
+	"github.com/grafana/grafana/pkg/util"
 )
 
 func GetUser(c *middleware.Context) {
@@ -84,3 +85,33 @@ func SetUsingAccount(c *middleware.Context) {
 
 	c.JsonOK("Active account changed")
 }
+
+func ChangeUserPassword(c *middleware.Context, cmd m.ChangeUserPasswordCommand) {
+	userQuery := m.GetUserByIdQuery{Id: c.UserId}
+
+	if err := bus.Dispatch(&userQuery); err != nil {
+		c.JsonApiErr(500, "Could not read user from database", err)
+		return
+	}
+
+	passwordHashed := util.EncodePassword(cmd.OldPassword, userQuery.Result.Salt)
+	if passwordHashed != userQuery.Result.Password {
+		c.JsonApiErr(401, "Invalid old password", nil)
+		return
+	}
+
+	if len(cmd.NewPassword) < 4 {
+		c.JsonApiErr(400, "New password too short", nil)
+		return
+	}
+
+	cmd.UserId = c.UserId
+	cmd.NewPassword = util.EncodePassword(cmd.NewPassword, userQuery.Result.Salt)
+
+	if err := bus.Dispatch(&cmd); err != nil {
+		c.JsonApiErr(500, "Failed to change user password", err)
+		return
+	}
+
+	c.JsonOK("User password changed")
+}

+ 7 - 0
pkg/models/user.go

@@ -52,6 +52,13 @@ type UpdateUserCommand struct {
 	UserId int64 `json:"-"`
 }
 
+type ChangeUserPasswordCommand struct {
+	OldPassword string `json:"oldPassword"`
+	NewPassword string `json:"newPassword"`
+
+	UserId int64 `json:"-"`
+}
+
 type DeleteUserCommand struct {
 	UserId int64
 }

+ 17 - 0
pkg/services/sqlstore/user.go

@@ -18,6 +18,7 @@ func init() {
 	bus.AddHandler("sql", CreateUser)
 	bus.AddHandler("sql", GetUserById)
 	bus.AddHandler("sql", UpdateUser)
+	bus.AddHandler("sql", ChangeUserPassword)
 	bus.AddHandler("sql", GetUserByLogin)
 	bus.AddHandler("sql", SetUsingAccount)
 	bus.AddHandler("sql", GetUserInfo)
@@ -181,6 +182,22 @@ func UpdateUser(cmd *m.UpdateUserCommand) error {
 	})
 }
 
+func ChangeUserPassword(cmd *m.ChangeUserPasswordCommand) error {
+	return inTransaction2(func(sess *session) error {
+
+		user := m.User{
+			Password: cmd.NewPassword,
+			Updated:  time.Now(),
+		}
+
+		if _, err := sess.Id(cmd.UserId).Update(&user); err != nil {
+			return err
+		}
+
+		return nil
+	})
+}
+
 func SetUsingAccount(cmd *m.SetUsingAccountCommand) error {
 	return inTransaction(func(sess *xorm.Session) error {
 		user := m.User{}

+ 1 - 0
src/app/features/all.js

@@ -9,6 +9,7 @@ define([
   './dashboard/all',
   './panel/all',
   './profile/profileCtrl',
+  './profile/changePasswordCtrl',
   './account/all',
   './admin/all',
   './grafanaDatasource/datasource',

+ 1 - 1
src/app/features/opentsdb/datasource.js

@@ -120,7 +120,7 @@ function (angular, _, kbn) {
     }
 
     function convertTargetToQuery(target) {
-      if (!target.metric) {
+      if (!target.metric || target.hide) {
         return null;
       }
 

+ 28 - 0
src/app/features/profile/changePasswordCtrl.js

@@ -0,0 +1,28 @@
+define([
+  'angular',
+  'config',
+],
+function (angular) {
+  'use strict';
+
+  var module = angular.module('grafana.controllers');
+
+  module.controller('ChangePasswordCtrl', function($scope, backendSrv, $location) {
+
+    $scope.command = {};
+
+    $scope.changePassword = function() {
+      if (!$scope.userForm.$valid) { return; }
+
+      if ($scope.command.newPassword !== $scope.command.confirmNew) {
+        $scope.appEvent('alert-warning', ['New passwords do not match', '']);
+        return;
+      }
+
+      backendSrv.put('/api/user/password', $scope.command).then(function() {
+        $location.path("profile");
+      });
+    };
+
+  });
+});

+ 56 - 0
src/app/features/profile/partials/password.html

@@ -0,0 +1,56 @@
+<topnav title="{{contextSrv.user.name}}" section="Profile" icon="fa fa-user" subnav="true">
+	<ul class="nav">
+		<li><a href="profile">Overview</a></li>
+		<li class="active"><a href="profile/password">Change password</a></li>
+	</ul>
+</topnav>
+
+<div class="page-container">
+	<div class="page">
+
+		<h2>Change password</h2>
+
+		<form name="userForm">
+			<div>
+				<div class="tight-form">
+					<ul class="tight-form-list">
+						<li class="tight-form-item" style="width: 100px">
+							<strong>Old Password</strong>
+						</li>
+						<li>
+							<input type="password" required ng-model="command.oldPassword" class="input-xxlarge tight-form-input last" >
+						</li>
+					</ul>
+					<div class="clearfix"></div>
+				</div>
+				<div class="tight-form" style="margin-top: 5px">
+					<ul class="tight-form-list">
+						<li class="tight-form-item" style="width: 100px">
+							<strong>New Password</strong>
+						</li>
+						<li>
+							<input type="password" required ng-model="command.newPassword" ng-minlength="4" class="input-xxlarge tight-form-input last" >
+						</li>
+					</ul>
+					<div class="clearfix"></div>
+				</div>
+				<div class="tight-form" style="margin-top: 5px">
+					<ul class="tight-form-list">
+						<li class="tight-form-item" style="width: 100px">
+							<strong>Confirm New</strong>
+						</li>
+						<li>
+							<input type="password" required ng-model="command.confirmNew" ng-minlength="4" class="input-xxlarge tight-form-input last" >
+						</li>
+					</ul>
+					<div class="clearfix"></div>
+				</div>
+			</div>
+
+			<br>
+			<button type="submit" class="pull-right btn btn-success" ng-click="changePassword()">Change Password</button>
+		</form>
+
+	</div>
+</div>
+

+ 5 - 3
src/app/features/profile/partials/profile.html

@@ -1,6 +1,8 @@
-<topnav title="{{contextSrv.user.name}}"
-				section="Profile"
-				icon="fa fa-user">
+<topnav title="{{contextSrv.user.name}}" section="Profile" icon="fa fa-user" subnav="true">
+	<ul class="nav">
+		<li class="active"><a href="profile">Overview</a></li>
+		<li><a href="profile/password">Change password</a></li>
+	</ul>
 </topnav>
 
 <div class="page-container">

+ 1 - 1
src/app/features/profile/profileCtrl.js

@@ -7,7 +7,7 @@ function (angular, config) {
 
   var module = angular.module('grafana.controllers');
 
-  module.controller('ProfileCtrl', function($scope, $http, backendSrv) {
+  module.controller('ProfileCtrl', function($scope, backendSrv) {
 
     $scope.newAccount = {name: ''};
 

+ 4 - 0
src/app/routes/backend/all.js

@@ -62,6 +62,10 @@ define([
         templateUrl: 'app/features/profile/partials/profile.html',
         controller : 'ProfileCtrl',
       })
+      .when('/profile/password', {
+        templateUrl: 'app/features/profile/partials/password.html',
+        controller : 'ChangePasswordCtrl',
+      })
       .when('/admin/settings', {
         templateUrl: 'app/features/admin/partials/settings.html',
         controller : 'AdminSettingsCtrl',