예제 #1
0
파일: handlers.go 프로젝트: husio/apps
func HandleUpdateNote(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	var input Note
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		web.JSONErr(w, err.Error(), http.StatusBadRequest)
		return
	}

	if errs := validateNote(&input); len(errs) > 0 {
		web.JSONErrs(w, errs, http.StatusBadRequest)
		return
	}

	tx, err := pg.DB(ctx).Beginx()
	if err != nil {
		log.Printf("cannot start transaction: %s", err)
		web.StdJSONErr(w, http.StatusInternalServerError)
		return
	}
	defer tx.Rollback()

	acc, ok := auth.AuthRequired(tx, w, r)
	if !ok {
		return
	}
	noteID := stoint(web.Args(ctx).ByIndex(0))

	if ok, err := IsNoteOwner(tx, noteID, acc.AccountID); err != nil {
		log.Printf("cannot check %d note owner: %s", noteID, err)
		web.StdJSONErr(w, http.StatusInternalServerError)
		return
	} else if !ok {
		web.JSONErr(w, "you are not owner of this note", http.StatusUnauthorized)
		return
	}

	note, err := UpdateNote(tx, input)
	if err != nil {
		log.Printf("cannot update %d note: %s", noteID, err)
		web.StdJSONErr(w, http.StatusInternalServerError)
		return
	}
	if err := tx.Commit(); err != nil {
		log.Printf("cannot commit transaction: %s", err)
		web.StdJSONErr(w, http.StatusInternalServerError)
		return
	}
	web.JSONResp(w, note, http.StatusOK)
}
예제 #2
0
파일: handlers.go 프로젝트: husio/apps
func HandleCreateNote(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	var note Note
	if err := json.NewDecoder(r.Body).Decode(&note); err != nil {
		web.JSONErr(w, err.Error(), http.StatusBadRequest)
		return
	}

	acc, ok := auth.AuthRequired(pg.DB(ctx), w, r)
	if !ok {
		return
	}

	if errs := validateNote(&note); len(errs) > 0 {
		web.JSONErrs(w, errs, http.StatusBadRequest)
		return
	}

	note.OwnerID = acc.AccountID

	n, err := CreateNote(pg.DB(ctx), note)
	if err != nil {
		log.Printf("cannot create note: %s", err)
		web.StdJSONErr(w, http.StatusInternalServerError)
		return
	}
	web.JSONResp(w, n, http.StatusCreated)
}
예제 #3
0
파일: handlers.go 프로젝트: husio/apps
func HandlePasteUpdate(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	var input struct {
		Content string
	}
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		web.StdJSONResp(w, http.StatusBadRequest)
		return
	}

	if input.Content == "" {
		web.JSONErr(w, `"Content" is required"`, http.StatusBadRequest)
		return
	}

	pid, _ := strconv.ParseInt(web.Args(ctx).ByIndex(0), 10, 64)

	db := pg.DB(ctx)
	paste, err := UpdatePaste(db, Paste{
		ID:      pid,
		Content: input.Content,
	})
	switch err {
	case nil:
		web.JSONResp(w, paste, http.StatusOK)
	case pg.ErrNotFound:
		web.StdJSONResp(w, http.StatusNotFound)
	default:
		log.Printf("cannot update paste %d: %s", pid, err)
		web.StdJSONResp(w, http.StatusInternalServerError)
	}
}
예제 #4
0
파일: handlers.go 프로젝트: husio/apps
// handlePublicKey return public RSA key for requested key ID.
func handlePublicKey(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	kid := web.Args(ctx).ByIndex(0)
	key, ok := keys.Manager(ctx).KeyByID(kid)
	if !ok {
		web.JSONErr(w, "key not found", http.StatusNotFound)
		return
	}
	w.Header().Set("Content-Type", "application/pkix-crl")
	w.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s.pub"`, kid))
	fmt.Fprint(w, key)
}
예제 #5
0
파일: handlers.go 프로젝트: husio/apps
func handleAddBookmark(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	var input struct {
		Url string `json:"url"`
	}
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		web.JSONErr(w, err.Error(), http.StatusBadRequest)
		return
	}

	resp, err := ctxhttp.Get(ctx, &crawler, input.Url)
	if err != nil {
		log.Error("cannot crawl",
			"url", input.Url,
			"error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}
	defer resp.Body.Close()

	body := make([]byte, 1024*20)
	if n, err := resp.Body.Read(body); err != nil && err != io.EOF {
		log.Error("cannot read crawler response",
			"url", input.Url,
			"error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	} else {
		body = body[:n]
	}

	title := pageTitle(body)

	var b Bookmark
	err = pg.DB(ctx).Get(&b, `
		INSERT INTO bookmarks (title, url, created)
		VALUES ($1, $2, $3)
		ON CONFLICT DO NOTHING
		RETURNING *
	`, title, input.Url, time.Now())
	if err != nil {
		log.Error("cannot create bookmark", "error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}

	web.JSONResp(w, b, http.StatusCreated)
}
예제 #6
0
파일: handlers.go 프로젝트: husio/apps
func HandleDeleteNote(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	tx, err := pg.DB(ctx).Beginx()
	if err != nil {
		log.Printf("cannot start transaction: %s", err)
		web.StdJSONErr(w, http.StatusInternalServerError)
		return
	}
	defer tx.Rollback()

	acc, ok := auth.AuthRequired(tx, w, r)
	if !ok {
		return
	}
	noteID := stoint(web.Args(ctx).ByIndex(0))

	if ok, err := IsNoteOwner(tx, noteID, acc.AccountID); err != nil {
		if err == pg.ErrNotFound {
			web.StdJSONErr(w, http.StatusNotFound)
		} else {
			log.Printf("cannot check %d note owner: %s", noteID, err)
			web.StdJSONErr(w, http.StatusInternalServerError)
		}
		return
	} else if !ok {
		web.JSONErr(w, "you are not owner of this note", http.StatusUnauthorized)
		return
	}

	if err := DeleteNote(tx, noteID); err != nil {
		log.Printf("cannot delete %d note: %s", noteID, err)
		web.StdJSONErr(w, http.StatusInternalServerError)
		return
	}

	if err := tx.Commit(); err != nil {
		log.Printf("cannot commit transaction: %s", err)
		web.StdJSONErr(w, http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusGone)
}
예제 #7
0
파일: note.go 프로젝트: husio/apps
func handleAddNote(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	var input struct {
		Content string    `json:"content"`
		Created time.Time `json:"created"`
	}

	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		web.JSONErr(w, err.Error(), http.StatusBadRequest)
		return
	}

	var errs []string
	if input.Content == "" {
		errs = append(errs, `"content" is required`)
	}
	if len(errs) != 0 {
		web.JSONErrs(w, errs, http.StatusBadRequest)
		return
	}

	if input.Created.IsZero() {
		input.Created = time.Now()
	}

	n := Note{
		NoteID:  generateId(),
		Content: input.Content,
		Created: input.Created,
	}

	key := datastore.NewKey(ctx, "Note", n.NoteID, 0, nil)
	_, err := datastore.Put(ctx, key, &n)
	if err != nil {
		log.Debug("cannot put note", "error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}

	web.JSONResp(w, &n, http.StatusCreated)
}
예제 #8
0
파일: handlers.go 프로젝트: husio/apps
func HandlePasteCreate(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	var input struct {
		Content string
	}
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		web.StdJSONResp(w, http.StatusBadRequest)
		return
	}

	if input.Content == "" {
		web.JSONErr(w, `"Content" is required"`, http.StatusBadRequest)
		return
	}

	db := pg.DB(ctx)
	paste, err := CreatePaste(db, Paste{Content: input.Content})
	if err != nil {
		log.Printf("cannot create paste: %s", err)
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}
	web.JSONResp(w, paste, http.StatusCreated)
}
예제 #9
0
파일: handlers.go 프로젝트: husio/apps
func HandleListNotes(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	db := pg.DB(ctx)

	acc, ok := auth.AuthRequired(db, w, r)
	if !ok {
		return
	}

	var offset int
	if raw := r.URL.Query().Get("offset"); raw != "" {
		if n, err := strconv.Atoi(raw); err != nil {
			web.JSONErr(w, "invalid 'offset' value", http.StatusBadRequest)
			return
		} else {
			offset = n
		}
	}

	notes, err := NotesByOwner(db, acc.AccountID, 300, offset)
	if err != nil {
		log.Printf("cannot fetch notes for %d: %s", acc.AccountID, err)
		web.StdJSONErr(w, http.StatusInternalServerError)
		return
	}

	if notes == nil {
		notes = make([]*Note, 0) // JSON api should return empty list
	}

	content := struct {
		Notes []*Note
	}{
		Notes: notes,
	}
	web.JSONResp(w, content, http.StatusOK)
}
예제 #10
0
파일: handlers.go 프로젝트: husio/apps
func handleUploadImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	if err := r.ParseMultipartForm(10 * megabyte); err != nil {
		web.JSONResp(w, err.Error(), http.StatusBadRequest)
		return
	}

	var header *multipart.FileHeader
	for _, headers := range r.MultipartForm.File {
		for _, h := range headers {
			log.Debug("uploading file", "name", h.Filename)
			if header != nil {
				web.JSONErr(w, "cannot upload more than one time at once", http.StatusBadRequest)
				return
			}
			header = h
		}
	}
	if header == nil {
		web.JSONErr(w, "image file missing", http.StatusBadRequest)
		return
	}
	if !strings.HasSuffix(strings.ToLower(header.Filename), ".jpg") {
		// XXX this is not the best validation
		web.JSONErr(w, "only JPEG format is allowed", http.StatusBadRequest)
		return
	}

	fd, err := header.Open()
	if err != nil {
		log.Error("cannot open uploaded file",
			"name", header.Filename,
			"error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}
	defer fd.Close()

	image, err := imageMeta(fd)
	if err != nil {
		log.Error("cannot extract image metadata", "error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}

	// store image in database
	db := sq.DB(ctx)
	image, err = CreateImage(db, *image)
	switch err {
	case nil:
		// all good
	case sq.ErrConflict:
		// image already exists, nothing more to do here
		web.JSONResp(w, image, http.StatusOK)
		return
	default:
		log.Error("cannot create object", "error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}

	if _, err := fd.Seek(0, os.SEEK_SET); err != nil {
		log.Error("cannot seek image", "error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}

	fs := FileStore(ctx)
	if err := fs.Put(image, fd); err != nil {
		log.Error("cannot store image", "error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}
	log.Debug("image file created", "id", image.ImageID)

	web.JSONResp(w, image, http.StatusCreated)
}
예제 #11
0
파일: handlers.go 프로젝트: husio/apps
func handleTagImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	var input struct {
		Name  string
		Value string
	}
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		web.JSONErr(w, err.Error(), http.StatusBadRequest)
		return
	}

	var errs []string
	if input.Name == "" {
		errs = append(errs, `"name" is required`)
	}
	if input.Value == "" {
		errs = append(errs, `"value" is required`)
	}
	if len(errs) != 0 {
		web.JSONErrs(w, errs, http.StatusBadRequest)
		return
	}

	db := sq.DB(ctx)

	img, err := ImageByID(db, web.Args(ctx).ByIndex(0))
	switch err {
	case nil:
		// all good
	case sq.ErrNotFound:
		web.JSONErr(w, "parent image does not exist", http.StatusBadRequest)
		return
	default:
		log.Error("database error",
			"image", web.Args(ctx).ByIndex(0),
			"error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}

	tag, err := CreateTag(db, Tag{
		ImageID: img.ImageID,
		Name:    input.Name,
		Value:   input.Value,
	})
	switch err {
	case nil:
		// all good, update storage meta
	case sq.ErrConflict:
		web.JSONResp(w, tag, http.StatusOK)
		return
	default:
		log.Error("cannot create object", "error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}

	if img.Tags, err = ImageTags(db, img.ImageID); err != nil {
		log.Error("cannot get image tags",
			"image", img.ImageID,
			"error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}

	fs := FileStore(ctx)
	if err := fs.PutMeta(img); err != nil {
		log.Error("cannot store image metadata",
			"image", img.ImageID,
			"error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}

	web.JSONResp(w, tag, http.StatusCreated)
}