mirror of
https://github.com/usememos/memos.git
synced 2025-06-05 22:09:59 +02:00
refactor: backend
This commit is contained in:
114
api/auth.go
114
api/auth.go
@@ -1,113 +1,11 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"memos/api/e"
|
||||
"memos/store"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func handleUserSignUp(w http.ResponseWriter, r *http.Request) {
|
||||
type UserSignUpDataBody struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
userSignup := UserSignUpDataBody{}
|
||||
err := json.NewDecoder(r.Body).Decode(&userSignup)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Bad request")
|
||||
return
|
||||
}
|
||||
|
||||
usernameUsable, _ := store.CheckUsernameUsable(userSignup.Username)
|
||||
if !usernameUsable {
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: false,
|
||||
Message: "Username is existed",
|
||||
Data: nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := store.CreateNewUser(userSignup.Username, userSignup.Password)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
session, _ := SessionStore.Get(r, "session")
|
||||
|
||||
session.Values["user_id"] = user.Id
|
||||
session.Save(r, w)
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: user,
|
||||
})
|
||||
type Login struct {
|
||||
Name string
|
||||
Password string
|
||||
}
|
||||
|
||||
func handleUserSignIn(w http.ResponseWriter, r *http.Request) {
|
||||
type UserSigninDataBody struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
userSignin := UserSigninDataBody{}
|
||||
err := json.NewDecoder(r.Body).Decode(&userSignin)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Bad request")
|
||||
return
|
||||
}
|
||||
|
||||
user, err := store.GetUserByUsernameAndPassword(userSignin.Username, userSignin.Password)
|
||||
|
||||
if err != nil {
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: false,
|
||||
Message: "Username and password not allowed",
|
||||
Data: nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
session, _ := SessionStore.Get(r, "session")
|
||||
|
||||
session.Values["user_id"] = user.Id
|
||||
session.Save(r, w)
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: user,
|
||||
})
|
||||
}
|
||||
|
||||
func handleUserSignOut(w http.ResponseWriter, r *http.Request) {
|
||||
session, _ := SessionStore.Get(r, "session")
|
||||
|
||||
session.Values["user_id"] = ""
|
||||
session.Save(r, w)
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func RegisterAuthRoutes(r *mux.Router) {
|
||||
authRouter := r.PathPrefix("/api/auth").Subrouter()
|
||||
|
||||
authRouter.Use(JSONResponseMiddleWare)
|
||||
|
||||
authRouter.HandleFunc("/signup", handleUserSignUp).Methods("POST")
|
||||
authRouter.HandleFunc("/signin", handleUserSignIn).Methods("POST")
|
||||
authRouter.HandleFunc("/signout", handleUserSignOut).Methods("POST")
|
||||
type Signup struct {
|
||||
Name string
|
||||
Password string
|
||||
}
|
||||
|
@@ -1,14 +0,0 @@
|
||||
package e
|
||||
|
||||
var Codes = map[string]int{
|
||||
"NOT_AUTH": 20001,
|
||||
|
||||
"REQUEST_BODY_ERROR": 40001,
|
||||
"UPLOAD_FILE_ERROR": 40002,
|
||||
"OVERLOAD_MAX_SIZE": 40003,
|
||||
"NOT_FOUND": 40400,
|
||||
"USER_NOT_FOUND": 40401,
|
||||
"RESOURCE_NOT_FOUND": 40402,
|
||||
|
||||
"DATABASE_ERROR": 50001,
|
||||
}
|
@@ -1,50 +0,0 @@
|
||||
package e
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type ServerError struct {
|
||||
Code int
|
||||
Message string
|
||||
}
|
||||
|
||||
type ErrorResponse struct {
|
||||
Succeed bool `json:"succeed"`
|
||||
Message string `json:"message"`
|
||||
StatusCode int `json:"statusCode"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func getServerError(err string) ServerError {
|
||||
code, exists := Codes[err]
|
||||
|
||||
println(err)
|
||||
|
||||
if !exists {
|
||||
err = "BAD_REQUEST"
|
||||
code = 40000
|
||||
}
|
||||
|
||||
return ServerError{
|
||||
Code: code,
|
||||
Message: err,
|
||||
}
|
||||
}
|
||||
|
||||
func ErrorHandler(w http.ResponseWriter, err string, message string) {
|
||||
serverError := getServerError(err)
|
||||
|
||||
res := ErrorResponse{
|
||||
Succeed: false,
|
||||
Message: message,
|
||||
StatusCode: serverError.Code,
|
||||
Data: nil,
|
||||
}
|
||||
|
||||
statusCode := int(serverError.Code / 100)
|
||||
|
||||
w.WriteHeader(statusCode)
|
||||
json.NewEncoder(w).Encode(res)
|
||||
}
|
130
api/memo.go
130
api/memo.go
@@ -1,115 +1,41 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"memos/api/e"
|
||||
"memos/store"
|
||||
"net/http"
|
||||
type Memo struct {
|
||||
Id int `jsonapi:"primary,memo"`
|
||||
CreatedTs int64 `jsonapi:"attr,createdTs"`
|
||||
UpdatedTs int64 `jsonapi:"attr,updatedTs"`
|
||||
RowStatus string `jsonapi:"attr,rowStatus"`
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func handleGetMyMemos(w http.ResponseWriter, r *http.Request) {
|
||||
userId, _ := GetUserIdInSession(r)
|
||||
urlParams := r.URL.Query()
|
||||
deleted := urlParams.Get("deleted")
|
||||
onlyDeletedFlag := deleted == "true"
|
||||
|
||||
memos, err := store.GetMemosByUserId(userId, onlyDeletedFlag)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: memos,
|
||||
})
|
||||
Content string `jsonapi:"attr,content"`
|
||||
CreatorId int `jsonapi:"attr,creatorId"`
|
||||
}
|
||||
|
||||
func handleCreateMemo(w http.ResponseWriter, r *http.Request) {
|
||||
userId, _ := GetUserIdInSession(r)
|
||||
|
||||
type CreateMemoDataBody struct {
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
createMemo := CreateMemoDataBody{}
|
||||
err := json.NewDecoder(r.Body).Decode(&createMemo)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Bad request")
|
||||
return
|
||||
}
|
||||
|
||||
memo, err := store.CreateNewMemo(createMemo.Content, userId)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: memo,
|
||||
})
|
||||
type MemoCreate struct {
|
||||
Content string `jsonapi:"attr,content"`
|
||||
CreatorId int
|
||||
}
|
||||
|
||||
func handleUpdateMemo(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
memoId := vars["id"]
|
||||
type MemoPatch struct {
|
||||
Id int
|
||||
|
||||
memoPatch := store.MemoPatch{}
|
||||
err := json.NewDecoder(r.Body).Decode(&memoPatch)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Bad request")
|
||||
return
|
||||
}
|
||||
|
||||
memo, err := store.UpdateMemo(memoId, &memoPatch)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: memo,
|
||||
})
|
||||
Content *string
|
||||
RowStatus *string
|
||||
}
|
||||
|
||||
func handleDeleteMemo(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
memoId := vars["id"]
|
||||
|
||||
err := store.DeleteMemo(memoId)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: nil,
|
||||
})
|
||||
type MemoFind struct {
|
||||
Id *int
|
||||
CreatorId *int
|
||||
}
|
||||
|
||||
func RegisterMemoRoutes(r *mux.Router) {
|
||||
memoRouter := r.PathPrefix("/api/memo").Subrouter()
|
||||
|
||||
memoRouter.Use(JSONResponseMiddleWare)
|
||||
memoRouter.Use(AuthCheckerMiddleWare)
|
||||
|
||||
memoRouter.HandleFunc("/all", handleGetMyMemos).Methods("GET")
|
||||
memoRouter.HandleFunc("/", handleCreateMemo).Methods("PUT")
|
||||
memoRouter.HandleFunc("/{id}", handleUpdateMemo).Methods("PATCH")
|
||||
memoRouter.HandleFunc("/{id}", handleDeleteMemo).Methods("DELETE")
|
||||
type MemoDelete struct {
|
||||
Id *int `jsonapi:"primary,memo"`
|
||||
CreatorId *int
|
||||
}
|
||||
|
||||
type MemoService interface {
|
||||
CreateMemo(create *MemoCreate) (*Memo, error)
|
||||
PatchMemo(patch *MemoPatch) (*Memo, error)
|
||||
FindMemoList(find *MemoFind) ([]*Memo, error)
|
||||
FindMemo(find *MemoFind) (*Memo, error)
|
||||
DeleteMemo(delete *MemoDelete) error
|
||||
}
|
||||
|
@@ -1,36 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"memos/api/e"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func AuthCheckerMiddleWare(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
session, _ := SessionStore.Get(r, "session")
|
||||
|
||||
if userId, ok := session.Values["user_id"].(string); !ok || userId == "" {
|
||||
e.ErrorHandler(w, "NOT_AUTH", "Need authorize")
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func JSONResponseMiddleWare(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func CorsMiddleWare(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
113
api/query.go
113
api/query.go
@@ -1,113 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"memos/api/e"
|
||||
"memos/store"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func handleGetMyQueries(w http.ResponseWriter, r *http.Request) {
|
||||
userId, _ := GetUserIdInSession(r)
|
||||
|
||||
queries, err := store.GetQueriesByUserId(userId)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: queries,
|
||||
})
|
||||
}
|
||||
|
||||
func handleCreateQuery(w http.ResponseWriter, r *http.Request) {
|
||||
userId, _ := GetUserIdInSession(r)
|
||||
|
||||
type CreateQueryDataBody struct {
|
||||
Title string `json:"title"`
|
||||
Querystring string `json:"querystring"`
|
||||
}
|
||||
|
||||
queryData := CreateQueryDataBody{}
|
||||
err := json.NewDecoder(r.Body).Decode(&queryData)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Bad request")
|
||||
return
|
||||
}
|
||||
|
||||
query, err := store.CreateNewQuery(queryData.Title, queryData.Querystring, userId)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: query,
|
||||
})
|
||||
}
|
||||
|
||||
func handleUpdateQuery(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
queryId := vars["id"]
|
||||
|
||||
queryPatch := store.QueryPatch{}
|
||||
err := json.NewDecoder(r.Body).Decode(&queryPatch)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Bad request")
|
||||
return
|
||||
}
|
||||
|
||||
query, err := store.UpdateQuery(queryId, &queryPatch)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: query,
|
||||
})
|
||||
}
|
||||
|
||||
func handleDeleteQuery(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
queryId := vars["id"]
|
||||
|
||||
err := store.DeleteQuery(queryId)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func RegisterQueryRoutes(r *mux.Router) {
|
||||
queryRouter := r.PathPrefix("/api/query").Subrouter()
|
||||
|
||||
queryRouter.Use(JSONResponseMiddleWare)
|
||||
queryRouter.Use(AuthCheckerMiddleWare)
|
||||
|
||||
queryRouter.HandleFunc("/all", handleGetMyQueries).Methods("GET")
|
||||
queryRouter.HandleFunc("/", handleCreateQuery).Methods("PUT")
|
||||
queryRouter.HandleFunc("/{id}", handleUpdateQuery).Methods("PATCH")
|
||||
queryRouter.HandleFunc("/{id}", handleDeleteQuery).Methods("DELETE")
|
||||
}
|
142
api/resource.go
142
api/resource.go
@@ -1,130 +1,40 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"memos/api/e"
|
||||
"memos/store"
|
||||
"net/http"
|
||||
"strings"
|
||||
type Resource struct {
|
||||
Id int `jsonapi:"primary,resource"`
|
||||
CreatedTs int64 `jsonapi:"attr,createdTs"`
|
||||
UpdatedTs int64 `jsonapi:"attr,updatedTs"`
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
Filename string `jsonapi:"attr,filename"`
|
||||
Blob []byte `jsonapi:"attr,blob"`
|
||||
Type string `jsonapi:"attr,type"`
|
||||
Size int64 `jsonapi:"attr,size"`
|
||||
|
||||
func handleGetMyResources(w http.ResponseWriter, r *http.Request) {
|
||||
userId, _ := GetUserIdInSession(r)
|
||||
|
||||
resources, err := store.GetResourcesByUserId(userId)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: resources,
|
||||
})
|
||||
CreatorId int `jsonapi:"attr,creatorId"`
|
||||
}
|
||||
|
||||
func handleUploadResource(w http.ResponseWriter, r *http.Request) {
|
||||
userId, _ := GetUserIdInSession(r)
|
||||
type ResourceCreate struct {
|
||||
Filename string `jsonapi:"attr,filename"`
|
||||
Blob []byte `jsonapi:"attr,blob"`
|
||||
Type string `jsonapi:"attr,type"`
|
||||
Size int64 `jsonapi:"attr,size"`
|
||||
|
||||
err := r.ParseMultipartForm(5 << 20)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "OVERLOAD_MAX_SIZE", "The max size of resource is 5Mb.")
|
||||
return
|
||||
}
|
||||
|
||||
file, handler, err := r.FormFile("file")
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Bad request")
|
||||
return
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
filename := handler.Filename
|
||||
filetype := handler.Header.Get("Content-Type")
|
||||
size := handler.Size
|
||||
|
||||
fileBytes, err := ioutil.ReadAll(file)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "UPLOAD_FILE_ERROR", "Read file error")
|
||||
return
|
||||
}
|
||||
|
||||
resource, err := store.CreateResource(userId, filename, fileBytes, filetype, size)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "Upload file succeed",
|
||||
Data: resource,
|
||||
})
|
||||
CreatorId int `jsonapi:"attr,creatorId"`
|
||||
}
|
||||
|
||||
func handleDeleteResource(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
resourceId := vars["id"]
|
||||
|
||||
err := store.DeleteResourceById(resourceId)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: nil,
|
||||
})
|
||||
type ResourceFind struct {
|
||||
Id *int
|
||||
CreatorId *int
|
||||
Filename *string
|
||||
}
|
||||
|
||||
func handleGetResource(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
resourceId := vars["id"]
|
||||
filename := vars["filename"]
|
||||
|
||||
etag := `"` + resourceId + "/" + filename + `"`
|
||||
w.Header().Set("Etag", etag)
|
||||
w.Header().Set("Cache-Control", "max-age=2592000")
|
||||
|
||||
if match := r.Header.Get("If-None-Match"); match != "" {
|
||||
if strings.Contains(match, etag) {
|
||||
w.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
resource, err := store.GetResourceByIdAndFilename(resourceId, filename)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "RESOURCE_NOT_FOUND", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Write(resource.Blob)
|
||||
type ResourceDelete struct {
|
||||
Id int
|
||||
}
|
||||
|
||||
func RegisterResourceRoutes(r *mux.Router) {
|
||||
resourceRouter := r.PathPrefix("/").Subrouter()
|
||||
|
||||
resourceRouter.Use(AuthCheckerMiddleWare)
|
||||
|
||||
resourceRouter.HandleFunc("/api/resource/all", handleGetMyResources).Methods("GET")
|
||||
resourceRouter.HandleFunc("/api/resource/", handleUploadResource).Methods("PUT")
|
||||
resourceRouter.HandleFunc("/api/resource/{id}", handleDeleteResource).Methods("DELETE")
|
||||
resourceRouter.HandleFunc("/r/{id}/{filename}", handleGetResource).Methods("GET")
|
||||
type ResourceService interface {
|
||||
CreateResource(create *ResourceCreate) (*Resource, error)
|
||||
FindResourceList(find *ResourceFind) ([]*Resource, error)
|
||||
FindResource(find *ResourceFind) (*Resource, error)
|
||||
DeleteResource(delete *ResourceDelete) error
|
||||
}
|
||||
|
@@ -1,9 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"memos/utils"
|
||||
|
||||
"github.com/gorilla/sessions"
|
||||
)
|
||||
|
||||
var SessionStore = sessions.NewCookieStore([]byte(utils.GenUUID()))
|
53
api/shortcut.go
Normal file
53
api/shortcut.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package api
|
||||
|
||||
type Shortcut struct {
|
||||
Id int `jsonapi:"primary,shortcut"`
|
||||
CreatedTs int64 `jsonapi:"attr,createdTs"`
|
||||
UpdatedTs int64 `jsonapi:"attr,updatedTs"`
|
||||
|
||||
Title string `jsonapi:"attr,title"`
|
||||
Payload string `jsonapi:"attr,payload"`
|
||||
PinnedTs int64 `jsonapi:"attr,pinnedTs"`
|
||||
CreatorId int
|
||||
}
|
||||
|
||||
type ShortcutCreate struct {
|
||||
// Standard fields
|
||||
CreatorId int
|
||||
|
||||
// Domain specific fields
|
||||
Title string `jsonapi:"attr,title"`
|
||||
Payload string `jsonapi:"attr,payload"`
|
||||
}
|
||||
|
||||
type ShortcutPatch struct {
|
||||
Id int
|
||||
|
||||
Title *string `jsonapi:"attr,title"`
|
||||
Payload *string `jsonapi:"attr,payload"`
|
||||
PinnedTs *int64
|
||||
|
||||
Pinned *bool `jsonapi:"attr,pinned"`
|
||||
}
|
||||
|
||||
type ShortcutFind struct {
|
||||
Id *int
|
||||
|
||||
// Standard fields
|
||||
CreatorId *int
|
||||
|
||||
// Domain specific fields
|
||||
Title *string `jsonapi:"attr,title"`
|
||||
}
|
||||
|
||||
type ShortcutDelete struct {
|
||||
Id int
|
||||
}
|
||||
|
||||
type ShortcutService interface {
|
||||
CreateShortcut(create *ShortcutCreate) (*Shortcut, error)
|
||||
PatchShortcut(patch *ShortcutPatch) (*Shortcut, error)
|
||||
FindShortcutList(find *ShortcutFind) ([]*Shortcut, error)
|
||||
FindShortcut(find *ShortcutFind) (*Shortcut, error)
|
||||
DeleteShortcut(delete *ShortcutDelete) error
|
||||
}
|
@@ -1,34 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type SPAHandler struct {
|
||||
StaticPath string
|
||||
IndexPath string
|
||||
}
|
||||
|
||||
func (h SPAHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
path, err := filepath.Abs(r.URL.Path)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
path = filepath.Join(h.StaticPath, path)
|
||||
|
||||
_, err = os.Stat(path)
|
||||
if os.IsNotExist(err) {
|
||||
// file does not exist, serve index.html
|
||||
http.ServeFile(w, r, filepath.Join(h.StaticPath, h.IndexPath))
|
||||
return
|
||||
} else if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.FileServer(http.Dir(h.StaticPath)).ServeHTTP(w, r)
|
||||
}
|
159
api/user.go
159
api/user.go
@@ -1,149 +1,40 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"memos/api/e"
|
||||
"memos/store"
|
||||
"net/http"
|
||||
type User struct {
|
||||
Id int `jsonapi:"primary,user"`
|
||||
CreatedTs int64 `jsonapi:"attr,createdTs"`
|
||||
UpdatedTs int64 `jsonapi:"attr,updatedTs"`
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func handleGetMyUserInfo(w http.ResponseWriter, r *http.Request) {
|
||||
userId, _ := GetUserIdInSession(r)
|
||||
|
||||
user, err := store.GetUserById(userId)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "USER_NOT_FOUND", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: user,
|
||||
})
|
||||
Name string `jsonapi:"attr,name"`
|
||||
Password string
|
||||
OpenId string `jsonapi:"attr,openId"`
|
||||
}
|
||||
|
||||
func handleUpdateMyUserInfo(w http.ResponseWriter, r *http.Request) {
|
||||
userId, _ := GetUserIdInSession(r)
|
||||
|
||||
updateUserPatch := store.UpdateUserPatch{}
|
||||
err := json.NewDecoder(r.Body).Decode(&updateUserPatch)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Bad request")
|
||||
return
|
||||
}
|
||||
|
||||
if updateUserPatch.Username != nil {
|
||||
usernameUsable, _ := store.CheckUsernameUsable(*updateUserPatch.Username)
|
||||
if !usernameUsable {
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: false,
|
||||
Message: "Username is existed",
|
||||
Data: nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
user, err := store.UpdateUser(userId, &updateUserPatch)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: user,
|
||||
})
|
||||
type UserCreate struct {
|
||||
Name string `jsonapi:"attr,name"`
|
||||
Password string `jsonapi:"attr,password"`
|
||||
OpenId string `jsonapi:"attr,openId"`
|
||||
}
|
||||
|
||||
func handleResetUserOpenId(w http.ResponseWriter, r *http.Request) {
|
||||
userId, _ := GetUserIdInSession(r)
|
||||
type UserPatch struct {
|
||||
Id int
|
||||
|
||||
openId, err := store.ResetUserOpenId(userId)
|
||||
Name *string `jsonapi:"attr,name"`
|
||||
Password *string `jsonapi:"attr,password"`
|
||||
OpenId *string
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: openId,
|
||||
})
|
||||
ResetOpenId *bool `jsonapi:"attr,resetOpenId"`
|
||||
}
|
||||
|
||||
func handleCheckUsername(w http.ResponseWriter, r *http.Request) {
|
||||
type CheckUsernameDataBody struct {
|
||||
Username string
|
||||
}
|
||||
type UserFind struct {
|
||||
Id *int `jsonapi:"attr,id"`
|
||||
|
||||
checkUsername := CheckUsernameDataBody{}
|
||||
err := json.NewDecoder(r.Body).Decode(&checkUsername)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Bad request")
|
||||
return
|
||||
}
|
||||
|
||||
usable, err := store.CheckUsernameUsable(checkUsername.Username)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: usable,
|
||||
})
|
||||
Name *string `jsonapi:"attr,name"`
|
||||
OpenId *string
|
||||
}
|
||||
|
||||
func handleValidPassword(w http.ResponseWriter, r *http.Request) {
|
||||
type ValidPasswordDataBody struct {
|
||||
Password string
|
||||
}
|
||||
|
||||
userId, _ := GetUserIdInSession(r)
|
||||
validPassword := ValidPasswordDataBody{}
|
||||
err := json.NewDecoder(r.Body).Decode(&validPassword)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Bad request")
|
||||
return
|
||||
}
|
||||
|
||||
valid, err := store.CheckPasswordValid(userId, validPassword.Password)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: valid,
|
||||
})
|
||||
}
|
||||
|
||||
func RegisterUserRoutes(r *mux.Router) {
|
||||
userRouter := r.PathPrefix("/api/user").Subrouter()
|
||||
|
||||
userRouter.Use(JSONResponseMiddleWare)
|
||||
userRouter.Use(AuthCheckerMiddleWare)
|
||||
|
||||
userRouter.HandleFunc("/me", handleGetMyUserInfo).Methods("GET")
|
||||
userRouter.HandleFunc("/me", handleUpdateMyUserInfo).Methods("PATCH")
|
||||
userRouter.HandleFunc("/open_id/new", handleResetUserOpenId).Methods("POST")
|
||||
userRouter.HandleFunc("/checkusername", handleCheckUsername).Methods("POST")
|
||||
userRouter.HandleFunc("/validpassword", handleValidPassword).Methods("POST")
|
||||
type UserService interface {
|
||||
CreateUser(create *UserCreate) (*User, error)
|
||||
PatchUser(patch *UserPatch) (*User, error)
|
||||
FindUser(find *UserFind) (*User, error)
|
||||
}
|
||||
|
23
api/utils.go
23
api/utils.go
@@ -1,23 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Response struct {
|
||||
Succeed bool `json:"succeed"`
|
||||
Message string `json:"message"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func GetUserIdInSession(r *http.Request) (string, error) {
|
||||
session, _ := SessionStore.Get(r, "session")
|
||||
|
||||
userId, ok := session.Values["user_id"].(string)
|
||||
|
||||
if !ok {
|
||||
return "", http.ErrNoCookie
|
||||
}
|
||||
|
||||
return userId, nil
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"memos/api/e"
|
||||
"memos/store"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func handleCreateMemoByWH(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
openId := vars["openId"]
|
||||
|
||||
type CreateMemoDataBody struct {
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
createMemo := CreateMemoDataBody{}
|
||||
err := json.NewDecoder(r.Body).Decode(&createMemo)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "REQUEST_BODY_ERROR", "Bad request")
|
||||
return
|
||||
}
|
||||
|
||||
user, err := store.GetUserByOpenId(openId)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
memo, err := store.CreateNewMemo(createMemo.Content, user.Id)
|
||||
|
||||
if err != nil {
|
||||
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(Response{
|
||||
Succeed: true,
|
||||
Message: "",
|
||||
Data: memo,
|
||||
})
|
||||
}
|
||||
|
||||
func RegisterWebHooksRoutes(r *mux.Router) {
|
||||
memoRouter := r.PathPrefix("/api/whs").Subrouter()
|
||||
|
||||
memoRouter.Use(JSONResponseMiddleWare)
|
||||
|
||||
memoRouter.HandleFunc("/memo/{openId}", handleCreateMemoByWH).Methods("POST")
|
||||
}
|
Reference in New Issue
Block a user