mirror of
				https://github.com/knadh/listmonk.git
				synced 2025-10-26 00:16:18 +08:00 
			
		
		
		
	Add user/password login handler.
This commit is contained in:
		
							parent
							
								
									435d6d5169
								
							
						
					
					
						commit
						0968e58766
					
				
					 7 changed files with 59 additions and 3 deletions
				
			
		
							
								
								
									
										27
									
								
								cmd/users.go
									
										
									
									
									
								
							
							
						
						
									
										27
									
								
								cmd/users.go
									
										
									
									
									
								
							|  | @ -156,3 +156,30 @@ func handleDeleteUsers(c echo.Context) error { | |||
| 
 | ||||
| 	return c.JSON(http.StatusOK, okResp{true}) | ||||
| } | ||||
| 
 | ||||
| // handleLoginUser logs a user in with a username and password. | ||||
| func handleLoginUser(c echo.Context) error { | ||||
| 	var ( | ||||
| 		app = c.Get("app").(*App) | ||||
| 	) | ||||
| 
 | ||||
| 	u := struct { | ||||
| 		Username string `json:"username"` | ||||
| 		Password string `json:"password"` | ||||
| 	}{} | ||||
| 
 | ||||
| 	if !strHasLen(u.Username, 1, stdInputMaxLen) { | ||||
| 		return echo.NewHTTPError(http.StatusBadRequest, app.i18n.Ts("globals.messages.invalidFields", "name", "username")) | ||||
| 	} | ||||
| 
 | ||||
| 	if !strHasLen(u.Password, 8, stdInputMaxLen) { | ||||
| 		return echo.NewHTTPError(http.StatusBadRequest, app.i18n.Ts("globals.messages.invalidFields", "name", "password")) | ||||
| 	} | ||||
| 
 | ||||
| 	_, err := app.core.LoginUser(u.Username, u.Password) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return c.JSON(http.StatusOK, okResp{true}) | ||||
| } | ||||
|  |  | |||
|  | @ -605,8 +605,9 @@ | |||
|     "users.username": "Username", | ||||
|     "users.usernameHelp": "Used with password login", | ||||
|     "users.password": "Password", | ||||
|     "users.invalidLogin": "Invalid username or password", | ||||
|     "users.passwordRepeat": "Repeat password", | ||||
|     "users.passwordEnable": "Enable password login", | ||||
|     "users.passwordEnable": "Enable logging in with password", | ||||
|     "users.passwordMismatch": "Passwords don't match", | ||||
|     "users.cantDelete": "User(s) couldn't be deleted. There has to be at least one 'super' user." | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| package core | ||||
| 
 | ||||
| import ( | ||||
| 	"database/sql" | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	"github.com/knadh/listmonk/models" | ||||
|  | @ -86,3 +87,19 @@ func (c *Core) DeleteUsers(ids []int) error { | |||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // LoginUser attempts to log the given user_id in by matching the password. | ||||
| func (c *Core) LoginUser(username, password string) (models.User, error) { | ||||
| 	var out models.User | ||||
| 	if err := c.q.LoginUser.Get(&out, username, password); err != nil { | ||||
| 		if err == sql.ErrNoRows { | ||||
| 			return out, echo.NewHTTPError(http.StatusForbidden, | ||||
| 				c.i18n.T("users.invalidLogin")) | ||||
| 		} | ||||
| 
 | ||||
| 		return out, echo.NewHTTPError(http.StatusInternalServerError, | ||||
| 			c.i18n.Ts("globals.messages.errorFetching", "name", "{globals.terms.users}", "error", pqErrMsg(err))) | ||||
| 	} | ||||
| 
 | ||||
| 	return out, nil | ||||
| } | ||||
|  |  | |||
|  | @ -12,6 +12,8 @@ import ( | |||
| func V3_1_0(db *sqlx.DB, fs stuffbin.FileSystem, ko *koanf.Koanf, lo *log.Logger) error { | ||||
| 	if _, err := db.Exec(` | ||||
| 		DO $$ | ||||
| 		CREATE EXTENSION IF NOT EXISTS pgcrypto; | ||||
| 
 | ||||
| 		BEGIN | ||||
| 			IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'user_status') THEN | ||||
| 			CREATE TYPE user_status AS ENUM ('enabled', 'disabled', 'super'); | ||||
|  |  | |||
|  | @ -112,6 +112,7 @@ type Queries struct { | |||
| 	UpdateUser  *sqlx.Stmt `query:"update-user"` | ||||
| 	DeleteUsers *sqlx.Stmt `query:"delete-users"` | ||||
| 	GetUsers    *sqlx.Stmt `query:"get-users"` | ||||
| 	LoginUser   *sqlx.Stmt `query:"login-user"` | ||||
| } | ||||
| 
 | ||||
| // CompileSubscriberQueryTpl takes an arbitrary WHERE expressions | ||||
|  |  | |||
							
								
								
									
										10
									
								
								queries.sql
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								queries.sql
									
										
									
									
									
								
							|  | @ -1028,13 +1028,13 @@ SELECT JSON_BUILD_OBJECT('version', (SELECT VERSION()), | |||
|                         'size_mb', (SELECT ROUND(pg_database_size((SELECT CURRENT_DATABASE()))/(1024^2)))) AS info; | ||||
| 
 | ||||
| -- name: create-user | ||||
| INSERT INTO users (username, password_login, password, email, name, status) VALUES($1, $2, $3, $4, $5, $6) RETURNING *; | ||||
| INSERT INTO users (username, password_login, password, email, name, status) VALUES($1, $2, (CASE WHEN $2 AND $3 != '' THEN CRYPT($3, GEN_SALT('bf')) ELSE NULL END), $4, $5, $6) RETURNING *; | ||||
| 
 | ||||
| -- name: update-user | ||||
| UPDATE users SET | ||||
|     username=(CASE WHEN $2 != '' THEN $2 ELSE username END), | ||||
|     password_login=$3, | ||||
|     password=(CASE WHEN $3 = TRUE THEN (CASE WHEN $4 != '' THEN $4 ELSE password END) ELSE NULL END), | ||||
|     password=(CASE WHEN $3 = TRUE THEN (CASE WHEN $4 != '' THEN CRYPT($4, GEN_SALT('bf')) ELSE password END) ELSE NULL END), | ||||
|     email=(CASE WHEN $5 != '' THEN $5 ELSE email END), | ||||
|     name=(CASE WHEN $6 != '' THEN $6 ELSE name END), | ||||
|     status=(CASE WHEN $7 != '' THEN $7::user_status ELSE status END) | ||||
|  | @ -1048,3 +1048,9 @@ DELETE FROM users WHERE id = ALL($1) AND (SELECT num FROM u) > 0; | |||
| 
 | ||||
| -- name: get-users | ||||
| SELECT * FROM users WHERE $1=0 OR id=$1 ORDER BY created_at; | ||||
| 
 | ||||
| -- name: login-user | ||||
| WITH u AS ( | ||||
|     SELECT * FROM users WHERE username=$1 AND status = 'enabled' AND password_login = TRUE | ||||
| ) | ||||
| SELECT * FROM u WHERE CRYPT($2, password) = password; | ||||
|  |  | |||
|  | @ -9,6 +9,8 @@ DROP TYPE IF EXISTS bounce_type CASCADE; CREATE TYPE bounce_type AS ENUM ('soft' | |||
| DROP TYPE IF EXISTS template_type CASCADE; CREATE TYPE template_type AS ENUM ('campaign', 'tx'); | ||||
| DROP TYPE IF EXISTS user_status CASCADE; CREATE TYPE user_status AS ENUM ('enabled', 'disabled', 'super'); | ||||
| 
 | ||||
| CREATE EXTENSION pgcrypto; | ||||
| 
 | ||||
| -- subscribers | ||||
| DROP TABLE IF EXISTS subscribers CASCADE; | ||||
| CREATE TABLE subscribers ( | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue