From 3fff558c4b1c9b9e0576723df810280cf4f7af81 Mon Sep 17 00:00:00 2001
From: Christian Pointner <equinox@helsinki.at>
Date: Wed, 4 Jul 2018 11:55:36 +0200
Subject: [PATCH] implemented PATCH file, aka update metadata

---
 api/v1/api_files.go         | 19 ++++++++++++++++++-
 cmd/tank/bindata_assetfs.go | 20 ++++++++++----------
 store/files.go              | 14 ++++++++++++++
 3 files changed, 42 insertions(+), 11 deletions(-)

diff --git a/api/v1/api_files.go b/api/v1/api_files.go
index 0ce3756..9f63ab3 100644
--- a/api/v1/api_files.go
+++ b/api/v1/api_files.go
@@ -88,7 +88,24 @@ func (api *API) ReadFileOfGroup() http.Handler {
 
 func (api *API) PatchFileOfGroup() http.Handler {
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{Error: "patching files of group not yet implemented"})
+		vars := mux.Vars(r)
+		id, err := idFromString(vars["file-id"])
+		if err != nil {
+			sendWebResponse(w, http.StatusBadRequest, ErrorResponse{Error: "invalid file-id: " + err.Error()})
+			return
+		}
+		data := make(map[string]interface{})
+		if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
+			sendWebResponse(w, http.StatusBadRequest, ErrorResponse{Error: "error decoding request: " + err.Error()})
+			return
+		}
+		// TODO: warn if data contains invalid/unknown keys
+		file, err := api.store.UpdateFileMetadata(vars["group-id"], id, data)
+		if err != nil {
+			sendStoreError(w, err)
+			return
+		}
+		sendWebResponse(w, http.StatusOK, file)
 	})
 }
 
diff --git a/cmd/tank/bindata_assetfs.go b/cmd/tank/bindata_assetfs.go
index d52f25a..d1a3c98 100644
--- a/cmd/tank/bindata_assetfs.go
+++ b/cmd/tank/bindata_assetfs.go
@@ -93,7 +93,7 @@ func uiIndexHtml() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "ui/index.html", size: 8855, mode: os.FileMode(436), modTime: time.Unix(1530625365, 0)}
+	info := bindataFileInfo{name: "ui/index.html", size: 8855, mode: os.FileMode(436), modTime: time.Unix(1530693618, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -113,7 +113,7 @@ func uiCssBootstrapRebootMinCss() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "ui/css/bootstrap-reboot.min.css", size: 3989, mode: os.FileMode(420), modTime: time.Unix(1525033372, 0)}
+	info := bindataFileInfo{name: "ui/css/bootstrap-reboot.min.css", size: 3989, mode: os.FileMode(436), modTime: time.Unix(1530321195, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -133,7 +133,7 @@ func uiCssBootstrapRebootMinCssMap() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "ui/css/bootstrap-reboot.min.css.map", size: 25857, mode: os.FileMode(436), modTime: time.Unix(1530624697, 0)}
+	info := bindataFileInfo{name: "ui/css/bootstrap-reboot.min.css.map", size: 25857, mode: os.FileMode(420), modTime: time.Unix(1525065771, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -153,7 +153,7 @@ func uiCssBootstrapMinCss() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "ui/css/bootstrap.min.css", size: 140930, mode: os.FileMode(420), modTime: time.Unix(1525033370, 0)}
+	info := bindataFileInfo{name: "ui/css/bootstrap.min.css", size: 140930, mode: os.FileMode(436), modTime: time.Unix(1530321195, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -173,7 +173,7 @@ func uiCssBootstrapMinCssMap() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "ui/css/bootstrap.min.css.map", size: 559636, mode: os.FileMode(436), modTime: time.Unix(1530624697, 0)}
+	info := bindataFileInfo{name: "ui/css/bootstrap.min.css.map", size: 559636, mode: os.FileMode(420), modTime: time.Unix(1525065769, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -193,7 +193,7 @@ func uiCssMainCss() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "ui/css/main.css", size: 232, mode: os.FileMode(436), modTime: time.Unix(1530314832, 0)}
+	info := bindataFileInfo{name: "ui/css/main.css", size: 232, mode: os.FileMode(436), modTime: time.Unix(1530321195, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -213,7 +213,7 @@ func uiJsBootstrapBundleMinJs() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "ui/js/bootstrap.bundle.min.js", size: 70682, mode: os.FileMode(420), modTime: time.Unix(1530305287, 0)}
+	info := bindataFileInfo{name: "ui/js/bootstrap.bundle.min.js", size: 70682, mode: os.FileMode(436), modTime: time.Unix(1530321195, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -233,7 +233,7 @@ func uiJsBootstrapBundleMinJsMap() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "ui/js/bootstrap.bundle.min.js.map", size: 292629, mode: os.FileMode(436), modTime: time.Unix(1530624697, 0)}
+	info := bindataFileInfo{name: "ui/js/bootstrap.bundle.min.js.map", size: 292629, mode: os.FileMode(420), modTime: time.Unix(1525065777, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -253,7 +253,7 @@ func uiJsJqueryMinJs() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "ui/js/jquery.min.js", size: 86927, mode: os.FileMode(436), modTime: time.Unix(1516469204, 0)}
+	info := bindataFileInfo{name: "ui/js/jquery.min.js", size: 86927, mode: os.FileMode(436), modTime: time.Unix(1530321195, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -273,7 +273,7 @@ func uiJsMainJs() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "ui/js/main.js", size: 13376, mode: os.FileMode(436), modTime: time.Unix(1530627768, 0)}
+	info := bindataFileInfo{name: "ui/js/main.js", size: 13376, mode: os.FileMode(436), modTime: time.Unix(1530693618, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
diff --git a/store/files.go b/store/files.go
index ea66905..1d6db05 100644
--- a/store/files.go
+++ b/store/files.go
@@ -74,6 +74,20 @@ func (st *Store) UpdateFile(group string, id uint64, file File) (*File, error) {
 	return &file, err
 }
 
+func (st *Store) UpdateFileMetadata(group string, id uint64, metadata map[string]interface{}) (*File, error) {
+	file := &File{ID: id}
+	md := make(map[string]interface{})
+	for key, value := range metadata {
+		md["metadata__"+key] = value
+	}
+	// make sure the file actually belongs to <group> since permissions are enforced
+	// based on group membership
+	if err := st.db.Model(&file).Where("group_name = ?", group).Update(md).Error; err != nil {
+		return nil, err
+	}
+	return file, nil
+}
+
 func (st *Store) getFileUsage(id uint64, playlists *Playlists) (err error) {
 	sub := st.db.Model(PlaylistEntry{}).Select("playlist_id").Where("file_id = ?", id).Group("playlist_id").SubQuery()
 	err = st.db.Where("id in ?", sub).Find(playlists).Error
-- 
GitLab