mirror of
https://github.com/knadh/listmonk.git
synced 2024-11-13 02:55:04 +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…
Reference in a new issue