mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-23 00:46:30 +00:00
added pages to add / edit / delete users from the system
This commit is contained in:
parent
79e46d1a8c
commit
6b9ae21c7a
11 changed files with 284 additions and 4 deletions
|
@ -50,8 +50,28 @@ app.config(['$routeProvider', '$locationProvider', function($routeProvider, $loc
|
|||
}
|
||||
}
|
||||
})
|
||||
.when('/admin/users/add', {
|
||||
templateUrl: '/views/users_add.html',
|
||||
controller: 'UserAddController',
|
||||
title: 'Add User',
|
||||
resolve: {
|
||||
user: function(authService) {
|
||||
return authService.getUser();
|
||||
}
|
||||
}
|
||||
})
|
||||
.when('/admin/users/:host/:login', {
|
||||
templateUrl: '/views/users_edit.html',
|
||||
controller: 'UserEditController',
|
||||
title: 'Edit User',
|
||||
resolve: {
|
||||
user: function(authService) {
|
||||
return authService.getUser();
|
||||
}
|
||||
}
|
||||
})
|
||||
.when('/admin/users', {
|
||||
templateUrl: '/views/sys_users.html',
|
||||
templateUrl: '/views/users.html',
|
||||
controller: 'UsersController',
|
||||
title: 'System Users',
|
||||
resolve: {
|
||||
|
|
|
@ -11,4 +11,45 @@ angular.module('app').controller("UsersController", function($scope, $http, user
|
|||
error(function(data, status, headers, config) {
|
||||
console.log(data);
|
||||
});
|
||||
});
|
||||
|
||||
angular.module('app').controller("UserAddController", function($scope, $http, users) {
|
||||
// set the default host to github ... however ...
|
||||
// eventually we can improve this logic to use the hostname
|
||||
// of the currently authenticated user.
|
||||
$scope.host='github.com';
|
||||
$scope.name='';
|
||||
|
||||
$scope.create = function() {
|
||||
users.create($scope.host, $scope.name).success(function () {
|
||||
window.location.href="/admin/users";
|
||||
})
|
||||
.error(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
angular.module('app').controller("UserEditController", function($scope, $http, $routeParams, users) {
|
||||
|
||||
var host = $routeParams.host;
|
||||
var name = $routeParams.login;
|
||||
|
||||
users.get(host, name).success(function (user) {
|
||||
$scope.account = user;
|
||||
$scope.state = 1;
|
||||
})
|
||||
.error(function (error) {
|
||||
$scope.account = undefined;
|
||||
$scope.state = 1;
|
||||
});
|
||||
|
||||
$scope.delete = function() {
|
||||
users.delete(host, name).success(function () {
|
||||
window.location.href="/admin/users";
|
||||
})
|
||||
.error(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
});
|
|
@ -4,4 +4,13 @@ angular.module('app').service('users', ['$http', function($http) {
|
|||
this.getCurrent = function() {
|
||||
return $http.get('/v1/user');
|
||||
};
|
||||
this.get = function(host, login) {
|
||||
return $http.get('/v1/users/'+host+'/'+login);
|
||||
};
|
||||
this.create = function(host, login) {
|
||||
return $http.post('/v1/users/'+host+'/'+login);
|
||||
};
|
||||
this.delete = function(host, login) {
|
||||
return $http.delete('/v1/users/'+host+'/'+login);
|
||||
};
|
||||
}]);
|
|
@ -917,6 +917,11 @@ nav div.options .pure-button i {
|
|||
margin: 10px 0px;
|
||||
font-size: 22px;
|
||||
}
|
||||
#accountpage section h4 small {
|
||||
opacity: 0.6;
|
||||
font-size: 16px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
#accountpage section img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
|
@ -928,6 +933,18 @@ nav div.options .pure-button i {
|
|||
right: 0px;
|
||||
margin: 20px;
|
||||
}
|
||||
#accountpage section .button-error {
|
||||
color: #FFF;
|
||||
background: #ca3c3c;
|
||||
padding: 10px 20px;
|
||||
float: right;
|
||||
}
|
||||
#accountpage section .pure-button-primary {
|
||||
color: #FFF;
|
||||
background: #4ab1ce;
|
||||
padding: 10px 20px;
|
||||
float: right;
|
||||
}
|
||||
#repopage {
|
||||
width: 100%;
|
||||
background: #f2f5f8;
|
||||
|
@ -1158,3 +1175,18 @@ nav div.options .pure-button i {
|
|||
white-space: pre-wrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
.pure-form.pure-form-stacked label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.pure-form.pure-form-stacked label:first-child {
|
||||
margin-top: 0px;
|
||||
}
|
||||
.pure-form.pure-form-stacked input[type="text"],
|
||||
.pure-form.pure-form-stacked select {
|
||||
min-width: 300px;
|
||||
box-shadow: none;
|
||||
padding: 10px 10px;
|
||||
}
|
||||
|
|
|
@ -821,6 +821,11 @@ nav {
|
|||
h4 {
|
||||
margin:10px 0px;
|
||||
font-size:22px;
|
||||
small {
|
||||
opacity:0.6;
|
||||
font-size:16px;
|
||||
margin-left:10px;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
|
@ -835,6 +840,20 @@ nav {
|
|||
right:0px;
|
||||
margin:20px;
|
||||
}
|
||||
|
||||
.button-error {
|
||||
color:#FFF;
|
||||
background: rgb(202, 60, 60);
|
||||
padding:10px 20px;
|
||||
float:right;
|
||||
}
|
||||
|
||||
.pure-button-primary {
|
||||
color:#FFF;
|
||||
background: @link2;
|
||||
padding:10px 20px;
|
||||
float:right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1030,3 +1049,22 @@ nav {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pure-form.pure-form-stacked {
|
||||
label {
|
||||
font-size:14px;
|
||||
color:#666;
|
||||
margin-top:20px;
|
||||
margin-bottom:5px;
|
||||
&:first-child {
|
||||
margin-top:0px;
|
||||
}
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
select {
|
||||
min-width:300px;
|
||||
box-shadow:none;
|
||||
padding:10px 10px;
|
||||
}
|
||||
}
|
2
server/app/styles/drone.min.css
vendored
2
server/app/styles/drone.min.css
vendored
File diff suppressed because one or more lines are too long
|
@ -1,8 +1,8 @@
|
|||
<div id="userspage">
|
||||
<nav>
|
||||
<div class="options">
|
||||
<a class="pure-button pure-button-primary" href="/admin/users/new">
|
||||
<i class="fa fa fa-plus"></i> Add User
|
||||
<a class="pure-button pure-button-primary" href="/admin/users/add">
|
||||
<i class="fa fa fa-plus"></i> Register User
|
||||
</a>
|
||||
</div>
|
||||
|
38
server/app/views/users_add.html
Normal file
38
server/app/views/users_add.html
Normal file
|
@ -0,0 +1,38 @@
|
|||
<article id="accountpage">
|
||||
<nav>
|
||||
<a href="/admin/users"><span class="fa fa-arrow-left"></span></a>
|
||||
<a href="/admin/users">users</a>
|
||||
<span class="separator">/</span>
|
||||
<a href="/admin/users/add">register</a>
|
||||
</nav>
|
||||
|
||||
<section class="pure-g profile">
|
||||
<div class="pure-u-1-6">
|
||||
<div>
|
||||
<a href="https://gravatar.com/" target="_blank">
|
||||
<img src="//www.gravatar.com/avatar/00000000000000000000000000000000?d=mm" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-5-6">
|
||||
<div>
|
||||
<form class="pure-form pure-form-stacked">
|
||||
<fieldset>
|
||||
<label for="host">Service</label>
|
||||
<select ng-model="host" name="host">
|
||||
<option value="github.com">GitHub</option>
|
||||
<option value="enterprise.github.com">GitHub Enterprise</option>
|
||||
<option value="gitlab.com">GitLab</option>
|
||||
<option value="bitbucket.org">Bitbucket</option>
|
||||
<option value="stash.atlassian.com">Stash</option>
|
||||
</select>
|
||||
|
||||
<label for="username">Username</label>
|
||||
<input type="text" ng-model="name" name="username" placeholder="ex. octocat" />
|
||||
</fieldset>
|
||||
</form>
|
||||
<button ng-click="create()" class="pure-button pure-button-primary">Register Account</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
26
server/app/views/users_edit.html
Normal file
26
server/app/views/users_edit.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
<article id="accountpage">
|
||||
<nav>
|
||||
<a href="/admin/users"><span class="fa fa-arrow-left"></span></a>
|
||||
<a href="/admin/users">users</a>
|
||||
<span class="separator">/</span>
|
||||
<a href="/admin/users/{{account.remote}}/{{ account.login }}">edit</a>
|
||||
</nav>
|
||||
|
||||
<section class="pure-g profile">
|
||||
<div class="pure-u-1-6">
|
||||
<div>
|
||||
<a href="https://gravatar.com/" target="_blank">
|
||||
<img ng-src="{{ account.gravatar | gravatar }}" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-5-6">
|
||||
<div>
|
||||
<h4>{{ account.login }} <small>{{ account.remote }}</small></h4>
|
||||
<span class="fullname">{{ account.name }}</span>
|
||||
<span class="email">{{ account.email }}</span>
|
||||
<button ng-click="delete()" class="pure-button button-error">Delete Account</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
|
@ -75,6 +75,7 @@ func (h *LoginHandler) GetLogin(w http.ResponseWriter, r *http.Request) error {
|
|||
// in case it changed in GitHub
|
||||
u.Access = login.Access
|
||||
u.Secret = login.Secret
|
||||
u.SetEmail(login.Email)
|
||||
if err := h.users.Update(u); err != nil {
|
||||
return badRequest{err}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/drone/drone/server/database"
|
||||
"github.com/drone/drone/server/session"
|
||||
"github.com/drone/drone/shared/model"
|
||||
"github.com/gorilla/pat"
|
||||
)
|
||||
|
||||
|
@ -35,6 +36,80 @@ func (h *UsersHandler) GetUsers(w http.ResponseWriter, r *http.Request) error {
|
|||
return json.NewEncoder(w).Encode(users)
|
||||
}
|
||||
|
||||
// GetUser gets a user by hostname and login.
|
||||
// GET /api/users/:host/:login
|
||||
func (h *UsersHandler) GetUser(w http.ResponseWriter, r *http.Request) error {
|
||||
remote := r.FormValue(":host")
|
||||
login := r.FormValue(":login")
|
||||
|
||||
// get the user form the session
|
||||
user := h.sess.User(r)
|
||||
if user == nil || !user.Admin {
|
||||
return notAuthorized{}
|
||||
}
|
||||
user, err := h.users.FindLogin(remote, login)
|
||||
if err != nil {
|
||||
return notFound{err}
|
||||
}
|
||||
|
||||
return json.NewEncoder(w).Encode(user)
|
||||
}
|
||||
|
||||
// PostUser registers a new user account.
|
||||
// POST /api/users/:host/:login
|
||||
func (h *UsersHandler) PostUser(w http.ResponseWriter, r *http.Request) error {
|
||||
remote := r.FormValue(":host")
|
||||
login := r.FormValue(":login")
|
||||
|
||||
// get the user form the session
|
||||
user := h.sess.User(r)
|
||||
if user == nil || !user.Admin {
|
||||
return notAuthorized{}
|
||||
}
|
||||
|
||||
account := model.NewUser(remote, login, "")
|
||||
if err := h.users.Insert(account); err != nil {
|
||||
return badRequest{err}
|
||||
}
|
||||
|
||||
return json.NewEncoder(w).Encode(account)
|
||||
}
|
||||
|
||||
// DeleteUser gets a user by hostname and login and deletes
|
||||
// from the system.
|
||||
//
|
||||
// DELETE /api/users/:host/:login
|
||||
func (h *UsersHandler) DeleteUser(w http.ResponseWriter, r *http.Request) error {
|
||||
remote := r.FormValue(":host")
|
||||
login := r.FormValue(":login")
|
||||
|
||||
// get the user form the session
|
||||
user := h.sess.User(r)
|
||||
if user == nil || !user.Admin {
|
||||
return notAuthorized{}
|
||||
}
|
||||
account, err := h.users.FindLogin(remote, login)
|
||||
if err != nil {
|
||||
return notFound{err}
|
||||
}
|
||||
|
||||
// user cannot delete his / her own account
|
||||
if account.ID == user.ID {
|
||||
return badRequest{}
|
||||
}
|
||||
|
||||
if err := h.users.Delete(account); err != nil {
|
||||
return badRequest{err}
|
||||
}
|
||||
|
||||
// return a 200 indicating deletion complete
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *UsersHandler) Register(r *pat.Router) {
|
||||
r.Delete("/v1/users/{host}/{login}", errorHandler(h.DeleteUser))
|
||||
r.Post("/v1/users/{host}/{login}", errorHandler(h.PostUser))
|
||||
r.Get("/v1/users/{host}/{login}", errorHandler(h.GetUser))
|
||||
r.Get("/v1/users", errorHandler(h.GetUsers))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue