FILE / Unmei/Backend
routes/users.go
Исходный файл и его история в репозитории.
301 lines
6.6 KiB
Go
301 lines
6.6 KiB
Go
package routes
|
|
|
|
import (
|
|
"backend/database"
|
|
"bytes"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/go-chi/chi/v5"
|
|
"image"
|
|
_ "image/gif"
|
|
_ "image/jpeg"
|
|
_ "image/png"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
func RegisterUsersRoutes(r chi.Router) {
|
|
r.Get("/", getUsers)
|
|
r.Get("/me", getCurrentUser)
|
|
r.Post("/me/avatar", uploadAvatar)
|
|
r.Route("/me/settings", func(s chi.Router) {
|
|
s.Get("/", getSettings)
|
|
s.Post("/", updateSettings)
|
|
})
|
|
r.Route("/{userId:[0-9]+}", func(s chi.Router) {
|
|
s.Get("/", getUser)
|
|
s.Put("/", updateUser)
|
|
})
|
|
r.Route("/{userId:[0-9]+}/novels", func(s chi.Router) {
|
|
s.Get("/", getUserNovels)
|
|
s.Post("/", addUserNovel)
|
|
})
|
|
r.Route("/{userId:[0-9]+}/novels/{novelId:[0-9]+}", func(s chi.Router) {
|
|
s.Get("/", getUserNovel)
|
|
s.Put("/", updateUserNovel)
|
|
s.Delete("/", deleteUserNovel)
|
|
})
|
|
r.Get("/{userId:[0-9]+}/novels/comments", resolveUserNovelsComments)
|
|
}
|
|
|
|
func getUsers(w http.ResponseWriter, r *http.Request) {
|
|
users, err := database.FetchUsers()
|
|
Response(w, err, users)
|
|
}
|
|
|
|
func getCurrentUser(w http.ResponseWriter, r *http.Request) {
|
|
user, err := GetCurrentUser(r)
|
|
if errors.Is(err, database.ErrNotAuthorized) {
|
|
NoToken.Ferror(w)
|
|
return
|
|
}
|
|
if errors.Is(err, http.ErrNoCookie) {
|
|
NoToken.Ferror(w)
|
|
return
|
|
}
|
|
Response(w, err, user)
|
|
}
|
|
|
|
func uploadAvatar(w http.ResponseWriter, r *http.Request) {
|
|
user, err := GetCurrentUser(r)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
Error(w, err)
|
|
return
|
|
}
|
|
|
|
err = r.ParseMultipartForm(user.Group.MaxAvaWeight)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
Error(w, err)
|
|
return
|
|
}
|
|
|
|
file, handler, err := r.FormFile("avatar")
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
Error(w, err)
|
|
return
|
|
}
|
|
|
|
if !strings.HasPrefix(handler.Header["Content-Type"][0], "image") {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
RawError(w, "Wrong document type!")
|
|
return
|
|
}
|
|
|
|
fileBytes, err := io.ReadAll(file)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
Error(w, err)
|
|
return
|
|
}
|
|
err = file.Close()
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
Error(w, err)
|
|
return
|
|
}
|
|
|
|
img, _, err := image.DecodeConfig(bytes.NewReader(fileBytes))
|
|
if err != nil {
|
|
log.Println(err)
|
|
}
|
|
width, height := img.Width, img.Width
|
|
if width > user.Group.MaxAvatarSize && height > user.Group.MaxAvatarSize {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
RawError(w, "Image too big!")
|
|
return
|
|
}
|
|
|
|
ext := strings.Split(handler.Header["Content-Type"][0], "/")[1]
|
|
path := filepath.Join(os.Getenv("CDN_PATH"), "users", "avatars", fmt.Sprintf("%v.%v", user.ID, ext))
|
|
|
|
err = os.WriteFile(path, fileBytes, 0644)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
Error(w, err)
|
|
return
|
|
}
|
|
avatarPath := fmt.Sprintf("%v/avatars/%v.%v", os.Getenv("CDN_URL"), user.ID, ext)
|
|
Response(w, nil, avatarPath)
|
|
}
|
|
|
|
func getSettings(w http.ResponseWriter, r *http.Request) {
|
|
id, err := GetCurrentUserID(r)
|
|
if err != nil {
|
|
Error(w, err)
|
|
return
|
|
}
|
|
settings, err := database.FetchUserSettings(id)
|
|
Response(w, err, settings)
|
|
}
|
|
func updateSettings(w http.ResponseWriter, r *http.Request) {
|
|
id, err := GetCurrentUserID(r)
|
|
settings, err := database.FetchUserSettings(id)
|
|
if err != nil {
|
|
Error(w, err)
|
|
return
|
|
}
|
|
|
|
body, err := ReadBody(r)
|
|
if err != nil {
|
|
Error(w, err)
|
|
return
|
|
}
|
|
|
|
err = json.Unmarshal(body, settings)
|
|
if err != nil {
|
|
Error(w, err)
|
|
return
|
|
}
|
|
|
|
user, err := database.UpdateUserSettings(id, settings)
|
|
Response(w, err, user)
|
|
}
|
|
|
|
func getUser(w http.ResponseWriter, r *http.Request) {
|
|
id, _ := strconv.Atoi(chi.URLParam(r, "userId"))
|
|
user, err := database.FetchUser(id)
|
|
Response(w, err, user)
|
|
}
|
|
func updateUser(w http.ResponseWriter, r *http.Request) {
|
|
id, _ := strconv.Atoi(chi.URLParam(r, "userId"))
|
|
|
|
currentUser, err := GetCurrentUser(r)
|
|
if err != nil && !errors.Is(err, database.ErrNotAuthorized) {
|
|
Error(w, err)
|
|
return
|
|
} else if errors.Is(err, database.ErrNotAuthorized) || currentUser == nil {
|
|
currentUser = &database.User{ID: -1}
|
|
}
|
|
if currentUser.ID != int64(id) && !hasPermission(currentUser, "users") {
|
|
NoAccess.Ferror(w)
|
|
return
|
|
}
|
|
_, err = database.FetchUser(id)
|
|
if err != nil {
|
|
Error(w, err)
|
|
return
|
|
}
|
|
|
|
body, err := ReadBody(r)
|
|
if err != nil {
|
|
Error(w, err)
|
|
return
|
|
}
|
|
|
|
var u *database.User
|
|
err = json.Unmarshal(body, u)
|
|
if err != nil {
|
|
Error(w, err)
|
|
return
|
|
}
|
|
user, err := database.UpdateUser(u)
|
|
Response(w, err, user)
|
|
}
|
|
|
|
func getUserNovels(w http.ResponseWriter, r *http.Request) {
|
|
userId, _ := strconv.Atoi(chi.URLParam(r, "userId"))
|
|
|
|
novels, err := database.FetchUserNovels(userId)
|
|
Response(w, err, novels)
|
|
}
|
|
func addUserNovel(w http.ResponseWriter, r *http.Request) {
|
|
userId, _ := strconv.Atoi(chi.URLParam(r, "userId"))
|
|
body, err := ReadBody(r)
|
|
if err != nil {
|
|
Error(w, err)
|
|
return
|
|
}
|
|
var novel = &database.UserNovels{}
|
|
err = json.Unmarshal(body, novel)
|
|
if err != nil {
|
|
Error(w, err)
|
|
return
|
|
}
|
|
|
|
novel.UserID = int64(userId)
|
|
|
|
novel, err = database.CreateUserNovel(novel)
|
|
if err == nil {
|
|
w.WriteHeader(http.StatusCreated)
|
|
w.Header().Add("Location", fmt.Sprintf("https://%v%v/%v", r.Host, r.URL, novel.NovelID))
|
|
}
|
|
Response(w, err, novel)
|
|
}
|
|
|
|
func getUserNovel(w http.ResponseWriter, r *http.Request) {
|
|
userId := IURLParam(r, "userId")
|
|
novelId := IURLParam(r, "novelId")
|
|
novel, err := database.FetchUserNovel(userId, novelId)
|
|
Response(w, err, novel)
|
|
|
|
}
|
|
func updateUserNovel(w http.ResponseWriter, r *http.Request) {
|
|
userId := IURLParam(r, "userId")
|
|
novelId := IURLParam(r, "novelId")
|
|
|
|
_, err := database.FetchNovel(novelId)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
NotFound.Ferror(w)
|
|
return
|
|
}
|
|
|
|
_, err = database.FetchUser(userId)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
NotFound.Ferror(w)
|
|
return
|
|
}
|
|
|
|
novel, _ := database.FetchUserNovel(userId, novelId)
|
|
body, err := ReadBody(r)
|
|
if err != nil {
|
|
Error(w, err)
|
|
return
|
|
}
|
|
|
|
if novel == nil {
|
|
NotFound.Ferror(w)
|
|
return
|
|
}
|
|
|
|
err = json.Unmarshal(body, &novel)
|
|
if err != nil {
|
|
Error(w, err)
|
|
return
|
|
}
|
|
|
|
updatedNovel, err := database.UpdateUserNovel(novel)
|
|
Response(w, err, updatedNovel)
|
|
}
|
|
func deleteUserNovel(w http.ResponseWriter, r *http.Request) {
|
|
userId := IURLParam(r, "userId")
|
|
novelId := IURLParam(r, "novelId")
|
|
_, err := database.FetchUserNovel(userId, novelId)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
NotFound.Ferror(w)
|
|
return
|
|
}
|
|
|
|
err = database.DeleteUserNovel(userId, novelId)
|
|
if err != nil {
|
|
Error(w, err)
|
|
}
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
func resolveUserNovelsComments(w http.ResponseWriter, r *http.Request) {
|
|
id := IURLParam(r, "userId")
|
|
|
|
comments, err := database.FetchUserNovelsComments(id)
|
|
Response(w, err, comments)
|
|
}
|