1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-08-02 20:15:26 +02:00

pin spaces and documents to sidebar

This commit is contained in:
Harvey Kandola 2016-11-21 19:27:18 -08:00
parent e0d2dd47df
commit 8cc798990a
27 changed files with 2943 additions and 1589 deletions

View file

@ -276,6 +276,14 @@ func DeleteDocument(w http.ResponseWriter, r *http.Request) {
return
}
_, err = p.DeletePinnedDocument(documentID)
if err != nil && err != sql.ErrNoRows {
log.IfErr(tx.Rollback())
writeServerError(w, method, err)
return
}
log.IfErr(tx.Commit())
writeSuccessEmptyJSON(w)

View file

@ -319,6 +319,14 @@ func RemoveFolder(w http.ResponseWriter, r *http.Request) {
return
}
_, err = p.DeletePinnedSpace(id)
if err != nil && err != sql.ErrNoRows {
log.IfErr(tx.Rollback())
writeServerError(w, method, err)
return
}
log.IfErr(tx.Commit())
writeSuccessString(w, "{}")

View file

@ -0,0 +1,235 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
package endpoint
import (
"database/sql"
"encoding/json"
"io/ioutil"
"net/http"
"strings"
"github.com/documize/community/core/api/entity"
"github.com/documize/community/core/api/request"
"github.com/documize/community/core/api/util"
"github.com/documize/community/core/log"
"github.com/gorilla/mux"
)
// AddPin saves pinned item.
func AddPin(w http.ResponseWriter, r *http.Request) {
method := "AddPin"
p := request.GetPersister(r)
params := mux.Vars(r)
userID := params["userID"]
if !p.Context.Authenticated {
writeForbiddenError(w)
return
}
if len(userID) == 0 {
writeMissingDataError(w, method, "userID")
return
}
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
if err != nil {
writePayloadError(w, method, err)
return
}
var pin entity.Pin
err = json.Unmarshal(body, &pin)
if err != nil {
writePayloadError(w, method, err)
return
}
pin.RefID = util.UniqueID()
pin.OrgID = p.Context.OrgID
pin.UserID = p.Context.UserID
pin.Pin = strings.TrimSpace(pin.Pin)
if len(pin.Pin) > 20 {
pin.Pin = pin.Pin[0:20]
}
tx, err := request.Db.Beginx()
if err != nil {
writeTransactionError(w, method, err)
return
}
p.Context.Transaction = tx
err = p.AddPin(pin)
if err != nil {
log.IfErr(tx.Rollback())
writeGeneralSQLError(w, method, err)
return
}
log.IfErr(tx.Commit())
newPin, err := p.GetPin(pin.RefID)
if err != nil {
writeGeneralSQLError(w, method, err)
return
}
util.WriteJSON(w, newPin)
}
// GetUserPins returns users' pins.
func GetUserPins(w http.ResponseWriter, r *http.Request) {
method := "GetUserPins"
p := request.GetPersister(r)
params := mux.Vars(r)
userID := params["userID"]
if len(userID) == 0 {
writeMissingDataError(w, method, "userID")
return
}
if p.Context.UserID != userID {
writeForbiddenError(w)
return
}
pins, err := p.GetUserPins(userID)
if err != nil && err != sql.ErrNoRows {
writeGeneralSQLError(w, method, err)
return
}
if err == sql.ErrNoRows {
pins = []entity.Pin{}
}
json, err := json.Marshal(pins)
if err != nil {
writeJSONMarshalError(w, method, "pin", err)
return
}
writeSuccessBytes(w, json)
}
// DeleteUserPin removes saved user pin.
func DeleteUserPin(w http.ResponseWriter, r *http.Request) {
method := "DeleteUserPin"
p := request.GetPersister(r)
params := mux.Vars(r)
userID := params["userID"]
pinID := params["pinID"]
if len(userID) == 0 {
writeMissingDataError(w, method, "userID")
return
}
if len(pinID) == 0 {
writeMissingDataError(w, method, "pinID")
return
}
if p.Context.UserID != userID {
writeForbiddenError(w)
return
}
tx, err := request.Db.Beginx()
if err != nil {
writeTransactionError(w, method, err)
return
}
p.Context.Transaction = tx
_, err = p.DeletePin(pinID)
if err != nil && err != sql.ErrNoRows {
log.IfErr(tx.Rollback())
writeGeneralSQLError(w, method, err)
return
}
log.IfErr(tx.Commit())
util.WriteSuccessEmptyJSON(w)
}
// UpdatePinSequence records order of pinned items.
func UpdatePinSequence(w http.ResponseWriter, r *http.Request) {
method := "UpdatePinSequence"
p := request.GetPersister(r)
params := mux.Vars(r)
userID := params["userID"]
if !p.Context.Authenticated {
writeForbiddenError(w)
return
}
if len(userID) == 0 {
writeMissingDataError(w, method, "userID")
return
}
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
if err != nil {
writePayloadError(w, method, err)
return
}
var pins []string
err = json.Unmarshal(body, &pins)
if err != nil {
writePayloadError(w, method, err)
return
}
tx, err := request.Db.Beginx()
if err != nil {
writeTransactionError(w, method, err)
return
}
p.Context.Transaction = tx
for k, v := range pins {
err = p.UpdatePinSequence(v, k+1)
if err != nil {
log.IfErr(tx.Rollback())
writeGeneralSQLError(w, method, err)
return
}
}
log.IfErr(tx.Commit())
newPins, err := p.GetUserPins(userID)
if err != nil {
writeGeneralSQLError(w, method, err)
return
}
util.WriteJSON(w, newPins)
}

View file

@ -221,6 +221,12 @@ func init() {
log.IfErr(Add(RoutePrefixPrivate, "global", []string{"GET", "OPTIONS"}, nil, GetGlobalConfig))
log.IfErr(Add(RoutePrefixPrivate, "global", []string{"PUT", "OPTIONS"}, nil, SaveGlobalConfig))
// Pinned items
log.IfErr(Add(RoutePrefixPrivate, "pin/{userID}", []string{"POST", "OPTIONS"}, nil, AddPin))
log.IfErr(Add(RoutePrefixPrivate, "pin/{userID}", []string{"GET", "OPTIONS"}, nil, GetUserPins))
log.IfErr(Add(RoutePrefixPrivate, "pin/{userID}/sequence", []string{"POST", "OPTIONS"}, nil, UpdatePinSequence))
log.IfErr(Add(RoutePrefixPrivate, "pin/{userID}/{pinID}", []string{"DELETE", "OPTIONS"}, nil, DeleteUserPin))
// Single page app handler
log.IfErr(Add(RoutePrefixRoot, "robots.txt", []string{"GET", "OPTIONS"}, nil, GetRobots))
log.IfErr(Add(RoutePrefixRoot, "sitemap.xml", []string{"GET", "OPTIONS"}, nil, GetSitemap))

View file

@ -385,3 +385,14 @@ type LinkCandidate struct {
Title string `json:"title"` // what we label the link
Context string `json:"context"` // additional context (e.g. excerpt, parent, file extension)
}
// Pin defines a saved link to a document or space
type Pin struct {
BaseEntity
OrgID string `json:"orgId"`
UserID string `json:"userId"`
FolderID string `json:"folderId"`
DocumentID string `json:"documentId"`
Pin string `json:"pin"`
Sequence int `json:"sequence"`
}

View file

@ -16,13 +16,12 @@ import (
"strings"
"time"
"github.com/jmoiron/sqlx"
"github.com/documize/community/core/api/endpoint/models"
"github.com/documize/community/core/api/entity"
"github.com/documize/community/core/api/util"
"github.com/documize/community/core/log"
"github.com/documize/community/core/utility"
"github.com/jmoiron/sqlx"
)
// AddPage inserts the given page into the page table, adds that page to the queue of pages to index and audits that the page has been added.

145
core/api/request/pin.go Normal file
View file

@ -0,0 +1,145 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
package request
import (
"fmt"
"time"
"github.com/documize/community/core/api/entity"
"github.com/documize/community/core/log"
"github.com/documize/community/core/utility"
"github.com/jmoiron/sqlx"
)
// AddPin saves pinned item.
func (p *Persister) AddPin(pin entity.Pin) (err error) {
row := Db.QueryRow("SELECT max(sequence) FROM pin WHERE orgid=? AND userid=?", p.Context.OrgID, p.Context.UserID)
var maxSeq int
err = row.Scan(&maxSeq)
if err != nil {
maxSeq = 99
}
pin.Created = time.Now().UTC()
pin.Revised = time.Now().UTC()
pin.Sequence = maxSeq + 1
stmt, err := p.Context.Transaction.Preparex("INSERT INTO pin (refid, orgid, userid, labelid, documentid, pin, sequence, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)")
defer utility.Close(stmt)
if err != nil {
log.Error("Unable to prepare insert for pin", err)
return
}
_, err = stmt.Exec(pin.RefID, pin.OrgID, pin.UserID, pin.FolderID, pin.DocumentID, pin.Pin, pin.Sequence, pin.Created, pin.Revised)
if err != nil {
log.Error("Unable to execute insert for pin", err)
return
}
return
}
// GetPin returns requested pinned item.
func (p *Persister) GetPin(id string) (pin entity.Pin, err error) {
err = nil
stmt, err := Db.Preparex("SELECT id, refid, orgid, userid, labelid as folderid, documentid, pin, sequence, created, revised FROM pin WHERE orgid=? AND refid=?")
defer utility.Close(stmt)
if err != nil {
log.Error(fmt.Sprintf("Unable to prepare select for pin %s", id), err)
return
}
err = stmt.Get(&pin, p.Context.OrgID, id)
if err != nil {
log.Error(fmt.Sprintf("Unable to execute select for pin %s", id), err)
return
}
return
}
// GetUserPins returns pinned items for specified user.
func (p *Persister) GetUserPins(userID string) (pins []entity.Pin, err error) {
err = Db.Select(&pins, "SELECT id, refid, orgid, userid, labelid as folderid, documentid, pin, sequence, created, revised FROM pin WHERE orgid=? AND userid=? ORDER BY sequence", p.Context.OrgID, userID)
if err != nil {
log.Error(fmt.Sprintf("Unable to execute select pin for org %s and user %s", p.Context.OrgID, userID), err)
return
}
return
}
// UpdatePin updates existing pinned item.
func (p *Persister) UpdatePin(pin entity.Pin) (err error) {
err = nil
pin.Revised = time.Now().UTC()
var stmt *sqlx.NamedStmt
stmt, err = p.Context.Transaction.PrepareNamed("UPDATE pin SET labelid=:folderid, documentid=:documentid, pin=:pin, sequence=:sequence, revised=:revised WHERE orgid=:orgid AND refid=:refid")
defer utility.Close(stmt)
if err != nil {
log.Error(fmt.Sprintf("Unable to prepare update for pin %s", pin.RefID), err)
return
}
_, err = stmt.Exec(&pin)
if err != nil {
log.Error(fmt.Sprintf("Unable to execute update for pin %s", pin.RefID), err)
return
}
return
}
// UpdatePinSequence updates existing pinned item sequence number
func (p *Persister) UpdatePinSequence(pinID string, sequence int) (err error) {
err = nil
stmt, err := p.Context.Transaction.Preparex("UPDATE pin SET sequence=?, revised=? WHERE orgid=? AND userid=? AND refid=?")
defer utility.Close(stmt)
if err != nil {
log.Error(fmt.Sprintf("Unable to prepare update for pin sequence %s", pinID), err)
return
}
_, err = stmt.Exec(sequence, time.Now().UTC(), p.Context.OrgID, p.Context.UserID, pinID)
return
}
// DeletePin removes folder from the store.
func (p *Persister) DeletePin(id string) (rows int64, err error) {
return p.Base.DeleteConstrained(p.Context.Transaction, "pin", p.Context.OrgID, id)
}
// DeletePinnedSpace removes any pins for specified space.
func (p *Persister) DeletePinnedSpace(spaceID string) (rows int64, err error) {
return p.Base.DeleteWhere(p.Context.Transaction, fmt.Sprintf("DELETE FROM pin WHERE orgid=\"%s\" AND labelid=\"%s\"", p.Context.OrgID, spaceID))
}
// DeletePinnedDocument removes any pins for specified document.
func (p *Persister) DeletePinnedDocument(documentID string) (rows int64, err error) {
return p.Base.DeleteWhere(p.Context.Transaction, fmt.Sprintf("DELETE FROM pin WHERE orgid=\"%s\" AND documentid=\"%s\"", p.Context.OrgID, documentID))
}