diff --git a/.vscode/launch.json b/.vscode/launch.json index be81ca1..79982f5 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -17,7 +17,7 @@ "request": "launch", "mode": "auto", "program": "${workspaceFolder}", - "args": ["-C", "${workspaceFolder}/test.yaml", "--buggy-attachments"] + "args": ["-C", "${workspaceFolder}/test.yaml"] }, ] } diff --git a/conference_ops.go b/conference_ops.go index d603170..fca36e7 100644 --- a/conference_ops.go +++ b/conference_ops.go @@ -107,7 +107,24 @@ func AttachmentSend(ctxt ui.AmContext) (string, any) { } else if info == nil { return "error", echo.NewHTTPError(http.StatusNotFound, "attachment not found") } - data, err := hdr.AttachmentData(ctxt.Ctx(), config.CommandLine.BuggyAttachments) + + // Do we need the buggy-attachment workaround? If it's not selected on the command line, check the + // conference flags, which means we need to get the containing conference. + bugWorkaround := config.CommandLine.BuggyAttachments + if !bugWorkaround { + conf, err := database.AmGetConferenceContainingPost(ctxt.Ctx(), postId) + if err == nil { + flg, err := conf.Flags(ctxt.Ctx()) + if err == nil { + bugWorkaround = flg.Get(database.ConferenceFlagBuggyAttachments) + } + } + if err != nil { + return "error", err + } + } + + data, err := hdr.AttachmentData(ctxt.Ctx(), bugWorkaround) if err != nil { return "error", err } diff --git a/conferenceadmin.go b/conferenceadmin.go index ed8e5cb..1628ab3 100644 --- a/conferenceadmin.go +++ b/conferenceadmin.go @@ -72,6 +72,7 @@ func EditConferenceForm(ctxt ui.AmContext) (string, any) { return "error", err } dlg.Field("pic_in_post").SetChecked(flags.Get(database.ConferenceFlagPicturesInPosts)) + dlg.Field("bugattach").SetChecked(flags.Get(database.ConferenceFlagBuggyAttachments)) return dlg.Render(ctxt) } @@ -113,6 +114,7 @@ func EditConference(ctxt ui.AmContext) (string, any) { flags, err = conf.Flags(ctxt.Ctx()) if err == nil { flags.Set(database.ConferenceFlagPicturesInPosts, dlg.Field("pic_in_post").IsChecked()) + flags.Set(database.ConferenceFlagBuggyAttachments, dlg.Field("bugattach").IsChecked()) err = conf.SaveFlags(ctxt.Ctx(), flags) } } @@ -711,12 +713,22 @@ func ConferenceExport(ctxt ui.AmContext) (string, any) { } } + // Get the value of the "bug workaround" flag. If not from the command line, then from the conference flags. + bugWorkaround := config.CommandLine.BuggyAttachments + if !bugWorkaround { + flg, err := conf.Flags(ctxt.Ctx()) + if err != nil { + return "error", err + } + bugWorkaround = flg.Get(database.ConferenceFlagBuggyAttachments) + } + // The tricky bit! We use a dedicated goroutine to generate the streamed output and send it to the inlet end of a pipe. filename := time.Now().Format("exported-data-20060102.xml") r, w := io.Pipe() go func() { start := time.Now() - err := exports.VCIFStreamTopicFile(context.Background(), w, topics, config.CommandLine.BuggyAttachments) + err := exports.VCIFStreamTopicFile(context.Background(), w, topics, bugWorkaround) if err != nil { log.Errorf("ConferenceExport task failed with %v", err) s := fmt.Sprintf("\r\n", err) diff --git a/database/conference.go b/database/conference.go index b3db49c..1b52643 100644 --- a/database/conference.go +++ b/database/conference.go @@ -98,7 +98,8 @@ const ( // Flag values for conference property index ConferencePropFlags defined. const ( - ConferenceFlagPicturesInPosts = uint(0) + ConferenceFlagPicturesInPosts = uint(0) // show pictures in posts + ConferenceFlagBuggyAttachments = uint(1) // buggy attachment behavior ) // conferenceCache is the cache for Conference objects. @@ -993,6 +994,26 @@ func AmGetConferenceByAlias(ctx context.Context, alias string) (*Conference, err return AmGetConference(ctx, confid) } +/* AmGetConferenceContainingPost looks up a post ID and returns the conference containing it. + * Parameters: + * ctx - Standard Go context value. + * postId - The post ID to look up. + * Returns: + * Pointer to the conference, or nil. + * Standard Go error status. + */ +func AmGetConferenceContainingPost(ctx context.Context, postId int64) (*Conference, error) { + row := amdb.QueryRowContext(ctx, "SELECT t.confid FROM topics t, posts p WHERE p.postid = ? AND p.topicid = t.topicid", postId) + var confId int32 + err := row.Scan(&confId) + if err == sql.ErrNoRows { + return nil, fmt.Errorf("post not found: %d", postId) + } else if err != nil { + return nil, err + } + return AmGetConference(ctx, confId) +} + /* AmGetConferenceByAliasInCommunity returns a conference in a community given its alias. * Parameters: * ctx - Standard Go context value. diff --git a/docs/MISSINGFUNCS.md b/docs/MISSINGFUNCS.md index 8a65484..4daf0ec 100644 --- a/docs/MISSINGFUNCS.md +++ b/docs/MISSINGFUNCS.md @@ -72,6 +72,7 @@ _(italicized items can be deferred)_ - Import Messages - ~~Delete Conference~~ - ~~Add to Hotlist/Remove from Hotlist~~ +- Actually implement pictures in posts - Related to bugs in Export Messages caused by bad data: - - Provide a per-conference flag that will set BuggyAttachment behavior + - ~~Provide a per-conference flag that will set BuggyAttachment behavior~~ - New feature: remove attachment from message (requires Conference.Nuke permission) diff --git a/ui/dialogs/edit_conference.yaml b/ui/dialogs/edit_conference.yaml index 9e034b6..829b666 100644 --- a/ui/dialogs/edit_conference.yaml +++ b/ui/dialogs/edit_conference.yaml @@ -78,6 +78,10 @@ fields: name: "pic_in_post" caption: "Display users' pictures next to their posts" subcaption: "(user can override)" + - type: "checkbox" + name: "bugattach" + caption: "Buggy attachment behavior" + subcaption: "(only used for legacy data)" - type: "button" name: "update" caption: "Update" diff --git a/ui/render_wrap.go b/ui/render_wrap.go index 27cf86a..87bbaa8 100644 --- a/ui/render_wrap.go +++ b/ui/render_wrap.go @@ -27,11 +27,15 @@ import ( * amctxt - The associated AmContext. * command - The type of rendering to be done. Known values are: * "bytes" - Output "data" as a byte array. - * "redirect" - Treat "data" as a URL to be redirected to and send a 302 Redirect. - * "string" - Output "data" as a string. - * "template" - Treat "data" as a template name, and output that template. + * "error" - Output the error rendering page. * "framed" - Treat "data" as an inner template name, and output that template rendered * within the outer "frame.jet" template. + * "ipban" - Output the IP address ban rendering page. + * "nocontent" - Output a 204 No Content response. + * "redirect" - Treat "data" as a URL to be redirected to and send a 302 Redirect. + * "stream" - Treat "data" as an io.Reader and use it to stream data. + * "string" - Output "data" as a string. + * "template" - Treat "data" as a template name, and output that template. * data - The data to be output, as determined by the command. * Returns: * Standard Go error status.