Added creation a new admin when none exist
This commit is contained in:
parent
d8af3a8a35
commit
ef9f105ab1
14
main.go
14
main.go
|
@ -41,14 +41,14 @@ func main() {
|
|||
// Init Config
|
||||
err := config.InitConfig()
|
||||
if err != nil {
|
||||
log.Log.Error(err.Error())
|
||||
log.Log.Fatal(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Set Engine
|
||||
err = models.SetEngine()
|
||||
if err != nil {
|
||||
log.Log.Error(err.Error())
|
||||
log.Log.Fatal(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,16 @@ func main() {
|
|||
// Additional swagger information
|
||||
docs.SwaggerInfo.Version = Version
|
||||
|
||||
// Create first admin if needed
|
||||
firstAdmin, err := models.CreateFirstAdmin()
|
||||
if err != nil {
|
||||
log.Log.Fatal("Could not create first admin.", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if firstAdmin != nil {
|
||||
log.Log.Infof("Created first admin user with name %s", firstAdmin.Username)
|
||||
}
|
||||
|
||||
// Start the webserver
|
||||
e := routes.NewEcho()
|
||||
routes.RegisterRoutes(e)
|
||||
|
|
|
@ -55,6 +55,9 @@ func InitConfig() (err error) {
|
|||
viper.SetDefault("database.path", "./sofaraum.db")
|
||||
viper.SetDefault("database.showqueries", false)
|
||||
viper.SetDefault("database.openconnections", 100)
|
||||
// First Admin
|
||||
viper.SetDefault("firstadmin.username", "admin")
|
||||
viper.SetDefault("firstadmin.password", "admin")
|
||||
// Cacher
|
||||
viper.SetDefault("cache.enabled", false)
|
||||
viper.SetDefault("cache.type", "memory")
|
||||
|
|
|
@ -150,3 +150,51 @@ const ErrCodeCouldNotGetUserID = 2003
|
|||
func (err ErrCouldNotGetUserID) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrCodeCouldNotGetUserID, Message: "Could not get user id."}
|
||||
}
|
||||
|
||||
// ErrUsernameExists represents a "UsernameAlreadyExists" kind of error.
|
||||
type ErrUsernameExists struct {
|
||||
UserID int64
|
||||
Username string
|
||||
}
|
||||
|
||||
// IsErrUsernameExists checks if an error is a ErrUsernameExists.
|
||||
func IsErrUsernameExists(err error) bool {
|
||||
_, ok := err.(ErrUsernameExists)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrUsernameExists) Error() string {
|
||||
return fmt.Sprintf("User with that username already exists [user id: %d, username: %s]", err.UserID, err.Username)
|
||||
}
|
||||
|
||||
// ErrorCodeUsernameExists holds the unique world-error code of this error
|
||||
const ErrorCodeUsernameExists = 2004
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrUsernameExists) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrorCodeUsernameExists, Message: "A user with this username already exists."}
|
||||
}
|
||||
|
||||
// ErrUserEmailExists represents a "UserEmailExists" kind of error.
|
||||
type ErrUserEmailExists struct {
|
||||
UserID int64
|
||||
Email string
|
||||
}
|
||||
|
||||
// IsErrUserEmailExists checks if an error is a ErrUserEmailExists.
|
||||
func IsErrUserEmailExists(err error) bool {
|
||||
_, ok := err.(ErrUserEmailExists)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrUserEmailExists) Error() string {
|
||||
return fmt.Sprintf("User with that email already exists [user id: %d, email: %s]", err.UserID, err.Email)
|
||||
}
|
||||
|
||||
// ErrorCodeUserEmailExists holds the unique world-error code of this error
|
||||
const ErrorCodeUserEmailExists = 2005
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrUserEmailExists) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrorCodeUserEmailExists, Message: "A user with this email address already exists."}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"fmt"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/labstack/echo"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"reflect"
|
||||
)
|
||||
|
@ -83,8 +84,8 @@ type APIUserPassword struct {
|
|||
}
|
||||
|
||||
// APIFormat formats an API User into a normal user struct
|
||||
func (apiUser *APIUserPassword) APIFormat() User {
|
||||
return User{
|
||||
func (apiUser *APIUserPassword) APIFormat() *User {
|
||||
return &User{
|
||||
ID: apiUser.ID,
|
||||
Username: apiUser.Username,
|
||||
Password: apiUser.Password,
|
||||
|
@ -155,3 +156,21 @@ func GetCurrentUser(c echo.Context) (user *User, err error) {
|
|||
|
||||
return
|
||||
}
|
||||
|
||||
// CreateFirstAdmin checks if there is at least one user and creates a new one if not
|
||||
func CreateFirstAdmin() (firstAdmin *User, err error) {
|
||||
count, err := x.Count(User{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if count < 1 {
|
||||
firstAdmin, err = CreateUser(&User{
|
||||
Username: viper.GetString("firstadmin.username"),
|
||||
Password: viper.GetString("firstadmin.password"),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
// Sofaraum server is the server which collects the statistics
|
||||
// for the sofaraum-heatmap application.
|
||||
// Copyright 2018 K.Langenberg and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// CreateUser creates a new user and inserts it into the database
|
||||
func CreateUser(user *User) (newUser *User, err error) {
|
||||
|
||||
newUser = user
|
||||
|
||||
// Check if we have all needed informations
|
||||
if newUser.Password == "" || newUser.Username == "" {
|
||||
return &User{}, ErrNoUsernamePassword{}
|
||||
}
|
||||
|
||||
// Check if the user already existst with that username
|
||||
var exists = true
|
||||
existingUser, err := GetUser(&User{Username: newUser.Username})
|
||||
if err != nil {
|
||||
if IsErrUserDoesNotExist(err) {
|
||||
exists = false
|
||||
} else {
|
||||
return &User{}, err
|
||||
}
|
||||
}
|
||||
if exists {
|
||||
return &User{}, ErrUsernameExists{newUser.ID, newUser.Username}
|
||||
}
|
||||
|
||||
// Check if the user already existst with that email
|
||||
if newUser.Email != "" {
|
||||
existingUser, err = GetUser(&User{Email: newUser.Email})
|
||||
if err != nil {
|
||||
if IsErrUserDoesNotExist(err) {
|
||||
exists = false
|
||||
} else {
|
||||
return &User{}, err
|
||||
}
|
||||
}
|
||||
if exists {
|
||||
return &User{}, ErrUserEmailExists{existingUser.ID, existingUser.Email}
|
||||
}
|
||||
}
|
||||
|
||||
// Hash the password
|
||||
newUser.Password, err = hashPassword(user.Password)
|
||||
if err != nil {
|
||||
return &User{}, err
|
||||
}
|
||||
|
||||
newUser.IsActive = true
|
||||
|
||||
// Insert it
|
||||
_, err = x.Insert(newUser)
|
||||
if err != nil {
|
||||
return &User{}, err
|
||||
}
|
||||
|
||||
return newUser, err
|
||||
}
|
||||
|
||||
// HashPassword hashes a password
|
||||
func hashPassword(password string) (string, error) {
|
||||
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
|
||||
return string(bytes), err
|
||||
}
|
||||
|
||||
// UpdateUser updates a user
|
||||
func UpdateUser(user *User) (updatedUser *User, err error) {
|
||||
|
||||
// Check if it exists
|
||||
theUser, err := GetUserByID(user.ID)
|
||||
if err != nil {
|
||||
return &User{}, err
|
||||
}
|
||||
|
||||
// Check if we have at least a username
|
||||
if user.Username == "" {
|
||||
//return User{}, ErrNoUsername{user.ID}
|
||||
user.Username = theUser.Username // Dont change the username if we dont have one
|
||||
}
|
||||
|
||||
user.Password = theUser.Password // set the password to the one in the database to not accedently resetting it
|
||||
|
||||
// Update it
|
||||
_, err = x.Id(user.ID).Update(user)
|
||||
if err != nil {
|
||||
return &User{}, err
|
||||
}
|
||||
|
||||
// Get the newly updated user
|
||||
updatedUser, err = GetUserByID(user.ID)
|
||||
if err != nil {
|
||||
return &User{}, err
|
||||
}
|
||||
|
||||
return updatedUser, err
|
||||
}
|
||||
|
||||
// UpdateUserPassword updates the password of a user
|
||||
func UpdateUserPassword(user *User, newPassword string) (err error) {
|
||||
|
||||
// Get all user details
|
||||
theUser, err := GetUserByID(user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Hash the new password and set it
|
||||
hashed, err := hashPassword(newPassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
theUser.Password = hashed
|
||||
|
||||
// Update it
|
||||
_, err = x.Id(user.ID).Update(theUser)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
// Sofaraum server is the server which collects the statistics
|
||||
// for the sofaraum-heatmap application.
|
||||
// Copyright 2018 K.Langenberg and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"code.sofaraum.de/server/pkg/models"
|
||||
"code.vikunja.io/web/handler"
|
||||
"github.com/labstack/echo"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// RegisterUser is the register handler
|
||||
// @Summary Register
|
||||
// @Description Creates a new user account.
|
||||
// @tags user
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param credentials body models.APIUserPassword true "The user credentials"
|
||||
// @Success 200 {object} models.User
|
||||
// @Failure 400 {object} code.vikunja.io/web.HTTPError "No or invalid user register object provided / User already exists."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /register [post]
|
||||
func CreateUser(c echo.Context) error {
|
||||
// Check for Request Content
|
||||
var datUser *models.APIUserPassword
|
||||
if err := c.Bind(&datUser); err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "No or invalid user model provided.")
|
||||
}
|
||||
|
||||
// Insert the user
|
||||
newUser, err := models.CreateUser(datUser.APIFormat())
|
||||
if err != nil {
|
||||
return handler.HandleHTTPError(err, c)
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusOK, newUser)
|
||||
}
|
|
@ -117,4 +117,5 @@ func RegisterRoutes(e *echo.Echo) {
|
|||
|
||||
// User stuff
|
||||
a.GET("/user", apiv1.UserShow)
|
||||
a.POST("/user/new", apiv1.CreateUser)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue