Add resources api (#9)

* feat: add resource api

* update delete model return variables
pull/10/head
STEVEN 3 years ago committed by GitHub
parent 6589671da8
commit aa40793a68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -4,6 +4,7 @@ var Codes = map[string]int{
"NOT_AUTH": 20001,
"REQUEST_BODY_ERROR": 40001,
"UPLOAD_FILE_ERROR": 40002,
"DATABASE_ERROR": 50001,
}

@ -88,7 +88,7 @@ func handleDeleteMemo(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
memoId := vars["id"]
_, err := store.DeleteMemo(memoId)
err := store.DeleteMemo(memoId)
if err != nil {
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())

@ -86,7 +86,7 @@ func handleDeleteQuery(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
queryId := vars["id"]
_, err := store.DeleteQuery(queryId)
err := store.DeleteQuery(queryId)
if err != nil {
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())

@ -0,0 +1,114 @@
package api
import (
"encoding/json"
"fmt"
"io/ioutil"
"memos/api/e"
"memos/store"
"net/http"
"github.com/gorilla/mux"
)
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,
})
}
func handleUploadResource(w http.ResponseWriter, r *http.Request) {
userId, _ := GetUserIdInSession(r)
r.ParseMultipartForm(10 << 20)
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")
fmt.Println(err)
}
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,
})
}
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,
})
}
func handleGetResource(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
resourceId := vars["id"]
filename := vars["filename"]
resource, err := store.GetResourceByIdAndFilename(resourceId, filename)
if err != nil {
e.ErrorHandler(w, "DATABASE_ERROR", err.Error())
return
}
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/octet-stream")
w.Write(resource.Blob)
}
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")
}

@ -1,5 +1,6 @@
DROP TABLE IF EXISTS `memos`;
DROP TABLE IF EXISTS `queries`;
DROP TABLE IF EXISTS `resources`;
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
@ -33,6 +34,18 @@ CREATE TABLE `memos` (
FOREIGN KEY(`user_id`) REFERENCES `users`(`id`)
);
CREATE TABLE `resources` (
`id` TEXT NOT NULL PRIMARY KEY,
`user_id` TEXT NOT NULL,
`filename` TEXT NOT NULL,
`blob` BLOB NOT NULL,
`type` TEXT NOT NULL,
`size` INTEGER NOT NULL DEFAULT 0,
`created_at` TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')),
FOREIGN KEY(`user_id`) REFERENCES `users`(`id`)
);
INSERT INTO `users`
(`id`, `username`, `password`)
VALUES

Binary file not shown.

@ -17,6 +17,7 @@ func main() {
api.RegisterUserRoutes(r)
api.RegisterMemoRoutes(r)
api.RegisterQueryRoutes(r)
api.RegisterResourceRoutes(r)
webServe := api.SPAHandler{
StaticPath: "./web/dist",

@ -57,11 +57,11 @@ func UpdateMemo(id string, memoPatch *MemoPatch) (Memo, error) {
return memo, err
}
func DeleteMemo(memoId string) (error, error) {
func DeleteMemo(memoId string) error {
query := `DELETE FROM memos WHERE id=?`
_, err := DB.Exec(query, memoId)
return nil, err
return err
}
func GetMemoById(id string) (Memo, error) {

@ -64,11 +64,11 @@ func UpdateQuery(id string, queryPatch *QueryPatch) (Query, error) {
return query, err
}
func DeleteQuery(queryId string) (error, error) {
func DeleteQuery(queryId string) error {
query := `DELETE FROM queries WHERE id=?`
_, err := DB.Exec(query, queryId)
return nil, err
return err
}
func GetQueryById(queryId string) (Query, error) {

@ -0,0 +1,63 @@
package store
import "memos/utils"
type Resource struct {
Id string `json:"id"`
UserId string `json:"userId"`
Filename string `json:"filename"`
Blob []byte `json:"blob"`
Type string `json:"type"`
Size int64 `json:"size"`
CreatedAt string `json:"createdAt"`
}
func CreateResource(userId string, filename string, blob []byte, filetype string, size int64) (Resource, error) {
newResource := Resource{
Id: utils.GenUUID(),
UserId: userId,
Filename: filename,
Blob: blob,
Type: filetype,
Size: size,
CreatedAt: utils.GetNowDateTimeStr(),
}
query := `INSERT INTO resources (id, user_id, filename, blob, type, size, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)`
_, err := DB.Exec(query, newResource.Id, newResource.UserId, newResource.Filename, newResource.Blob, newResource.Type, newResource.Size, newResource.CreatedAt)
return newResource, err
}
func GetResourcesByUserId(userId string) ([]Resource, error) {
query := `SELECT id, filename, type, size, created_at FROM resources WHERE user_id=?`
rows, _ := DB.Query(query, userId)
defer rows.Close()
resources := []Resource{}
for rows.Next() {
resource := Resource{}
rows.Scan(&resource.Id, &resource.Filename, &resource.Type, &resource.Size, &resource.CreatedAt)
resources = append(resources, resource)
}
if err := rows.Err(); err != nil {
return nil, err
}
return resources, nil
}
func GetResourceByIdAndFilename(id string, filename string) (Resource, error) {
query := `SELECT id, filename, blob, type, size FROM resources WHERE id=? AND filename=?`
resource := Resource{}
err := DB.QueryRow(query, id, filename).Scan(&resource.Id, &resource.Filename, &resource.Blob, &resource.Type, &resource.Size)
return resource, err
}
func DeleteResourceById(id string) error {
query := `DELETE FROM resources WHERE id=?`
_, err := DB.Exec(query, id)
return err
}

@ -6,16 +6,26 @@ type ResponseType<T = unknown> = {
data: T;
};
async function request<T>(method: string, url: string, data?: any): Promise<ResponseType<T>> {
type RequestConfig = {
method: string;
url: string;
data?: any;
dataType?: "json" | "file";
};
async function request<T>(config: RequestConfig): Promise<ResponseType<T>> {
const { method, url, data, dataType } = config;
const requestConfig: RequestInit = {
method,
};
if (method !== "GET") {
requestConfig.headers = {
"Content-Type": "application/json",
};
if (data !== null) {
if (data !== undefined) {
if (dataType === "file") {
requestConfig.body = data;
} else {
requestConfig.headers = {
"Content-Type": "application/json",
};
requestConfig.body = JSON.stringify(data);
}
}
@ -32,87 +42,169 @@ async function request<T>(method: string, url: string, data?: any): Promise<Resp
namespace api {
export function getUserInfo() {
return request<Model.User>("GET", "/api/user/me");
return request<Model.User>({
method: "GET",
url: "/api/user/me",
});
}
export function signin(username: string, password: string) {
return request("POST", "/api/auth/signin", { username, password });
return request({
method: "POST",
url: "/api/auth/signin",
data: { username, password },
});
}
export function signup(username: string, password: string) {
return request("POST", "/api/auth/signup", { username, password });
return request({
method: "POST",
url: "/api/auth/signup",
data: { username, password },
});
}
export function signout() {
return request("POST", "/api/auth/signout");
return request({
method: "POST",
url: "/api/auth/signout",
});
}
export function checkUsernameUsable(username: string) {
return request<boolean>("POST", "/api/user/checkusername", { username });
return request<boolean>({
method: "POST",
url: "/api/user/checkusername",
data: { username },
});
}
export function checkPasswordValid(password: string) {
return request<boolean>("POST", "/api/user/validpassword", { password });
return request<boolean>({
method: "POST",
url: "/api/user/validpassword",
data: { password },
});
}
export function updateUserinfo(userinfo: Partial<{ username: string; password: string; githubName: string }>) {
return request("PATCH", "/api/user/me", userinfo);
return request({
method: "PATCH",
url: "/api/user/me",
data: userinfo,
});
}
export function getMyMemos() {
return request<Model.Memo[]>("GET", "/api/memo/all");
return request<Model.Memo[]>({
method: "GET",
url: "/api/memo/all",
});
}
export function getMyDeletedMemos() {
return request<Model.Memo[]>("GET", "/api/memo/all?deleted=true");
return request<Model.Memo[]>({
method: "GET",
url: "/api/memo/all?deleted=true",
});
}
export function createMemo(content: string) {
return request<Model.Memo>("PUT", "/api/memo/", { content });
return request<Model.Memo>({
method: "PUT",
url: "/api/memo/",
data: { content },
});
}
export function updateMemo(memoId: string, content: string) {
return request<Model.Memo>("PATCH", `/api/memo/${memoId}`, { content });
return request<Model.Memo>({
method: "PATCH",
url: `/api/memo/${memoId}`,
data: { content },
});
}
export function hideMemo(memoId: string) {
return request("PATCH", `/api/memo/${memoId}`, {
deletedAt: utils.getDateTimeString(Date.now()),
return request({
method: "PATCH",
url: `/api/memo/${memoId}`,
data: {
deletedAt: utils.getDateTimeString(Date.now()),
},
});
}
export function restoreMemo(memoId: string) {
return request("PATCH", `/api/memo/${memoId}`, {
deletedAt: "",
return request({
method: "PATCH",
url: `/api/memo/${memoId}`,
data: {
deletedAt: "",
},
});
}
export function deleteMemo(memoId: string) {
return request("DELETE", `/api/memo/${memoId}`);
return request({
method: "DELETE",
url: `/api/memo/${memoId}`,
});
}
export function getMyQueries() {
return request<Model.Query[]>("GET", "/api/query/all");
return request<Model.Query[]>({
method: "GET",
url: "/api/query/all",
});
}
export function createQuery(title: string, querystring: string) {
return request<Model.Query>("PUT", "/api/query/", { title, querystring });
return request<Model.Query>({
method: "PUT",
url: "/api/query/",
data: { title, querystring },
});
}
export function updateQuery(queryId: string, title: string, querystring: string) {
return request<Model.Query>("PATCH", `/api/query/${queryId}`, { title, querystring });
return request<Model.Query>({
method: "PATCH",
url: `/api/query/${queryId}`,
data: { title, querystring },
});
}
export function deleteQueryById(queryId: string) {
return request("DELETE", `/api/query/${queryId}`);
return request({
method: "DELETE",
url: `/api/query/${queryId}`,
});
}
export function pinQuery(queryId: string) {
return request("PATCH", `/api/query/${queryId}`, { pinnedAt: utils.getDateTimeString(Date.now()) });
return request({
method: "PATCH",
url: `/api/query/${queryId}`,
data: { pinnedAt: utils.getDateTimeString(Date.now()) },
});
}
export function unpinQuery(queryId: string) {
return request("PATCH", `/api/query/${queryId}`, { pinnedAt: "" });
return request({
method: "PATCH",
url: `/api/query/${queryId}`,
data: { pinnedAt: "" },
});
}
export function uploadFile(formData: FormData) {
return request({
method: "PUT",
url: "/api/resource/",
data: formData,
dataType: "file",
});
}
}

Loading…
Cancel
Save