repos / pico

pico services - prose.sh, pastes.sh, imgs.sh, feeds.sh, pgs.sh
git clone https://github.com/picosh/pico.git

pico / filehandlers / imgs
Eric Bower · 20 Sep 24

img.go

  1package uploadimgs
  2
  3import (
  4	"bytes"
  5	"fmt"
  6	"strings"
  7	"time"
  8
  9	"github.com/charmbracelet/ssh"
 10	"github.com/picosh/pico/db"
 11	"github.com/picosh/pico/filehandlers/util"
 12	"github.com/picosh/pico/shared"
 13	"github.com/picosh/send/send/utils"
 14)
 15
 16func (h *UploadImgHandler) validateImg(data *PostMetaData) (bool, error) {
 17	totalFileSize, err := h.DBPool.FindTotalSizeForUser(data.User.ID)
 18	if err != nil {
 19		return false, err
 20	}
 21
 22	fileMax := data.FeatureFlag.Data.FileMax
 23	if int64(data.FileSize) > fileMax {
 24		return false, fmt.Errorf("ERROR: file (%s) has exceeded maximum file size (%d bytes)", data.Filename, fileMax)
 25	}
 26
 27	storageMax := data.FeatureFlag.Data.StorageMax
 28	if uint64(totalFileSize+data.FileSize) > storageMax {
 29		return false, fmt.Errorf("ERROR: user (%s) has exceeded (%d bytes) max (%d bytes)", data.User.Name, totalFileSize, storageMax)
 30	}
 31
 32	if !shared.IsExtAllowed(data.Filepath, h.Cfg.AllowedExt) {
 33		extStr := strings.Join(h.Cfg.AllowedExt, ",")
 34		err := fmt.Errorf(
 35			"ERROR: (%s) invalid file, format must be (%s), skipping",
 36			data.Filename,
 37			extStr,
 38		)
 39		return false, err
 40	}
 41
 42	return true, nil
 43}
 44
 45func (h *UploadImgHandler) metaImg(data *PostMetaData) error {
 46	// if the file is empty that means we should delete it
 47	// so we can skip all the meta info
 48	if data.FileSize == 0 {
 49		return nil
 50	}
 51
 52	bucket, err := h.Storage.UpsertBucket(data.User.ID)
 53	if err != nil {
 54		return err
 55	}
 56
 57	reader := bytes.NewReader([]byte(data.Text))
 58
 59	fname, _, err := h.Storage.PutObject(
 60		bucket,
 61		data.Filename,
 62		utils.NopReaderAtCloser(reader),
 63		&utils.FileEntry{},
 64	)
 65	if err != nil {
 66		return err
 67	}
 68
 69	data.Data = db.PostData{
 70		ImgPath: fname,
 71	}
 72
 73	data.Text = ""
 74
 75	return nil
 76}
 77
 78func (h *UploadImgHandler) writeImg(s ssh.Session, data *PostMetaData) error {
 79	valid, err := h.validateImg(data)
 80	if !valid {
 81		return err
 82	}
 83	user, err := util.GetUser(s.Context())
 84	if err != nil {
 85		return err
 86	}
 87
 88	logger := h.Cfg.Logger
 89	logger = shared.LoggerWithUser(logger, user)
 90
 91	err = h.metaImg(data)
 92	if err != nil {
 93		logger.Error("could not get meta for img", "err", err.Error())
 94		return err
 95	}
 96
 97	modTime := time.Now()
 98
 99	if data.Mtime > 0 {
100		modTime = time.Unix(data.Mtime, 0)
101	}
102
103	logger = logger.With(
104		"filename", data.Filename,
105	)
106
107	if data.Cur == nil {
108		logger.Info("file not found, adding record")
109		insertPost := db.Post{
110			UserID: user.ID,
111			Space:  Space,
112
113			Data:        data.Data,
114			Description: data.Description,
115			Filename:    data.Filename,
116			FileSize:    data.FileSize,
117			Hidden:      data.Hidden,
118			MimeType:    data.MimeType,
119			PublishAt:   data.PublishAt,
120			Shasum:      data.Shasum,
121			Slug:        data.Slug,
122			Text:        data.Text,
123			Title:       data.Title,
124			UpdatedAt:   &modTime,
125		}
126		_, err := h.DBPool.InsertPost(&insertPost)
127		if err != nil {
128			logger.Error("post could not create", "err", err.Error())
129			return fmt.Errorf("error for %s: %v", data.Filename, err)
130		}
131
132		if len(data.Tags) > 0 {
133			logger.Info(
134				"found post tags, replacing with old tags",
135				"tags", strings.Join(data.Tags, ","),
136			)
137			err = h.DBPool.ReplaceTagsForPost(data.Tags, data.Post.ID)
138			if err != nil {
139				logger.Error("post could not replace tags", "err", err.Error())
140				return fmt.Errorf("error for %s: %v", data.Filename, err)
141			}
142		}
143	} else {
144		if data.Shasum == data.Cur.Shasum && modTime.Equal(*data.Cur.UpdatedAt) {
145			logger.Info("image found, but image is identical, skipping")
146			return nil
147		}
148
149		logger.Info("file found, updating record")
150
151		updatePost := db.Post{
152			ID: data.Cur.ID,
153
154			Data:        data.Data,
155			FileSize:    data.FileSize,
156			Description: data.Description,
157			PublishAt:   data.PublishAt,
158			Slug:        data.Slug,
159			Shasum:      data.Shasum,
160			Text:        data.Text,
161			Title:       data.Title,
162			Hidden:      data.Hidden,
163			UpdatedAt:   &modTime,
164		}
165		_, err = h.DBPool.UpdatePost(&updatePost)
166		if err != nil {
167			logger.Error("post could not update", "err", err.Error())
168			return fmt.Errorf("error for %s: %v", data.Filename, err)
169		}
170
171		logger.Info(
172			"found post tags, replacing with old tags",
173			"tags", strings.Join(data.Tags, ","),
174		)
175		err = h.DBPool.ReplaceTagsForPost(data.Tags, data.Cur.ID)
176		if err != nil {
177			logger.Error("post could not replace tags", "err", err.Error())
178			return fmt.Errorf("error for %s: %v", data.Filename, err)
179		}
180	}
181
182	return nil
183}