mirror of https://github.com/mikkolehtisalo/iw.git
267 lines
8.3 KiB
Go
267 lines
8.3 KiB
Go
package models
|
|
|
|
import (
|
|
"time"
|
|
"github.com/revel/revel"
|
|
"github.com/mikkolehtisalo/revel/acl"
|
|
"regexp"
|
|
"html"
|
|
"strings"
|
|
"fmt"
|
|
//. "github.com/mikkolehtisalo/revel/common"
|
|
)
|
|
|
|
type Page struct {
|
|
Page_id string
|
|
Wiki_id string
|
|
Path string
|
|
Title string
|
|
Create_user string
|
|
Readacl string
|
|
Writeacl string
|
|
Adminacl string
|
|
Stopinheritation bool
|
|
Index int
|
|
Depth int
|
|
Status string
|
|
Modified time.Time
|
|
MatchedPermissions []string
|
|
Loaded bool `json:"loaded"`
|
|
}
|
|
|
|
// Sets modified time
|
|
// Updates depth automatically
|
|
func (p *Page) Save(save_activity bool) {
|
|
revel.TRACE.Printf("Page Save(): %+v", p)
|
|
db := get_db()
|
|
defer db.Close()
|
|
|
|
// Update depth
|
|
update_depth(p)
|
|
p.Modified = time.Now()
|
|
|
|
_, err := db.Exec("insert into pages(page_id, wiki_id, path, title, create_user, readacl, writeacl, adminacl, stopinheritation, index, depth, modified, status) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)",
|
|
p.Page_id, p.Wiki_id, p.Path, p.Title, p.Create_user, p.Readacl, p.Writeacl, p.Adminacl, p.Stopinheritation, p.Index, p.Depth, p.Modified, p.Status )
|
|
|
|
if err != nil {
|
|
revel.ERROR.Printf("Page Save(): failed with %+v", err)
|
|
}
|
|
|
|
if save_activity {
|
|
SaveActivity(p)
|
|
}
|
|
}
|
|
|
|
// Wiki id, one page id, path
|
|
// The pages in path must either exist in database or match given single id (in case target is not already in database)
|
|
func valid_path(w string, me string, p string) bool {
|
|
valid := true
|
|
split_path := strings.Split(p, "/")
|
|
|
|
for _, part := range split_path {
|
|
x := GetPage(w, part)
|
|
if part != me && x.Page_id != part {
|
|
valid = false
|
|
}
|
|
}
|
|
|
|
return valid
|
|
}
|
|
|
|
func (p *Page) Validate(v *revel.Validation) {
|
|
// Required fields
|
|
v.Required(p.Page_id)
|
|
v.Required(p.Wiki_id)
|
|
v.Required(p.Path)
|
|
v.Required(p.Title)
|
|
|
|
// Match against regexp patterns
|
|
v.Match(p.Wiki_id, regexp.MustCompile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")).Message("Wiki_id not UUID?")
|
|
v.Match(p.Page_id, regexp.MustCompile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")).Message("Page_id not UUID?")
|
|
|
|
// Escape HTML from the fields that might be rendered to users
|
|
p.Title = html.EscapeString(p.Title)
|
|
|
|
// Validate Path
|
|
v.Required(valid_path(p.Wiki_id, p.Page_id, p.Path)).Message(fmt.Sprintf("Path is probably invalid: %+v", p.Path))
|
|
}
|
|
|
|
func has_children(page Page) bool {
|
|
result := false
|
|
pages := Get_children(page)
|
|
if len(pages) > 0 {
|
|
result = true
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// Only the next level
|
|
func Get_children(page Page) []Page {
|
|
revel.TRACE.Printf("Page Get_children(): %+v", page)
|
|
pages := []Page{}
|
|
db := get_db()
|
|
defer db.Close()
|
|
|
|
path := page.Path + "/%"
|
|
db.Select(&pages, "select * from pages p1 where p1.status='ACTIVE' and not exists (select * from pages p2 where p1.wiki_id=p2.wiki_id and p1.page_id=p2.page_id and p2.modified>p1.modified) and p1.path like $1 and p1.depth=$2 order by index", path, page.Depth + 1)
|
|
|
|
return pages
|
|
}
|
|
|
|
// Used only from Wiki.Delete()
|
|
func DeletePages(wiki string, user string) {
|
|
revel.TRACE.Printf("Page DeletePages(): wiki %+v, user %+v", wiki, user)
|
|
pages := []Page{}
|
|
db := get_db()
|
|
defer db.Close()
|
|
|
|
db.Select(&pages, "select * from pages p1 where p1.status='ACTIVE' and p1.wiki_id=uuid_in($1) and not exists (select * from pages p2 where p1.wiki_id=p2.wiki_id and p1.page_id=p2.page_id and p2.modified>p1.modified)",
|
|
wiki)
|
|
|
|
for _, page := range pages {
|
|
DeletePage(wiki, page.Page_id, user, false)
|
|
}
|
|
}
|
|
|
|
func ListPages(wiki_id string, node string) []Page {
|
|
revel.TRACE.Printf("ListPages() wiki_id: %+v, node: %+v", wiki_id, node)
|
|
pages := []Page{}
|
|
db := get_db()
|
|
defer db.Close()
|
|
|
|
if len(node) > 0 {
|
|
// Get the parent, and find what's under it - if anything
|
|
p := GetPage(wiki_id, node)
|
|
path := p.Path + "/%"
|
|
depth := p.Depth + 1
|
|
db.Select(&pages, "select * from pages p1 where p1.status='ACTIVE' and not exists (select * from pages p2 where p1.wiki_id=p2.wiki_id and p1.page_id=p2.page_id and p2.modified>p1.modified) and p1.path like $1 and p1.depth=$2", path, depth)
|
|
} else {
|
|
db.Select(&pages, "select * from pages p1 where p1.status='ACTIVE' and p1.wiki_id=uuid_in($1) and p1.depth=0 and not exists (select * from pages p2 where p1.wiki_id=p2.wiki_id and p1.page_id=p2.page_id and p2.modified>p1.modified)", wiki_id)
|
|
}
|
|
|
|
// Update children status
|
|
for x, _ := range pages {
|
|
pages[x].Loaded = !has_children(pages[x])
|
|
revel.TRACE.Printf("Page %+v children: %+v", pages[x], has_children(pages[x]))
|
|
}
|
|
|
|
revel.TRACE.Printf("ListPages returning %+v", pages)
|
|
return pages
|
|
}
|
|
|
|
func DeletePage(wiki_id string, page_id string, user string, save_activity bool) {
|
|
revel.TRACE.Printf("DeletePage() wiki: %+v, page: %+v, user: %+v", wiki_id, page_id, user)
|
|
|
|
page := GetPage(wiki_id, page_id)
|
|
pages := Get_children(page)
|
|
// For looping
|
|
pages = append(pages, page)
|
|
|
|
for _, p := range pages {
|
|
if p.Wiki_id != "" {
|
|
p.Status = "DELETED"
|
|
p.Create_user = user
|
|
p.Save(save_activity)
|
|
|
|
// Delete ContentField too
|
|
cf := GetContent(p.Wiki_id, p.Page_id, nil)
|
|
cf.Status = "DELETED"
|
|
cf.Create_user = user
|
|
cf.Save(save_activity)
|
|
}
|
|
}
|
|
}
|
|
|
|
func GetPage(wiki_id string, page_id string) Page {
|
|
revel.TRACE.Printf("Page GetPage(): page: %+v wiki: %+v", page_id, wiki_id)
|
|
pages := []Page{}
|
|
page := Page{}
|
|
db := get_db()
|
|
defer db.Close()
|
|
|
|
db.Select(&pages, "select * from pages p1 where p1.wiki_id=uuid_in($1) and p1.page_id=uuid_in($2) and p1.status='ACTIVE' and not exists (select * from pages p2 where p1.wiki_id=p2.wiki_id and p1.page_id=p2.page_id and p2.modified>p1.modified)",
|
|
wiki_id, page_id)
|
|
if len(pages)>0 {
|
|
page = pages[0]
|
|
}
|
|
return page
|
|
}
|
|
|
|
func GetPageAllStatuses(wiki_id string, page_id string) Page {
|
|
revel.TRACE.Printf("Page GetPageAllStatuses(): page: %+v wiki: %+v", page_id, wiki_id)
|
|
pages := []Page{}
|
|
page := Page{}
|
|
db := get_db()
|
|
defer db.Close()
|
|
|
|
db.Select(&pages, "select * from pages p1 where p1.wiki_id=uuid_in($1) and p1.page_id=uuid_in($2) and not exists (select * from pages p2 where p1.wiki_id=p2.wiki_id and p1.page_id=p2.page_id and p2.modified>p1.modified)",
|
|
wiki_id, page_id)
|
|
if len(pages)>0 {
|
|
page = pages[0]
|
|
}
|
|
return page
|
|
}
|
|
|
|
func update_depth(page *Page) {
|
|
split := strings.Split(page.Path, "/")
|
|
page.Depth = len(split) - 1
|
|
}
|
|
|
|
// ACL stuff
|
|
|
|
// Build ACL entry for reference
|
|
func (p Page) BuildACLEntry(reference string) acl.ACLEntry {
|
|
revel.TRACE.Printf("BuildACLEntry() %+v", reference)
|
|
var entry acl.ACLEntry
|
|
|
|
if reference != ("page:"+p.Wiki_id+"/"+p.Page_id) {
|
|
if strings.Index(reference, "page") == 0 {
|
|
// We are not working on this copy, get from database
|
|
re := regexp.MustCompile("page:([^/]*)/(.*)")
|
|
m := re.FindStringSubmatch(reference)
|
|
wref := m[1]
|
|
pref := m[2]
|
|
pa := GetPage(wref, pref)
|
|
entry = entry_helper(pa.Readacl, pa.Writeacl, pa.Adminacl, reference, pa)
|
|
} else {
|
|
// This must be wiki!
|
|
re := regexp.MustCompile("wiki:(.*)")
|
|
ref := re.FindStringSubmatch(reference)[1]
|
|
wi := GetWiki(ref)
|
|
entry = entry_helper(wi.Readacl, wi.Writeacl, wi.Adminacl, reference, wi)
|
|
}
|
|
} else {
|
|
// It's exactly the originating item!
|
|
entry = entry_helper(p.Readacl, p.Writeacl, p.Adminacl, reference, p)
|
|
}
|
|
|
|
return entry
|
|
}
|
|
|
|
// Set the matched permissions to a variable
|
|
func (p Page) SetMatched(permissions []string) interface{} {
|
|
p.MatchedPermissions = permissions
|
|
return p
|
|
}
|
|
|
|
// Building parent information
|
|
func (p Page) BuildACLParent() string {
|
|
if p.Depth==0 {
|
|
return "wiki:"+p.Wiki_id
|
|
} else {
|
|
pslice := strings.Split(p.Path, "/")
|
|
return "page:"+p.Wiki_id + "/" + pslice[len(pslice)-2]
|
|
}
|
|
}
|
|
|
|
// Wiki+page ids...
|
|
func (p Page) BuildACLReference() string {
|
|
return "page:"+p.Wiki_id+"/"+p.Page_id
|
|
}
|
|
|
|
// Set on data
|
|
func (p Page) BuildACLInheritation() bool {
|
|
return !p.Stopinheritation
|
|
}
|