Add post format selection
authorr <r@freesoftwareextremist.com>
Thu, 26 Dec 2019 11:25:29 +0000 (11:25 +0000)
committerr <r@freesoftwareextremist.com>
Thu, 26 Dec 2019 11:25:29 +0000 (11:25 +0000)
config/config.go
default.conf
main.go
mastodon/mastodon.go
mastodon/status.go
model/postContext.go
service/auth.go
service/logging.go
service/service.go
service/transport.go
templates/postform.tmpl

index 17fcecac0bca7426531c566e272ef21663db6c47..c463c9115cfc5926c0b79a8454f9bcd76c1beb87 100644 (file)
@@ -6,6 +6,7 @@ import (
        "io"
        "os"
        "strings"
+       "web/model"
 )
 
 type config struct {
@@ -17,6 +18,7 @@ type config struct {
        TemplatesGlobPattern string
        DatabasePath         string
        CustomCSS            string
+       PostFormats          []model.PostFormat
        Logfile              string
 }
 
@@ -43,7 +45,13 @@ func getDefaultConfig() *config {
                TemplatesGlobPattern: "templates/*",
                DatabasePath:         "database.db",
                CustomCSS:            "",
-               Logfile:              "",
+               PostFormats: []model.PostFormat{
+                       model.PostFormat{"Plain Text", "text/plain"},
+                       model.PostFormat{"HTML", "text/html"},
+                       model.PostFormat{"Markdown", "text/markdown"},
+                       model.PostFormat{"BBCode", "text/bbcode"},
+               },
+               Logfile: "",
        }
 }
 
@@ -87,6 +95,25 @@ func Parse(r io.Reader) (c *config, err error) {
                        c.DatabasePath = val
                case "custom_css":
                        c.CustomCSS = val
+               case "post_formats":
+                       vals := strings.Split(val, ",")
+                       var formats []model.PostFormat
+                       for _, v := range vals {
+                               pair := strings.Split(v, ":")
+                               if len(pair) != 2 {
+                                       return nil, errors.New("invalid config key " + key)
+                               }
+                               n := strings.TrimSpace(pair[0])
+                               t := strings.TrimSpace(pair[1])
+                               if len(n) < 1 || len(t) < 1 {
+                                       return nil, errors.New("invalid config key " + key)
+                               }
+                               formats = append(formats, model.PostFormat{
+                                       Name: n,
+                                       Type: t,
+                               })
+                       }
+                       c.PostFormats = formats
                case "logfile":
                        c.Logfile = val
                default:
index eede82b8453921488919677730368457b57cd2b1..81ed26a8e320afdfefd0693c2ed5746e928ce6f0 100644 (file)
@@ -5,4 +5,5 @@ client_website=http://localhost:8080
 static_directory=static
 templates_glob_pattern=templates/*
 #custom_css=custom.css
+#post_formats=PlainText:text/plain,HTML:text/html,Markdown:text/markdown,BBCode:text/bbcode
 database_path=database
diff --git a/main.go b/main.go
index f9fdc8f3160a1342cbe133e85e2b5ab51614c902..e29f53aeff4ca8d996c02f100cd7d0c834390405 100644 (file)
--- a/main.go
+++ b/main.go
@@ -71,7 +71,8 @@ func main() {
                logger = log.New(lf, "", log.LstdFlags)
        }
 
-       s := service.NewService(config.ClientName, config.ClientScope, config.ClientWebsite, customCSS, renderer, sessionRepo, appRepo)
+       s := service.NewService(config.ClientName, config.ClientScope, config.ClientWebsite,
+               customCSS, config.PostFormats, renderer, sessionRepo, appRepo)
        s = service.NewAuthService(sessionRepo, appRepo, s)
        s = service.NewLoggingService(logger, s)
        handler := service.NewHandler(s, config.StaticDirectory)
index 22f5a5340bcb6e2019e53a4b8b29b1d68dce1f26..8a8af6a9993b0a2b08f2b4d32458af0f43295369 100644 (file)
@@ -273,6 +273,7 @@ type Toot struct {
        Sensitive   bool     `json:"sensitive"`
        SpoilerText string   `json:"spoiler_text"`
        Visibility  string   `json:"visibility"`
+       ContentType string   `json:"content_type"`
 }
 
 // Mention hold information for mention.
index c36b6cba2e3870407010acab735ec217753d5a4c..edd88e93b82838ce7eea302c3017e8e263e0a57b 100644 (file)
@@ -266,6 +266,9 @@ func (c *Client) PostStatus(ctx context.Context, toot *Toot) (*Status, error) {
        if toot.SpoilerText != "" {
                params.Set("spoiler_text", toot.SpoilerText)
        }
+       if toot.ContentType != "" {
+               params.Set("content_type", toot.ContentType)
+       }
 
        var status Status
        err := c.doAPI(ctx, http.MethodPost, "/api/v1/statuses", params, &status, nil)
index 90e5771047ddcf2aeb27dd1b34cd58bc7f90e9ea..3098437658d89d811c1ecf3f43da5cae31cc87eb 100644 (file)
@@ -1,8 +1,14 @@
 package model
 
+type PostFormat struct {
+       Name string
+       Type string
+}
+
 type PostContext struct {
        DefaultVisibility string
        ReplyContext      *ReplyContext
+       Formats           []PostFormat
 }
 
 type ReplyContext struct {
index c40867221f17d3106956fca29e494ac3ed37ef61..0c2e7f6b0f129a9466e0306d1bf8514bd94ee7ba 100644 (file)
@@ -181,12 +181,12 @@ func (s *authService) UnRetweet(ctx context.Context, client io.Writer, c *model.
        return s.Service.UnRetweet(ctx, client, c, id)
 }
 
-func (s *authService) PostTweet(ctx context.Context, client io.Writer, c *model.Client, content string, replyToID string, visibility string, isNSFW bool, files []*multipart.FileHeader) (id string, err error) {
+func (s *authService) PostTweet(ctx context.Context, client io.Writer, c *model.Client, content string, replyToID string, format string, visibility string, isNSFW bool, files []*multipart.FileHeader) (id string, err error) {
        c, err = s.getClient(ctx)
        if err != nil {
                return
        }
-       return s.Service.PostTweet(ctx, client, c, content, replyToID, visibility, isNSFW, files)
+       return s.Service.PostTweet(ctx, client, c, content, replyToID, format, visibility, isNSFW, files)
 }
 
 func (s *authService) Follow(ctx context.Context, client io.Writer, c *model.Client, id string) (err error) {
index fbc63717a747d321748e32593fc54658067e4572..f5e6d6605f2df1fc77044133fabc154450b79c78 100644 (file)
@@ -157,12 +157,12 @@ func (s *loggingService) UnRetweet(ctx context.Context, client io.Writer, c *mod
        return s.Service.UnRetweet(ctx, client, c, id)
 }
 
-func (s *loggingService) PostTweet(ctx context.Context, client io.Writer, c *model.Client, content string, replyToID string, visibility string, isNSFW bool, files []*multipart.FileHeader) (id string, err error) {
+func (s *loggingService) PostTweet(ctx context.Context, client io.Writer, c *model.Client, content string, replyToID string, format string, visibility string, isNSFW bool, files []*multipart.FileHeader) (id string, err error) {
        defer func(begin time.Time) {
-               s.logger.Printf("method=%v, content=%v, reply_to_id=%v, visibility=%v, is_nsfw=%v, took=%v, err=%v\n",
-                       "PostTweet", content, replyToID, visibility, isNSFW, time.Since(begin), err)
+               s.logger.Printf("method=%v, content=%v, reply_to_id=%v, format=%v, visibility=%v, is_nsfw=%v, took=%v, err=%v\n",
+                       "PostTweet", content, replyToID, format, visibility, isNSFW, time.Since(begin), err)
        }(time.Now())
-       return s.Service.PostTweet(ctx, client, c, content, replyToID, visibility, isNSFW, files)
+       return s.Service.PostTweet(ctx, client, c, content, replyToID, format, visibility, isNSFW, files)
 }
 
 func (s *loggingService) Follow(ctx context.Context, client io.Writer, c *model.Client, id string) (err error) {
index 7dc784f38391f66402930cc675122499189872c6..27870795b541184f07529b31d27d0e5a42b409e9 100644 (file)
@@ -43,7 +43,7 @@ type Service interface {
        UnLike(ctx context.Context, client io.Writer, c *model.Client, id string) (err error)
        Retweet(ctx context.Context, client io.Writer, c *model.Client, id string) (err error)
        UnRetweet(ctx context.Context, client io.Writer, c *model.Client, id string) (err error)
-       PostTweet(ctx context.Context, client io.Writer, c *model.Client, content string, replyToID string, visibility string, isNSFW bool, files []*multipart.FileHeader) (id string, err error)
+       PostTweet(ctx context.Context, client io.Writer, c *model.Client, content string, replyToID string, format string, visibility string, isNSFW bool, files []*multipart.FileHeader) (id string, err error)
        Follow(ctx context.Context, client io.Writer, c *model.Client, id string) (err error)
        UnFollow(ctx context.Context, client io.Writer, c *model.Client, id string) (err error)
 }
@@ -53,19 +53,21 @@ type service struct {
        clientScope   string
        clientWebsite string
        customCSS     string
+       postFormats   []model.PostFormat
        renderer      renderer.Renderer
        sessionRepo   model.SessionRepository
        appRepo       model.AppRepository
 }
 
 func NewService(clientName string, clientScope string, clientWebsite string,
-       customCSS string, renderer renderer.Renderer, sessionRepo model.SessionRepository,
-       appRepo model.AppRepository) Service {
+       customCSS string, postFormats []model.PostFormat, renderer renderer.Renderer,
+       sessionRepo model.SessionRepository, appRepo model.AppRepository) Service {
        return &service{
                clientName:    clientName,
                clientScope:   clientScope,
                clientWebsite: clientWebsite,
                customCSS:     customCSS,
+               postFormats:   postFormats,
                renderer:      renderer,
                sessionRepo:   sessionRepo,
                appRepo:       appRepo,
@@ -297,6 +299,7 @@ func (svc *service) ServeTimelinePage(ctx context.Context, client io.Writer,
 
        postContext := model.PostContext{
                DefaultVisibility: c.Session.Settings.DefaultVisibility,
+               Formats:           svc.postFormats,
        }
 
        commonData, err := svc.getCommonData(ctx, client, c)
@@ -353,6 +356,7 @@ func (svc *service) ServeThreadPage(ctx context.Context, client io.Writer, c *mo
 
                postContext = model.PostContext{
                        DefaultVisibility: s.Visibility,
+                       Formats:           svc.postFormats,
                        ReplyContext: &model.ReplyContext{
                                InReplyToID:   id,
                                InReplyToName: status.Account.Acct,
@@ -647,7 +651,7 @@ func (svc *service) UnRetweet(ctx context.Context, client io.Writer, c *model.Cl
        return
 }
 
-func (svc *service) PostTweet(ctx context.Context, client io.Writer, c *model.Client, content string, replyToID string, visibility string, isNSFW bool, files []*multipart.FileHeader) (id string, err error) {
+func (svc *service) PostTweet(ctx context.Context, client io.Writer, c *model.Client, content string, replyToID string, format string, visibility string, isNSFW bool, files []*multipart.FileHeader) (id string, err error) {
        var mediaIds []string
        for _, f := range files {
                a, err := c.UploadMediaFromMultipartFileHeader(ctx, f)
@@ -667,6 +671,7 @@ func (svc *service) PostTweet(ctx context.Context, client io.Writer, c *model.Cl
                Status:      content,
                InReplyToID: replyToID,
                MediaIDs:    mediaIds,
+               ContentType: format,
                Visibility:  visibility,
                Sensitive:   isNSFW,
        }
index d4011dbdf56febe0a4e08b363ed808d05371b467..654177264004722943c3f1359539858e6ab63153 100644 (file)
@@ -183,12 +183,13 @@ func NewHandler(s Service, staticDir string) http.Handler {
 
                content := getMultipartFormValue(req.MultipartForm, "content")
                replyToID := getMultipartFormValue(req.MultipartForm, "reply_to_id")
+               format := getMultipartFormValue(req.MultipartForm, "format")
                visibility := getMultipartFormValue(req.MultipartForm, "visibility")
                isNSFW := "on" == getMultipartFormValue(req.MultipartForm, "is_nsfw")
 
                files := req.MultipartForm.File["attachments"]
 
-               id, err := s.PostTweet(ctx, w, nil, content, replyToID, visibility, isNSFW, files)
+               id, err := s.PostTweet(ctx, w, nil, content, replyToID, format, visibility, isNSFW, files)
                if err != nil {
                        s.ServeErrorPage(ctx, w, err)
                        return
index 54024f08221d805d647d32d64e2672ec2a6896f1..0e104b46bb1bc9802da54408c86ca9dec398374c 100644 (file)
                <textarea id="post-content" name="content" class="post-content" cols="50" rows="5">{{if .ReplyContext}}{{.ReplyContext.ReplyContent}}{{end}}</textarea>
        </div>
        <div>
+               {{if gt (len .Formats) 0}}
+               <span class="post-form-field">
+                       <label for="post-format"> Format </label>
+                       <select id="post-format" name="format">
+                               {{range .Formats}} <option value="{{.Type}}">{{.Name}}</option> {{end}}
+                       </select>
+               </span>
+               {{end}}
                <span class="post-form-field">
                        <label for="post-visilibity"> Visibility </label>
                        <select id="post-visilibity" name="visibility">
@@ -25,8 +33,6 @@
                        <input type="checkbox" id="nsfw-checkbox" name="is_nsfw" value="on">
                        <label for="nsfw-checkbox"> Is NSFW </label>
                </span>
-               <span class="post-form-field">
-               </span>
        </div>
        <div>
                <span class="post-form-field">