Skip to content
This repository was archived by the owner on Sep 2, 2024. It is now read-only.

Commit d42977b

Browse files
committed
Merge branch 'chore/create-web-ui-for-file-storage' of https://github.com/VladPetriv/core into VladPetriv-chore/create-web-ui-for-file-storage
2 parents 20253be + 96f0250 commit d42977b

File tree

12 files changed

+288
-2
lines changed

12 files changed

+288
-2
lines changed

database/memory/storage.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,16 @@ func (m *Memory) DeleteFile(dbName, fileID string) error {
3232
m.DB[key] = files
3333
return nil
3434
}
35+
36+
func (m *Memory) ListAllFiles(dbName, accountID string) (results []internal.File, err error) {
37+
files, err := all[internal.File](m, dbName, "sb_files")
38+
if err != nil {
39+
return
40+
}
41+
42+
results = filter(files, func(x internal.File) bool {
43+
return x.AccountID == accountID
44+
})
45+
46+
return
47+
}

database/memory/storage_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,31 @@ func TestFileStorage(t *testing.T) {
1616
Uploaded: time.Now(),
1717
}
1818

19+
f1 := internal.File{
20+
AccountID: adminAccount.ID,
21+
Key: "key1",
22+
URL: "https://test1",
23+
Size: 123456,
24+
Uploaded: time.Now(),
25+
}
26+
1927
id, err := datastore.AddFile(confDBName, f)
2028
if err != nil {
2129
t.Fatal(err)
2230
}
2331

32+
_, err = datastore.AddFile(confDBName, f1)
33+
if err != nil {
34+
t.Fatal(err)
35+
}
36+
37+
list, err := datastore.ListAllFiles(confDBName, f.AccountID)
38+
if err != nil {
39+
t.Fatal(err)
40+
} else if len(list) > 2 || len(list) < 2 {
41+
t.Errorf("expected list length to be 2 got %d", len(list))
42+
}
43+
2444
f2, err := datastore.GetFileByID(confDBName, id)
2545
if err != nil {
2646
t.Fatal(err)

database/mongo/storage.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,38 @@ func (mg *Mongo) DeleteFile(dbName, fileID string) error {
108108
}
109109
return nil
110110
}
111+
112+
func (mg *Mongo) ListAllFiles(dbName, accountID string) ([]internal.File, error) {
113+
db := mg.Client.Database(dbName)
114+
115+
aid, err := primitive.ObjectIDFromHex(accountID)
116+
if err != nil {
117+
return nil, err
118+
}
119+
120+
filter := bson.M{FieldAccountID: aid}
121+
122+
sr, err := db.Collection("sb_files").Find(mg.Ctx, filter)
123+
if err != nil {
124+
return nil, err
125+
}
126+
127+
defer sr.Close(mg.Ctx)
128+
129+
var results []internal.File
130+
131+
for sr.Next(mg.Ctx) {
132+
var f LocalFile
133+
if err = sr.Decode(&f); err != nil {
134+
return nil, err
135+
}
136+
137+
results = append(results, fromLocalFile(f))
138+
}
139+
140+
if err := sr.Err(); err != nil {
141+
return nil, err
142+
}
143+
144+
return results, nil
145+
}

database/mongo/storage_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,35 @@ func TestFileStorage(t *testing.T) {
1616
Uploaded: time.Now(),
1717
}
1818

19+
f1 := internal.File{
20+
AccountID: adminAccount.ID,
21+
Key: "key1",
22+
URL: "https://test1",
23+
Size: 123456,
24+
Uploaded: time.Now(),
25+
}
26+
1927
id, err := datastore.AddFile(confDBName, f)
2028
if err != nil {
2129
t.Fatal(err)
2230
} else if len(id) < 10 {
2331
t.Fatalf("expected to get id got %s", id)
2432
}
2533

34+
_, err = datastore.AddFile(confDBName, f1)
35+
if err != nil {
36+
t.Fatal(err)
37+
} else if len(id) < 10 {
38+
t.Fatalf("expected to get id got %s", id)
39+
}
40+
41+
list, err := datastore.ListAllFiles(confDBName, f.AccountID)
42+
if err != nil {
43+
t.Fatal(err)
44+
} else if len(list) < 2 || len(list) > 2 {
45+
t.Errorf("expected file length to be 2 go %d", len(list))
46+
}
47+
2648
f2, err := datastore.GetFileByID(confDBName, id)
2749
if err != nil {
2850
t.Fatal(err)

database/postgresql/storage.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,34 @@ func (pg *PostgreSQL) DeleteFile(dbName, fileID string) error {
5050
return nil
5151
}
5252

53+
func (pg *PostgreSQL) ListAllFiles(dbName, accountID string) (results []internal.File, err error) {
54+
qry := fmt.Sprintf(`
55+
SELECT *
56+
FROM %s.sb_files
57+
WHERE account_id = $1
58+
`, dbName)
59+
60+
rows, err := pg.DB.Query(qry, accountID)
61+
if err != nil {
62+
return
63+
}
64+
65+
defer rows.Close()
66+
67+
for rows.Next() {
68+
var f internal.File
69+
if err = scanFile(rows, &f); err != nil {
70+
return
71+
}
72+
73+
results = append(results, f)
74+
}
75+
76+
err = rows.Err()
77+
78+
return
79+
}
80+
5381
func scanFile(rows Scanner, f *internal.File) error {
5482
return rows.Scan(
5583
&f.ID,

database/postgresql/storage_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,31 @@ func TestFileStorage(t *testing.T) {
1616
Uploaded: time.Now(),
1717
}
1818

19+
f1 := internal.File{
20+
AccountID: adminAccount.ID,
21+
Key: "key1",
22+
URL: "https://test1",
23+
Size: 123456,
24+
Uploaded: time.Now(),
25+
}
26+
1927
id, err := datastore.AddFile(confDBName, f)
2028
if err != nil {
2129
t.Fatal(err)
2230
}
2331

32+
_, err = datastore.AddFile(confDBName, f1)
33+
if err != nil {
34+
t.Fatal(err)
35+
}
36+
37+
list, err := datastore.ListAllFiles(confDBName, f.AccountID)
38+
if err != nil {
39+
t.Fatal(err)
40+
} else if len(list) > 2 || len(list) < 2 {
41+
t.Errorf("expected list length to be 2 got %d", len(list))
42+
}
43+
2444
f2, err := datastore.GetFileByID(confDBName, id)
2545
if err != nil {
2646
t.Fatal(err)

internal/persister.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,5 @@ type Persister interface {
7777
AddFile(dbName string, f File) (id string, err error)
7878
GetFileByID(dbName, fileID string) (f File, err error)
7979
DeleteFile(dbName, fileID string) error
80+
ListAllFiles(dbName, accountID string) ([]File, error)
8081
}

render.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"log"
77
"net/http"
88
"os"
9+
"path/filepath"
910
"runtime/debug"
1011
"strconv"
1112
"strings"
@@ -123,5 +124,48 @@ func customFuncs() template.FuncMap {
123124
}
124125
return fmt.Sprintf("%v", v)
125126
},
127+
"convertFileSize": func(size int64) string {
128+
const unit = 1000
129+
if size < unit {
130+
return fmt.Sprintf("%d B", size)
131+
}
132+
div, exp := int64(unit), 0
133+
for n := size / unit; n >= unit; n /= unit {
134+
div *= unit
135+
exp++
136+
}
137+
138+
return fmt.Sprintf("%.1f %cB", float64(size)/float64(div), "KMGTPE"[exp])
139+
},
140+
"convertFileType": func(key string) string {
141+
return filepath.Ext(key)[1:]
142+
},
143+
"convertFileUploadedDate": func(uploaded time.Time) string {
144+
return uploaded.Format("January 02, 2006 at 15:04")
145+
},
146+
"parseFilename": func(key string) string {
147+
splitedKey := strings.Split(key, "/")
148+
149+
filename := splitedKey[len(splitedKey)-1]
150+
151+
return strings.Split(filename, ".")[0]
152+
},
153+
"getElementByFileExt": func(fileType string) string {
154+
imgTypes := "jpg png gif jpeg svg icon webp raw"
155+
videoTypes := "avi mp4 mkv mov wmv flv avchd"
156+
audioTypes := "mp3 ogg aac oga flac pcm wav aiff"
157+
158+
fileType = strings.ToLower(fileType)
159+
160+
if strings.Contains(imgTypes, fileType) {
161+
return "image"
162+
} else if strings.Contains(videoTypes, fileType) {
163+
return "video"
164+
} else if strings.Contains(audioTypes, fileType) {
165+
return "audio"
166+
}
167+
168+
return ""
169+
},
126170
}
127171
}

server.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ func Start(c config.AppConfig) {
248248
http.Handle("/ui/fn", middleware.Chain(http.HandlerFunc(webUI.fnList), stdRoot...))
249249
http.Handle("/ui/forms", middleware.Chain(http.HandlerFunc(webUI.forms), stdRoot...))
250250
http.Handle("/ui/forms/del/", middleware.Chain(http.HandlerFunc(webUI.formDel), stdRoot...))
251+
http.Handle("/ui/fs", middleware.Chain(http.HandlerFunc(webUI.fsList), stdRoot...))
252+
http.Handle("/ui/fs/del/", middleware.Chain(http.HandlerFunc(webUI.fsDel), stdRoot...))
251253
http.HandleFunc("/", webUI.login)
252254

253255
// graceful shutdown

templates/fs_list.html

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{{ template "head" .}}
2+
3+
<body>
4+
{{template "navbar" .}}
5+
<div class="container p-6">
6+
<br>
7+
<h2 class="title is-2">
8+
Files
9+
</h2>
10+
<table class="table is-striped" style="width:100%;">
11+
<thead>
12+
<tr>
13+
<th style="width:30%;">Name</th>
14+
<th style="width:10%; text-align:center;">Size</th>
15+
<th style="width:10%; text-align:center;">Type</th>
16+
<th style="width:20%; text-align:center;">Uploaded</th>
17+
<th style="text-align:center;">Preview</th>
18+
<th style="text-align:center;">Delete</th>
19+
</tr>
20+
</thead>
21+
<tbody>
22+
{{range .Data}}
23+
{{$fileType := convertFileType .Key}}
24+
{{$elementType := getElementByFileExt $fileType}}
25+
26+
{{ if or (eq $elementType "") (eq $elementType "audio")}}
27+
<tr style="height:100px;">
28+
{{ else }}
29+
<tr style="height:200px;">
30+
{{ end }}
31+
<td>{{ parseFilename .Key }}</td>
32+
<td style="text-align:center;">{{ convertFileSize .Size }}</td>
33+
<td style="text-align:center;">{{ $fileType }}</td>
34+
<td style="text-align:center;">{{ convertFileUploadedDate .Uploaded}}</td>
35+
<td style="text-align:center;">
36+
{{ if eq $elementType "image" }}
37+
<a href="{{ .URL }}">
38+
<img src="{{ .URL }}" alt="uploaded image" style="height:200px;">
39+
</a>
40+
{{ else if eq $elementType "video" }}
41+
<video controls style="height:200px;">
42+
<source src="{{ .URL }}">
43+
</video>
44+
{{ else if eq $elementType "audio" }}
45+
<audio src="{{ .URL }}" controls></audio>
46+
{{ else }}
47+
<a href="{{ .URL }}">
48+
Can't preview!
49+
</a>
50+
{{ end }}
51+
</td>
52+
<td style="text-align:center;">
53+
<a
54+
href="/ui/fs/del/{{ .ID }}"
55+
class="delete"
56+
onclick="return confirm('Are you sure you want to delete this file?\n\nThis is irreversible.')">
57+
</a>
58+
</td>
59+
</tr>
60+
{{end}}
61+
</tbody>
62+
</table>
63+
</div>
64+
65+
</body>
66+
67+
{{template "foot"}}
68+

0 commit comments

Comments
 (0)