1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-12-12 05:20:26 +00:00

Allow unattaching

This commit is contained in:
bouncepaw 2021-01-19 23:08:59 +05:00
parent 36ecf44a2e
commit 0341fa6440
12 changed files with 307 additions and 33 deletions

View File

@ -24,6 +24,7 @@ const (
TypeEditBinary
TypeDeleteHypha
TypeRenameHypha
TypeUnattachHypha
)
// HistoryOp is an object representing a history operation.

View File

@ -16,11 +16,65 @@ func init() {
http.HandleFunc("/edit/", handlerEdit)
http.HandleFunc("/delete-ask/", handlerDeleteAsk)
http.HandleFunc("/rename-ask/", handlerRenameAsk)
http.HandleFunc("/unattach-ask/", handlerUnattachAsk)
// And those that do mutate something:
http.HandleFunc("/upload-binary/", handlerUploadBinary)
http.HandleFunc("/upload-text/", handlerUploadText)
http.HandleFunc("/delete-confirm/", handlerDeleteConfirm)
http.HandleFunc("/rename-confirm/", handlerRenameConfirm)
http.HandleFunc("/unattach-confirm/", handlerUnattachConfirm)
}
func handlerUnattachAsk(w http.ResponseWriter, rq *http.Request) {
log.Println(rq.URL)
var (
hyphaName = HyphaNameFromRq(rq, "unattach-ask")
hd, isOld = HyphaStorage[hyphaName]
hasAmnt = hd != nil && hd.binaryPath != ""
)
if !hasAmnt {
HttpErr(w, http.StatusBadRequest, hyphaName, "Cannot unattach", "No attachment attached yet, therefore you cannot unattach")
log.Println("Rejected (no amnt):", rq.URL)
return
} else if ok := user.CanProceed(rq, "unattach-confirm"); !ok {
HttpErr(w, http.StatusForbidden, hyphaName, "Not enough rights", "You must be a trusted editor to unattach attachments")
log.Println("Rejected (no rights):", rq.URL)
return
}
util.HTTP200Page(w, base("Unattach "+hyphaName+"?", templates.UnattachAskHTML(rq, hyphaName, isOld)))
}
func handlerUnattachConfirm(w http.ResponseWriter, rq *http.Request) {
log.Println(rq.URL)
var (
hyphaName = HyphaNameFromRq(rq, "unattach-confirm")
hyphaData, isOld = HyphaStorage[hyphaName]
hasAmnt = hyphaData != nil && hyphaData.binaryPath != ""
u = user.FromRequest(rq)
)
if !u.CanProceed("unattach-confirm") {
HttpErr(w, http.StatusForbidden, hyphaName, "Not enough rights", "You must be a trusted editor to unattach attachments")
log.Println("Rejected (no rights):", rq.URL)
return
}
if !hasAmnt {
HttpErr(w, http.StatusBadRequest, hyphaName, "Cannot unattach", "No attachment attached yet, therefore you cannot unattach")
log.Println("Rejected (no amnt):", rq.URL)
return
} else if !isOld {
// The precondition is to have the hypha in the first place.
HttpErr(w, http.StatusPreconditionFailed, hyphaName,
"Error: no such hypha",
"Could not unattach this hypha because it does not exist")
return
}
if hop := hyphaData.UnattachHypha(hyphaName, u); len(hop.Errs) != 0 {
HttpErr(w, http.StatusInternalServerError, hyphaName,
"Error: could not unattach hypha",
fmt.Sprintf("Could not unattach this hypha due to internal errors. Server errors: <code>%v</code>", hop.Errs))
return
}
http.Redirect(w, rq, "/page/"+hyphaName, http.StatusSeeOther)
}
func handlerRenameAsk(w http.ResponseWriter, rq *http.Request) {

View File

@ -80,6 +80,7 @@ func handlerPage(w http.ResponseWriter, rq *http.Request) {
var (
hyphaName = HyphaNameFromRq(rq, "page")
data, hyphaExists = HyphaStorage[hyphaName]
hasAmnt = hyphaExists && data.binaryPath != ""
contents string
openGraph string
)
@ -102,6 +103,7 @@ func handlerPage(w http.ResponseWriter, rq *http.Request) {
templates.PageHTML(rq, hyphaName,
naviTitle(hyphaName),
contents,
treeHTML, prevHypha, nextHypha),
treeHTML, prevHypha, nextHypha,
hasAmnt),
openGraph))
}

View File

@ -128,6 +128,29 @@ func (hd *HyphaData) DeleteHypha(hyphaName string, u *user.User) *history.Histor
return hop
}
// UnattachHypha unattaches hypha and makes a history record about that.
func (hd *HyphaData) UnattachHypha(hyphaName string, u *user.User) *history.HistoryOp {
hop := history.Operation(history.TypeUnattachHypha).
WithFilesRemoved(hd.binaryPath).
WithMsg(fmt.Sprintf("Unattach %s", hyphaName)).
WithUser(u).
Apply()
if len(hop.Errs) == 0 {
hd, ok := HyphaStorage[hyphaName]
if ok {
if hd.binaryPath != "" {
hd.binaryPath = ""
}
// If nothing is left of the hypha
if hd.textPath == "" {
delete(HyphaStorage, hyphaName)
hyphae.DecrementCount()
}
}
}
return hop
}
func findHyphaeToRename(hyphaName string, recursive bool) []string {
hyphae := []string{hyphaName}
if recursive {

View File

@ -154,7 +154,7 @@ func main() {
history.Start(WikiDir)
// See http_readers.go for /page/, /text/, /binary/
// See http_mutators.go for /upload-binary/, /upload-text/, /edit/, /delete-ask/, /delete-confirm/, /rename-ask/, /rename-confirm/
// See http_mutators.go for /upload-binary/, /upload-text/, /edit/, /delete-ask/, /delete-confirm/, /rename-ask/, /rename-confirm/, /unattach-ask/, /unattach-confirm/
// See http_auth.go for /login, /login-data, /logout, /logout-confirm
// See http_history.go for /history/, /recent-changes
http.HandleFunc("/list", handlerList)

View File

@ -72,6 +72,7 @@ article pre.codeblock { padding:.5rem; white-space: pre-wrap; border-radius: .25
.navi-title__separator { margin: 0 .25rem; }
.navi-title__colon { margin-right: .5rem; }
.upload-amnt { clear: both; padding: .5rem; border-radius: .25rem; }
.upload-amnt__unattach { display: block; }
aside { clear: both; }
.img-gallery { text-align: center; margin-top: .25rem; margin-bottom: .25rem; }

View File

@ -47,6 +47,7 @@ article pre.codeblock { padding:.5rem; white-space: pre-wrap; border-radius: .25
.navi-title__separator { margin: 0 .25rem; }
.navi-title__colon { margin-right: .5rem; }
.upload-amnt { clear: both; padding: .5rem; border-radius: .25rem; }
.upload-amnt__unattach { display: block; }
aside { clear: both; }
.img-gallery { text-align: center; margin-top: .25rem; margin-bottom: .25rem; }

View File

@ -28,7 +28,7 @@
{% endfunc %}
If `contents` == "", a helpful message is shown instead.
{% func PageHTML(rq *http.Request, hyphaName, naviTitle, contents, tree, prevHyphaName, nextHyphaName string) %}
{% func PageHTML(rq *http.Request, hyphaName, naviTitle, contents, tree, prevHyphaName, nextHyphaName string, hasAmnt bool) %}
<main>
{%= navHTML(rq, hyphaName, "page") %}
<article>
@ -51,6 +51,9 @@ If `contents` == "", a helpful message is shown instead.
<form action="/upload-binary/{%s hyphaName %}"
method="post" enctype="multipart/form-data"
class="upload-amnt">
{% if hasAmnt %}
<a class="upload-amnt__unattach" href="/unattach-ask/{%s hyphaName %}">Unattach current attachment?</a>
{% endif %}
<label for="upload-binary__input">Upload a new attachment</label>
<br>
<input type="file" id="upload-binary__input" name="binary"/>

View File

@ -144,7 +144,7 @@ func RevisionHTML(rq *http.Request, hyphaName, naviTitle, contents, tree, revHas
// If `contents` == "", a helpful message is shown instead.
//line templates/http_readers.qtpl:31
func StreamPageHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, naviTitle, contents, tree, prevHyphaName, nextHyphaName string) {
func StreamPageHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, naviTitle, contents, tree, prevHyphaName, nextHyphaName string, hasAmnt bool) {
//line templates/http_readers.qtpl:31
qw422016.N().S(`
<main>
@ -237,50 +237,65 @@ func StreamPageHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, navi
qw422016.N().S(`"
method="post" enctype="multipart/form-data"
class="upload-amnt">
`)
//line templates/http_readers.qtpl:54
if hasAmnt {
//line templates/http_readers.qtpl:54
qw422016.N().S(`
<a class="upload-amnt__unattach" href="/unattach-ask/`)
//line templates/http_readers.qtpl:55
qw422016.E().S(hyphaName)
//line templates/http_readers.qtpl:55
qw422016.N().S(`">Unattach current attachment?</a>
`)
//line templates/http_readers.qtpl:56
}
//line templates/http_readers.qtpl:56
qw422016.N().S(`
<label for="upload-binary__input">Upload a new attachment</label>
<br>
<input type="file" id="upload-binary__input" name="binary"/>
<input type="submit"/>
</form>
`)
//line templates/http_readers.qtpl:59
//line templates/http_readers.qtpl:62
}
//line templates/http_readers.qtpl:59
//line templates/http_readers.qtpl:62
qw422016.N().S(`
<aside>
`)
//line templates/http_readers.qtpl:61
//line templates/http_readers.qtpl:64
qw422016.N().S(tree)
//line templates/http_readers.qtpl:61
//line templates/http_readers.qtpl:64
qw422016.N().S(`
</aside>
</main>
`)
//line templates/http_readers.qtpl:64
//line templates/http_readers.qtpl:67
}
//line templates/http_readers.qtpl:64
func WritePageHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, naviTitle, contents, tree, prevHyphaName, nextHyphaName string) {
//line templates/http_readers.qtpl:64
//line templates/http_readers.qtpl:67
func WritePageHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, naviTitle, contents, tree, prevHyphaName, nextHyphaName string, hasAmnt bool) {
//line templates/http_readers.qtpl:67
qw422016 := qt422016.AcquireWriter(qq422016)
//line templates/http_readers.qtpl:64
StreamPageHTML(qw422016, rq, hyphaName, naviTitle, contents, tree, prevHyphaName, nextHyphaName)
//line templates/http_readers.qtpl:64
//line templates/http_readers.qtpl:67
StreamPageHTML(qw422016, rq, hyphaName, naviTitle, contents, tree, prevHyphaName, nextHyphaName, hasAmnt)
//line templates/http_readers.qtpl:67
qt422016.ReleaseWriter(qw422016)
//line templates/http_readers.qtpl:64
//line templates/http_readers.qtpl:67
}
//line templates/http_readers.qtpl:64
func PageHTML(rq *http.Request, hyphaName, naviTitle, contents, tree, prevHyphaName, nextHyphaName string) string {
//line templates/http_readers.qtpl:64
//line templates/http_readers.qtpl:67
func PageHTML(rq *http.Request, hyphaName, naviTitle, contents, tree, prevHyphaName, nextHyphaName string, hasAmnt bool) string {
//line templates/http_readers.qtpl:67
qb422016 := qt422016.AcquireByteBuffer()
//line templates/http_readers.qtpl:64
WritePageHTML(qb422016, rq, hyphaName, naviTitle, contents, tree, prevHyphaName, nextHyphaName)
//line templates/http_readers.qtpl:64
//line templates/http_readers.qtpl:67
WritePageHTML(qb422016, rq, hyphaName, naviTitle, contents, tree, prevHyphaName, nextHyphaName, hasAmnt)
//line templates/http_readers.qtpl:67
qs422016 := string(qb422016.B)
//line templates/http_readers.qtpl:64
//line templates/http_readers.qtpl:67
qt422016.ReleaseByteBuffer(qb422016)
//line templates/http_readers.qtpl:64
//line templates/http_readers.qtpl:67
return qs422016
//line templates/http_readers.qtpl:64
//line templates/http_readers.qtpl:67
}

24
templates/unattach.qtpl Normal file
View File

@ -0,0 +1,24 @@
{% import "net/http" %}
{% func UnattachAskHTML(rq *http.Request, hyphaName string, isOld bool) %}
<main>
{%= navHTML(rq, hyphaName, "unattach-ask") %}
{%- if isOld -%}
<section>
<h1>Unattach {%s hyphaName %}?</h1>
<p>Do you really want to unattach hypha <em>{%s hyphaName %}</em>?</p>
<p><a href="/unattach-confirm/{%s hyphaName %}"><strong>Confirm</strong></a></p>
<p><a href="/page/{%s hyphaName %}">Cancel</a></p>
</section>
{%- else -%}
{%= cannotUnattachDueToNonExistence(hyphaName) %}
{%- endif -%}
</main>
{% endfunc %}
{% func cannotUnattachDueToNonExistence(hyphaName string) %}
<section>
<h1>Cannot unattach {%s hyphaName %}</h1>
<p>This hypha does not exist.</p>
<p><a href="/page/{%s hyphaName %}">Go back</a></p>
</section>
{% endfunc %}

148
templates/unattach.qtpl.go Normal file
View File

@ -0,0 +1,148 @@
// Code generated by qtc from "unattach.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
//line templates/unattach.qtpl:1
package templates
//line templates/unattach.qtpl:1
import "net/http"
//line templates/unattach.qtpl:2
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line templates/unattach.qtpl:2
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line templates/unattach.qtpl:2
func StreamUnattachAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
//line templates/unattach.qtpl:2
qw422016.N().S(`
<main>
`)
//line templates/unattach.qtpl:4
streamnavHTML(qw422016, rq, hyphaName, "unattach-ask")
//line templates/unattach.qtpl:4
qw422016.N().S(`
`)
//line templates/unattach.qtpl:5
if isOld {
//line templates/unattach.qtpl:5
qw422016.N().S(` <section>
<h1>Unattach `)
//line templates/unattach.qtpl:7
qw422016.E().S(hyphaName)
//line templates/unattach.qtpl:7
qw422016.N().S(`?</h1>
<p>Do you really want to unattach hypha <em>`)
//line templates/unattach.qtpl:8
qw422016.E().S(hyphaName)
//line templates/unattach.qtpl:8
qw422016.N().S(`</em>?</p>
<p><a href="/unattach-confirm/`)
//line templates/unattach.qtpl:9
qw422016.E().S(hyphaName)
//line templates/unattach.qtpl:9
qw422016.N().S(`"><strong>Confirm</strong></a></p>
<p><a href="/page/`)
//line templates/unattach.qtpl:10
qw422016.E().S(hyphaName)
//line templates/unattach.qtpl:10
qw422016.N().S(`">Cancel</a></p>
</section>
`)
//line templates/unattach.qtpl:12
} else {
//line templates/unattach.qtpl:12
qw422016.N().S(` `)
//line templates/unattach.qtpl:13
streamcannotUnattachDueToNonExistence(qw422016, hyphaName)
//line templates/unattach.qtpl:13
qw422016.N().S(`
`)
//line templates/unattach.qtpl:14
}
//line templates/unattach.qtpl:14
qw422016.N().S(`</main>
`)
//line templates/unattach.qtpl:16
}
//line templates/unattach.qtpl:16
func WriteUnattachAskHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
//line templates/unattach.qtpl:16
qw422016 := qt422016.AcquireWriter(qq422016)
//line templates/unattach.qtpl:16
StreamUnattachAskHTML(qw422016, rq, hyphaName, isOld)
//line templates/unattach.qtpl:16
qt422016.ReleaseWriter(qw422016)
//line templates/unattach.qtpl:16
}
//line templates/unattach.qtpl:16
func UnattachAskHTML(rq *http.Request, hyphaName string, isOld bool) string {
//line templates/unattach.qtpl:16
qb422016 := qt422016.AcquireByteBuffer()
//line templates/unattach.qtpl:16
WriteUnattachAskHTML(qb422016, rq, hyphaName, isOld)
//line templates/unattach.qtpl:16
qs422016 := string(qb422016.B)
//line templates/unattach.qtpl:16
qt422016.ReleaseByteBuffer(qb422016)
//line templates/unattach.qtpl:16
return qs422016
//line templates/unattach.qtpl:16
}
//line templates/unattach.qtpl:18
func streamcannotUnattachDueToNonExistence(qw422016 *qt422016.Writer, hyphaName string) {
//line templates/unattach.qtpl:18
qw422016.N().S(`
<section>
<h1>Cannot unattach `)
//line templates/unattach.qtpl:20
qw422016.E().S(hyphaName)
//line templates/unattach.qtpl:20
qw422016.N().S(`</h1>
<p>This hypha does not exist.</p>
<p><a href="/page/`)
//line templates/unattach.qtpl:22
qw422016.E().S(hyphaName)
//line templates/unattach.qtpl:22
qw422016.N().S(`">Go back</a></p>
</section>
`)
//line templates/unattach.qtpl:24
}
//line templates/unattach.qtpl:24
func writecannotUnattachDueToNonExistence(qq422016 qtio422016.Writer, hyphaName string) {
//line templates/unattach.qtpl:24
qw422016 := qt422016.AcquireWriter(qq422016)
//line templates/unattach.qtpl:24
streamcannotUnattachDueToNonExistence(qw422016, hyphaName)
//line templates/unattach.qtpl:24
qt422016.ReleaseWriter(qw422016)
//line templates/unattach.qtpl:24
}
//line templates/unattach.qtpl:24
func cannotUnattachDueToNonExistence(hyphaName string) string {
//line templates/unattach.qtpl:24
qb422016 := qt422016.AcquireByteBuffer()
//line templates/unattach.qtpl:24
writecannotUnattachDueToNonExistence(qb422016, hyphaName)
//line templates/unattach.qtpl:24
qs422016 := string(qb422016.B)
//line templates/unattach.qtpl:24
qt422016.ReleaseByteBuffer(qb422016)
//line templates/unattach.qtpl:24
return qs422016
//line templates/unattach.qtpl:24
}

View File

@ -15,14 +15,16 @@ type User struct {
// Route — Right (more is more right)
var minimalRights = map[string]int{
"edit": 1,
"upload-binary": 1,
"upload-text": 1,
"rename-ask": 2,
"rename-confirm": 2,
"delete-ask": 3,
"delete-confirm": 3,
"reindex": 4,
"edit": 1,
"upload-binary": 1,
"upload-text": 1,
"rename-ask": 2,
"rename-confirm": 2,
"unattach-ask": 2,
"unattach-confirm": 2,
"delete-ask": 3,
"delete-confirm": 3,
"reindex": 4,
}
// Group — Right