Stian Aune
5 years ago
8 changed files with 242 additions and 10 deletions
-
20Gopkg.lock
-
12cmd/lucifer-server/main.go
-
70controllers/user-controller.go
-
94database/sqlite/user-repository.go
-
4internal/config/config.go
-
18internal/respond/error.go
-
14internal/respond/json.go
-
20models/user.go
@ -0,0 +1,70 @@ |
|||
package controllers |
|||
|
|||
import ( |
|||
"encoding/json" |
|||
"net/http" |
|||
|
|||
"git.aiterp.net/lucifer/lucifer/internal/respond" |
|||
"git.aiterp.net/lucifer/lucifer/models" |
|||
"github.com/gorilla/mux" |
|||
) |
|||
|
|||
// The UserController is a controller for all user inports.
|
|||
type UserController struct { |
|||
users models.UserRepository |
|||
} |
|||
|
|||
// getUsers (`GET /`): List users
|
|||
func (c *UserController) getUsers(w http.ResponseWriter, r *http.Request) { |
|||
// TODO: Check session
|
|||
|
|||
users, err := c.users.List(r.Context()) |
|||
if err != nil { |
|||
respond.Error(w, 500, "db_error", err.Error()) |
|||
return |
|||
} |
|||
|
|||
respond.JSON(w, 200, users) |
|||
} |
|||
|
|||
// login (`POST /login`): Log in as user
|
|||
func (c *UserController) login(w http.ResponseWriter, r *http.Request) { |
|||
loginData := struct { |
|||
Username string `json:"username"` |
|||
Password string `json:"password"` |
|||
}{} |
|||
|
|||
err := json.NewDecoder(r.Body).Decode(&loginData) |
|||
if err != nil { |
|||
respond.Error(w, 400, "invalid_json", "Input is not valid JSON.") |
|||
return |
|||
} |
|||
|
|||
user, err := c.users.FindByName(r.Context(), loginData.Username) |
|||
if err != nil { |
|||
respond.Error(w, http.StatusUnauthorized, "login_failed", "Login failed.") |
|||
return |
|||
} |
|||
|
|||
if err := user.CheckPassword(loginData.Password); err != nil { |
|||
respond.Error(w, http.StatusUnauthorized, "login_failed", "Login failed.") |
|||
return |
|||
} |
|||
|
|||
// TODO: Open session
|
|||
|
|||
respond.JSON(w, 200, user) |
|||
} |
|||
|
|||
// Mount mounts the controller
|
|||
func (c *UserController) Mount(router *mux.Router, prefix string) { |
|||
sub := router.PathPrefix(prefix).Subrouter() |
|||
|
|||
sub.Handle("/", http.HandlerFunc(c.getUsers)).Methods("GET") |
|||
sub.Handle("/login", http.HandlerFunc(c.login)).Methods("POST") |
|||
} |
|||
|
|||
// NewUserController creates a new UserController.
|
|||
func NewUserController(users models.UserRepository) *UserController { |
|||
return &UserController{users: users} |
|||
} |
@ -0,0 +1,94 @@ |
|||
package sqlite |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"git.aiterp.net/lucifer/lucifer/models" |
|||
) |
|||
|
|||
// UserRepository is a sqlite database.
|
|||
var UserRepository = &userRepository{} |
|||
|
|||
type userRepository struct{} |
|||
|
|||
func (repo *userRepository) FindByID(ctx context.Context, id int) (models.User, error) { |
|||
row := db.QueryRowxContext(ctx, "SELECT * FROM user WHERE id=?", id) |
|||
if err := row.Err(); err != nil { |
|||
return models.User{}, err |
|||
} |
|||
|
|||
user := models.User{} |
|||
if err := row.StructScan(&user); err != nil { |
|||
return models.User{}, err |
|||
} |
|||
|
|||
return user, nil |
|||
} |
|||
|
|||
func (repo *userRepository) FindByName(ctx context.Context, name string) (models.User, error) { |
|||
row := db.QueryRowxContext(ctx, "SELECT * FROM user WHERE name=?", name) |
|||
if err := row.Err(); err != nil { |
|||
return models.User{}, err |
|||
} |
|||
|
|||
user := models.User{} |
|||
if err := row.StructScan(&user); err != nil { |
|||
return models.User{}, err |
|||
} |
|||
|
|||
return user, nil |
|||
} |
|||
|
|||
func (repo *userRepository) List(ctx context.Context) ([]models.User, error) { |
|||
res, err := db.QueryxContext(ctx, "SELECT * FROM user") |
|||
if err != nil { |
|||
return nil, err |
|||
} else if err := res.Err(); err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
users := make([]models.User, 0, 64) |
|||
for res.Next() { |
|||
user := models.User{} |
|||
if err := res.StructScan(&user); err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
users = append(users, user) |
|||
} |
|||
|
|||
return users, nil |
|||
} |
|||
|
|||
func (repo *userRepository) Insert(ctx context.Context, user models.User) (models.User, error) { |
|||
res, err := db.NamedExecContext(ctx, "INSERT INTO user (name, hash) VALUES(:name, :hash)", user) |
|||
if err != nil { |
|||
return models.User{}, err |
|||
} |
|||
|
|||
id, err := res.LastInsertId() |
|||
if err != nil { |
|||
return models.User{}, err |
|||
} |
|||
|
|||
user.ID = int(id) |
|||
return user, nil |
|||
} |
|||
|
|||
func (repo *userRepository) Update(ctx context.Context, user models.User) error { |
|||
_, err := db.NamedExecContext(ctx, "UPDATE user SET name=:name AND hash=:hash WHERE id=:id", user) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
return nil |
|||
} |
|||
|
|||
func (repo *userRepository) Remove(ctx context.Context, user models.User) error { |
|||
_, err := db.ExecContext(ctx, "REMOVE FROM user WHERE id=?", user.ID) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
return err |
|||
} |
@ -0,0 +1,18 @@ |
|||
package respond |
|||
|
|||
import "net/http" |
|||
|
|||
// Error responds with a standardized error object.
|
|||
func Error(w http.ResponseWriter, code int, kind string, message string) { |
|||
type errorContent struct { |
|||
Code int `json:"code"` |
|||
Kind string `json:"kind"` |
|||
Message string `json:"message"` |
|||
} |
|||
|
|||
JSON(w, code, &errorContent{ |
|||
Code: code, |
|||
Kind: kind, |
|||
Message: message, |
|||
}) |
|||
} |
@ -0,0 +1,14 @@ |
|||
package respond |
|||
|
|||
import ( |
|||
"encoding/json" |
|||
"net/http" |
|||
) |
|||
|
|||
// JSON gets the json value.
|
|||
func JSON(w http.ResponseWriter, code int, data interface{}) { |
|||
w.Header().Set("Content-Type", "application/json") |
|||
w.WriteHeader(code) |
|||
|
|||
json.NewEncoder(w).Encode(data) |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue