/* Copyright (C) 2019, 2020, 2021 Monomax Software Pty Ltd * * This file is part of Dnote. * * Dnote is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Dnote is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Dnote. If not, see . */ package api // import ( // "fmt" // "net/http" // "net/url" // "strconv" // "strings" // "time" // // "github.com/dnote/dnote/pkg/server/database" // "github.com/dnote/dnote/pkg/server/helpers" // "github.com/dnote/dnote/pkg/server/middleware" // "github.com/dnote/dnote/pkg/server/operations" // "github.com/dnote/dnote/pkg/server/presenters" // "github.com/gorilla/mux" // "github.com/jinzhu/gorm" // "github.com/pkg/errors" // ) // // type ftsParams struct { // HighlightAll bool // } // // func getHeadlineOptions(params *ftsParams) string { // headlineOptions := []string{ // "StartSel=", // "StopSel=", // "ShortWord=0", // } // // if params != nil && params.HighlightAll { // headlineOptions = append(headlineOptions, "HighlightAll=true") // } else { // headlineOptions = append(headlineOptions, "MaxFragments=3, MaxWords=50, MinWords=10") // } // // return strings.Join(headlineOptions, ",") // } // // func selectFTSFields(conn *gorm.DB, search string, params *ftsParams) *gorm.DB { // headlineOpts := getHeadlineOptions(params) // // return conn.Select(` // notes.id, // notes.uuid, // notes.created_at, // notes.updated_at, // notes.book_uuid, // notes.user_id, // notes.added_on, // notes.edited_on, // notes.usn, // notes.deleted, // notes.encrypted, // ts_headline('english_nostop', notes.body, plainto_tsquery('english_nostop', ?), ?) AS body // `, search, headlineOpts) // } // // func respondWithNote(w http.ResponseWriter, note database.Note) { // presentedNote := presenters.PresentNote(note) // // middleware.RespondJSON(w, http.StatusOK, presentedNote) // } // // func parseSearchQuery(q url.Values) string { // searchStr := q.Get("q") // // return escapeSearchQuery(searchStr) // } // // func getNoteBaseQuery(db *gorm.DB, noteUUID string, search string) *gorm.DB { // var conn *gorm.DB // if search != "" { // conn = selectFTSFields(db, search, &ftsParams{HighlightAll: true}) // } else { // conn = db // } // // conn = conn.Where("notes.uuid = ? AND deleted = ?", noteUUID, false) // // return conn // } // // func (a *API) getNote(w http.ResponseWriter, r *http.Request) { // user, _, err := middleware.AuthWithSession(a.App.DB, r) // if err != nil { // middleware.DoError(w, "authenticating", err, http.StatusInternalServerError) // return // } // // vars := mux.Vars(r) // noteUUID := vars["noteUUID"] // // note, ok, err := operations.GetNote(a.App.DB, noteUUID, &user) // if !ok { // middleware.RespondNotFound(w) // return // } // if err != nil { // middleware.DoError(w, "finding note", err, http.StatusInternalServerError) // return // } // // respondWithNote(w, note) // } // // /**** getNotesHandler */ // // // GetNotesResponse is a reponse by getNotesHandler // type GetNotesResponse struct { // Notes []presenters.Note `json:"notes"` // Total int `json:"total"` // } // // type dateRange struct { // lower int64 // upper int64 // } // // func (a *API) getNotes(w http.ResponseWriter, r *http.Request) { // user, ok := r.Context().Value(helpers.KeyUser).(database.User) // if !ok { // middleware.DoError(w, "No authenticated user found", nil, http.StatusInternalServerError) // return // } // query := r.URL.Query() // // respondGetNotes(a.App.DB, user.ID, query, w) // } // // func respondGetNotes(db *gorm.DB, userID int, query url.Values, w http.ResponseWriter) { // q, err := parseGetNotesQuery(query) // if err != nil { // http.Error(w, err.Error(), http.StatusBadRequest) // return // } // // conn := getNotesBaseQuery(db, userID, q) // // var total int // if err := conn.Model(database.Note{}).Count(&total).Error; err != nil { // middleware.DoError(w, "counting total", err, http.StatusInternalServerError) // return // } // // notes := []database.Note{} // if total != 0 { // conn = orderGetNotes(conn) // conn = database.PreloadNote(conn) // conn = paginate(conn, q.Page) // // if err := conn.Find(¬es).Error; err != nil { // middleware.DoError(w, "finding notes", err, http.StatusInternalServerError) // return // } // } // // response := GetNotesResponse{ // Notes: presenters.PresentNotes(notes), // Total: total, // } // middleware.RespondJSON(w, http.StatusOK, response) // } // // type getNotesQuery struct { // Year int // Month int // Page int // Books []string // Search string // Encrypted bool // } // // func parseGetNotesQuery(q url.Values) (getNotesQuery, error) { // yearStr := q.Get("year") // monthStr := q.Get("month") // books := q["book"] // pageStr := q.Get("page") // encryptedStr := q.Get("encrypted") // // fmt.Println("books", books) // // var page int // if len(pageStr) > 0 { // p, err := strconv.Atoi(pageStr) // if err != nil { // return getNotesQuery{}, errors.Errorf("invalid page %s", pageStr) // } // if p < 1 { // return getNotesQuery{}, errors.Errorf("invalid page %s", pageStr) // } // // page = p // } else { // page = 1 // } // // var year int // if len(yearStr) > 0 { // y, err := strconv.Atoi(yearStr) // if err != nil { // return getNotesQuery{}, errors.Errorf("invalid year %s", yearStr) // } // // year = y // } // // var month int // if len(monthStr) > 0 { // m, err := strconv.Atoi(monthStr) // if err != nil { // return getNotesQuery{}, errors.Errorf("invalid month %s", monthStr) // } // if m < 1 || m > 12 { // return getNotesQuery{}, errors.Errorf("invalid month %s", monthStr) // } // // month = m // } // // var encrypted bool // if strings.ToLower(encryptedStr) == "true" { // encrypted = true // } else { // encrypted = false // } // // ret := getNotesQuery{ // Year: year, // Month: month, // Page: page, // Search: parseSearchQuery(q), // Books: books, // Encrypted: encrypted, // } // // return ret, nil // } // // func getDateBounds(year, month int) (int64, int64) { // var yearUpperbound, monthUpperbound int // // if month == 12 { // monthUpperbound = 1 // yearUpperbound = year + 1 // } else { // monthUpperbound = month + 1 // yearUpperbound = year // } // // lower := time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC).UnixNano() // upper := time.Date(yearUpperbound, time.Month(monthUpperbound), 1, 0, 0, 0, 0, time.UTC).UnixNano() // // return lower, upper // } // // func getNotesBaseQuery(db *gorm.DB, userID int, q getNotesQuery) *gorm.DB { // conn := db.Where( // "notes.user_id = ? AND notes.deleted = ? AND notes.encrypted = ?", // userID, false, q.Encrypted, // ) // // if q.Search != "" { // conn = selectFTSFields(conn, q.Search, nil) // conn = conn.Where("tsv @@ plainto_tsquery('english_nostop', ?)", q.Search) // } // // if len(q.Books) > 0 { // conn = conn.Joins("INNER JOIN books ON books.uuid = notes.book_uuid"). // Where("books.label in (?)", q.Books) // } // // if q.Year != 0 || q.Month != 0 { // dateLowerbound, dateUpperbound := getDateBounds(q.Year, q.Month) // conn = conn.Where("notes.added_on >= ? AND notes.added_on < ?", dateLowerbound, dateUpperbound) // } // // return conn // } // // func orderGetNotes(conn *gorm.DB) *gorm.DB { // return conn.Order("notes.updated_at DESC, notes.id DESC") // } // // // escapeSearchQuery escapes the query for full text search // func escapeSearchQuery(searchQuery string) string { // return strings.Join(strings.Fields(searchQuery), "&") // } // // func (a *API) legacyGetNotes(w http.ResponseWriter, r *http.Request) { // user, ok := r.Context().Value(helpers.KeyUser).(database.User) // if !ok { // middleware.DoError(w, "No authenticated user found", nil, http.StatusInternalServerError) // return // } // // var notes []database.Note // if err := a.App.DB.Where("user_id = ? AND encrypted = true", user.ID).Find(¬es).Error; err != nil { // middleware.DoError(w, "finding notes", err, http.StatusInternalServerError) // return // } // // presented := presenters.PresentNotes(notes) // middleware.RespondJSON(w, http.StatusOK, presented) // }