Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#97): Implement name & descriptions #110

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions internal/db/db_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 17 additions & 1 deletion internal/db/db_sqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ func (s *Sqlite) FindFile(ctx context.Context, id string) (*snips.File, error) {
id,
created_at,
updated_at,
name,
description,
size,
content,
private,
Expand All @@ -80,6 +82,8 @@ func (s *Sqlite) FindFile(ctx context.Context, id string) (*snips.File, error) {
&file.ID,
&file.CreatedAt,
&file.UpdatedAt,
&file.Name,
&file.Description,
&file.Size,
&file.RawContent,
&file.Private,
Expand Down Expand Up @@ -122,18 +126,22 @@ func (s *Sqlite) CreateFile(ctx context.Context, file *snips.File, maxFileCount
id,
created_at,
updated_at,
name,
description,
size,
content,
private,
type,
user_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`

if _, err := s.ExecContext(ctx, insertQuery,
file.ID,
file.CreatedAt,
file.UpdatedAt,
file.Name,
file.Description,
file.Size,
file.RawContent,
file.Private,
Expand All @@ -153,6 +161,8 @@ func (s *Sqlite) UpdateFile(ctx context.Context, file *snips.File) error {
UPDATE files
SET
updated_at = ?,
name = ?,
description = ?,
size = ?,
content = ?,
private = ?,
Expand All @@ -162,6 +172,8 @@ func (s *Sqlite) UpdateFile(ctx context.Context, file *snips.File) error {

if _, err := s.ExecContext(ctx, query,
file.UpdatedAt,
file.Name,
file.Description,
file.Size,
file.RawContent,
file.Private,
Expand Down Expand Up @@ -194,6 +206,8 @@ func (s *Sqlite) FindFilesByUser(ctx context.Context, userID string) ([]*snips.F
id,
created_at,
updated_at,
name,
description,
size,
private,
type,
Expand All @@ -216,6 +230,8 @@ func (s *Sqlite) FindFilesByUser(ctx context.Context, userID string) ([]*snips.F
&file.ID,
&file.CreatedAt,
&file.UpdatedAt,
&file.Name,
&file.Description,
&file.Size,
&file.Private,
&file.Type,
Expand Down
8 changes: 8 additions & 0 deletions internal/db/schema.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ table "files" {
column "updated_at" {
type = datetime
}
column "name" {
type = text
default = ""
}
column "description" {
type = text
default = ""
}
column "size" {
type = integer
}
Expand Down
18 changes: 10 additions & 8 deletions internal/http/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,16 @@ func FileHandler(cfg *config.Config, database db.DB, assets Assets) http.Handler
}

vars := map[string]interface{}{
"FileID": file.ID,
"FileSize": humanize.Bytes(file.Size),
"CreatedAt": humanize.Time(file.CreatedAt),
"UpdatedAt": humanize.Time(file.UpdatedAt),
"FileType": strings.ToLower(file.Type),
"RawHREF": rawHref,
"HTML": html,
"Private": file.Private,
"FileID": file.ID,
"FileName": file.Name,
"FileDescription": file.Description,
"FileSize": humanize.Bytes(file.Size),
"CreatedAt": humanize.Time(file.CreatedAt),
"UpdatedAt": humanize.Time(file.UpdatedAt),
"FileType": strings.ToLower(file.Type),
"RawHREF": rawHref,
"HTML": html,
"Private": file.Private,
}

err = tmpl.ExecuteTemplate(w, "file.go.html", vars)
Expand Down
30 changes: 22 additions & 8 deletions internal/snips/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package snips

import (
"encoding/binary"
"errors"
"fmt"
"net/url"
"time"
Expand All @@ -14,17 +15,21 @@ import (
const (
FileTypeBinary = "binary"
FileTypeMarkdown = "markdown"

DescriptionCharacterLimit = 120
)

type File struct {
ID string
CreatedAt time.Time
UpdatedAt time.Time
Size uint64
RawContent []byte
Private bool
Type string
UserID string
ID string
CreatedAt time.Time
UpdatedAt time.Time
Name string
Description string
Size uint64
RawContent []byte
Private bool
Type string
UserID string
}

func (f *File) IsBinary() bool {
Expand Down Expand Up @@ -71,6 +76,15 @@ func (f *File) GetContent() ([]byte, error) {
return decodedBytes, err
}

func (f *File) SetDescription(description string) error {
if len(description) > DescriptionCharacterLimit {
return errors.New("description max length is 120 characters")
}

f.Description = description
return nil
}

func (f *File) SetContent(in []byte, compress bool) error {
if !compress {
f.RawContent = in
Expand Down
15 changes: 8 additions & 7 deletions internal/ssh/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package ssh
import "errors"

var (
ErrFileNotFound = errors.New("file not found")
ErrFileTooLarge = errors.New("file too large")
ErrNilProgram = errors.New("nil program")
ErrPrivateFileAccess = errors.New("private file access")
ErrUnknownCommand = errors.New("unknown command")
ErrSignPublicFile = errors.New("unable to sign public file")
ErrOpOnNonOwnedFile = errors.New("operation on non-owned file")
ErrFileNotFound = errors.New("file not found")
ErrFileTooLarge = errors.New("file too large")
ErrNilProgram = errors.New("nil program")
ErrPrivateFileAccess = errors.New("private file access")
ErrUnknownCommand = errors.New("unknown command")
ErrSignPublicFile = errors.New("unable to sign public file")
ErrOpOnNonOwnedFile = errors.New("operation on non-owned file")
ErrEmptyNameDescFields = errors.New("either name or desc field is required")
)
29 changes: 26 additions & 3 deletions internal/ssh/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,19 @@ var (
type UploadFlags struct {
*flag.FlagSet

Private bool
Extension string
TTL time.Duration
Name string
Description string
Private bool
Extension string
TTL time.Duration
}

func (uf *UploadFlags) Parse(out io.Writer, args []string) error {
uf.FlagSet = flag.NewFlagSet("", flag.ContinueOnError)
uf.SetOutput(out)

uf.StringVar(&uf.Name, "name", "", "set a description for your file")
uf.StringVar(&uf.Description, "desc", "", "set a description for your file")
uf.BoolVar(&uf.Private, "private", false, "only accessible via creator or signed urls (optional)")
uf.StringVar(&uf.Extension, "ext", "", "set the file extension (optional)")
addDurationFlag(uf.FlagSet, &uf.TTL, "ttl", 0, "lifetime of the signed url (optional)")
Expand All @@ -41,10 +45,29 @@ func (uf *UploadFlags) Parse(out io.Writer, args []string) error {
}

uf.Extension = strings.TrimPrefix(strings.ToLower(uf.Extension), ".")
uf.Name = strings.Trim(uf.Name, " ")
uf.Description = strings.Trim(uf.Description, " ")

return nil
}

type ChangeField struct {
*flag.FlagSet

Name string
Description string
}

func (sf *ChangeField) Parse(out io.Writer, args []string) error {
sf.FlagSet = flag.NewFlagSet("", flag.ContinueOnError)
sf.SetOutput(out)

sf.FlagSet.StringVar(&sf.Name, "name", "", "provide a name for your snippet")
sf.FlagSet.StringVar(&sf.Description, "desc", "", "provide a description for your snippet")

return sf.FlagSet.Parse(args)
}

type SignFlags struct {
*flag.FlagSet

Expand Down
76 changes: 75 additions & 1 deletion internal/ssh/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,10 @@ func (h *SessionHandler) FileRequest(sesh *UserSession) {
h.DeleteFile(sesh, file)
case "sign":
h.SignFile(sesh, file)
case "modify":
h.ChangeNameOrDesc(sesh, file)
default:
sesh.Error(ErrUnknownCommand, "Unknown command", "Unknown command specified: %q", args[0])
sesh.Error(ErrUnknownCommand, "Unknown command", "Unknown command specified: %q. Known commands: rm, sign, modify", args[0])
}
}

Expand Down Expand Up @@ -263,6 +265,78 @@ func (h *SessionHandler) SignFile(sesh *UserSession, file *snips.File) {
noti.Render(sesh)
}

func (h *SessionHandler) ChangeNameOrDesc(sesh *UserSession, file *snips.File) {
var err error

log := logger.From(sesh.Context())

flags := ChangeField{}

args := sesh.Command()[1:]

if err := flags.Parse(sesh.Stderr(), args); err != nil {
if !errors.Is(err, flag.ErrHelp) {
log.Warn().Err(err).Msg("invalid user specified flags")
flags.PrintDefaults()
}
return
}

if flags.Name == "" && flags.Description == "" {
// no changes to be made
sesh.Error(ErrEmptyNameDescFields, "Unable to modify file", "You need to provide either a name or desc flag")
return
}

if flags.Name != "" {
file.Name = flags.Name
}

if flags.Description != "" {
err = file.SetDescription(flags.Description)
if err != nil {
log.Warn().Err(err).Msg("description failed validation")
return
}
}

err = h.DB.UpdateFile(sesh.Context(), file)
if err != nil {
log.Warn().Err(err).Msg("could not update file")
return
}

metrics.IncrCounter([]string{"file", "modify file"}, 1)

noti := Notification{
Color: styles.Colors.Cyan,
Title: "File updated 📝",
WithStyle: func(s *lipgloss.Style) {
s.MarginTop(1)
},
}
visibility := styles.C(styles.Colors.White, "public")
if file.Private {
visibility = styles.C(styles.Colors.Red, "private")
}

attrs := make([]string, 0)
kvp := map[string]string{
"name": styles.C(styles.Colors.White, file.Name),
"description": styles.C(styles.Colors.White, file.Description),
"type": styles.C(styles.Colors.White, file.Type),
"size": styles.C(styles.Colors.White, humanize.Bytes(file.Size)),
"visibility": visibility,
}
for k, v := range kvp {
key := styles.C(styles.Colors.Muted, k+": ")
attrs = append(attrs, key+v)
}
sort.Strings(attrs)
noti.Messagef("id: %s\n%s", styles.C(styles.Colors.White, file.ID), strings.Join(attrs, styles.C(styles.Colors.Muted, " • ")))
noti.Render(sesh)
}

func (h *SessionHandler) DownloadFile(sesh *UserSession, file *snips.File) {
content, err := file.GetContent()
if err != nil {
Expand Down
10 changes: 10 additions & 0 deletions internal/tui/views/browser/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ type option struct {
}

var options = []option{
{
name: "change name",
prompt: prompt.ChangeName,
},
{
name: "change description",
prompt: prompt.ChangeDescription,
},
{
name: "edit extension",
prompt: prompt.ChangeExtension,
Expand Down Expand Up @@ -147,6 +155,8 @@ func (bwsr Browser) renderDetails() string {

values := [][2]string{
{"ID", file.ID},
{"Name", file.Name},
{"Desc", file.Description},
{"Size", humanize.Bytes(file.Size)},
{"Created", fmt.Sprintf("%s (%s)", file.CreatedAt.Format(time.RFC3339), humanize.Time(file.CreatedAt))},
{"Modified", fmt.Sprintf("%s (%s)", file.CreatedAt.Format(time.RFC3339), humanize.Time(file.UpdatedAt))},
Expand Down
6 changes: 5 additions & 1 deletion internal/tui/views/browser/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ type column struct {

var columns = []column{
{
name: "ID",
name: "Name",
render: func(file *snips.File) string {
if file.Name != "" {
return file.Name
}

return file.ID
},
},
Expand Down
Loading