Merge 7ee1aec3b7
into 038a80c25e
This commit is contained in:
commit
7285315d5e
12
admin.go
12
admin.go
|
@ -12,6 +12,7 @@ package writefreely
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
"path/filepath"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
|
@ -19,6 +20,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"os"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/writeas/impart"
|
||||
|
@ -345,10 +347,20 @@ func handleAdminDeleteUser(app *App, u *User, w http.ResponseWriter, r *http.Req
|
|||
return impart.HTTPError{http.StatusInternalServerError, fmt.Sprintf("Could not delete user account for '%s': %v", username, err)}
|
||||
}
|
||||
|
||||
deleteMediaFilesOfUser(app, username)
|
||||
_ = addSessionFlash(app, w, r, fmt.Sprintf("User \"%s\" was deleted successfully.", username), nil)
|
||||
return impart.HTTPError{http.StatusFound, "/admin/users"}
|
||||
}
|
||||
|
||||
func deleteMediaFilesOfUser(app *App, username string) {
|
||||
mediaDirectoryPath := filepath.Join(app.cfg.Server.MediaParentDir, mediaDir,
|
||||
username)
|
||||
err := os.RemoveAll(mediaDirectoryPath)
|
||||
if err != nil {
|
||||
log.Error("Deleting media directory of %s failed: %v", username, err)
|
||||
}
|
||||
}
|
||||
|
||||
func handleAdminToggleUserStatus(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
|
||||
vars := mux.Vars(r)
|
||||
username := vars["username"]
|
||||
|
|
1
app.go
1
app.go
|
@ -47,6 +47,7 @@ import (
|
|||
|
||||
const (
|
||||
staticDir = "static"
|
||||
mediaDir = "media"
|
||||
assumedTitleLen = 80
|
||||
postsPerPage = 10
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ type (
|
|||
|
||||
TemplatesParentDir string `ini:"templates_parent_dir"`
|
||||
StaticParentDir string `ini:"static_parent_dir"`
|
||||
MediaParentDir string `ini:"media_parent_dir"`
|
||||
PagesParentDir string `ini:"pages_parent_dir"`
|
||||
KeysParentDir string `ini:"keys_parent_dir"`
|
||||
|
||||
|
@ -168,6 +169,10 @@ type (
|
|||
|
||||
// Disable password authentication if use only Oauth
|
||||
DisablePasswordAuth bool `ini:"disable_password_auth"`
|
||||
|
||||
AllowUploadMedia bool `ini:"allow_upload_media"`
|
||||
MediaMaxSize int64 `ini:"media_max_size"`
|
||||
TotalMediaSpace int64 `ini:"total_media_size"`
|
||||
}
|
||||
|
||||
EmailCfg struct {
|
||||
|
@ -203,8 +208,11 @@ func New() *Config {
|
|||
SingleUser: true,
|
||||
MinUsernameLen: 3,
|
||||
MaxBlogs: 1,
|
||||
MediaMaxSize: 10,
|
||||
TotalMediaSpace: 100,
|
||||
Federation: true,
|
||||
PublicStats: true,
|
||||
AllowUploadMedia: false,
|
||||
},
|
||||
}
|
||||
c.UseMySQL(true)
|
||||
|
|
|
@ -670,7 +670,12 @@ func (db *datastore) CreatePost(userID, collID int64, post *SubmittedPost) (*Pos
|
|||
ownerCollID := sql.NullInt64{
|
||||
Valid: false,
|
||||
}
|
||||
slug := sql.NullString{"", false}
|
||||
slugString := *post.Slug
|
||||
slugValid := true
|
||||
if slugString == "" {
|
||||
slugValid = false
|
||||
}
|
||||
slug := sql.NullString{slugString, slugValid}
|
||||
|
||||
// If an alias was supplied, we'll add this to the collection as well.
|
||||
if userID > 0 {
|
||||
|
|
|
@ -43,6 +43,7 @@ var (
|
|||
ErrCollectionGone = impart.HTTPError{http.StatusGone, "This blog was unpublished."}
|
||||
ErrCollectionPageNotFound = impart.HTTPError{http.StatusNotFound, "Collection page doesn't exist."}
|
||||
ErrPostNotFound = impart.HTTPError{Status: http.StatusNotFound, Message: "Post not found."}
|
||||
ErrFileNotFound = impart.HTTPError{Status: http.StatusNotFound, Message: "File not found."}
|
||||
ErrPostBanned = impart.HTTPError{Status: http.StatusGone, Message: "Post removed."}
|
||||
ErrPostUnpublished = impart.HTTPError{Status: http.StatusGone, Message: "Post unpublished by author."}
|
||||
ErrPostFetchError = impart.HTTPError{Status: http.StatusInternalServerError, Message: "We encountered an error getting the post. The humans have been alerted."}
|
||||
|
|
246
pad.go
246
pad.go
|
@ -11,9 +11,18 @@
|
|||
package writefreely
|
||||
|
||||
import (
|
||||
"os"
|
||||
"io"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
uuid "github.com/nu7hatch/gouuid"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/writeas/impart"
|
||||
"github.com/writeas/web-core/log"
|
||||
|
@ -120,6 +129,89 @@ func handleViewPad(app *App, w http.ResponseWriter, r *http.Request) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func okToEdit(app *App, w http.ResponseWriter, r *http.Request) error {
|
||||
vars := mux.Vars(r)
|
||||
action := vars["action"]
|
||||
slug := vars["slug"]
|
||||
collAlias := vars["collection"]
|
||||
appData := &struct {
|
||||
page.StaticPage
|
||||
Post *RawPost
|
||||
User *User
|
||||
EditCollection *Collection // Collection of the post we're editing, if any
|
||||
Flashes []string
|
||||
NeedsToken bool
|
||||
Silenced bool
|
||||
}{
|
||||
StaticPage: pageForReq(app, r),
|
||||
Post: &RawPost{Font: "norm"},
|
||||
User: getUserSession(app, r),
|
||||
}
|
||||
var err error
|
||||
appData.Silenced, err = app.db.IsUserSilenced(appData.User.ID)
|
||||
if err != nil {
|
||||
log.Error("view meta: get user status: %v", err)
|
||||
return ErrInternalGeneral
|
||||
}
|
||||
|
||||
if action == "" && slug == "" {
|
||||
return ErrPostNotFound
|
||||
}
|
||||
|
||||
// Make sure this isn't cached, so user doesn't accidentally lose data
|
||||
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||
w.Header().Set("Expires", "Thu, 28 Jul 1989 12:00:00 GMT")
|
||||
if slug != "" {
|
||||
appData.Post = getRawCollectionPost(app, slug, collAlias)
|
||||
if appData.Post.OwnerID != appData.User.ID {
|
||||
// TODO: add ErrForbiddenEditPost message to flashes
|
||||
return impart.HTTPError{
|
||||
http.StatusFound, r.URL.Path[:strings.LastIndex(r.URL.Path, "/meta")]}
|
||||
}
|
||||
if app.cfg.App.SingleUser {
|
||||
// TODO: optimize this query just like we do in GetCollectionForPad (?)
|
||||
appData.EditCollection, err = app.db.GetCollectionByID(1)
|
||||
} else {
|
||||
appData.EditCollection, err = app.db.GetCollectionForPad(collAlias)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appData.EditCollection.hostName = app.cfg.App.Host
|
||||
} else {
|
||||
// Editing a floating article
|
||||
appData.Post = getRawPost(app, action)
|
||||
appData.Post.Id = action
|
||||
}
|
||||
appData.NeedsToken = appData.User == nil || appData.User.ID != appData.Post.OwnerID
|
||||
|
||||
if appData.Post.Gone {
|
||||
return ErrPostUnpublished
|
||||
} else if appData.Post.Found && appData.Post.Content != "" {
|
||||
// Got the post
|
||||
} else if appData.Post.Found {
|
||||
return ErrPostFetchError
|
||||
} else {
|
||||
return ErrPostNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleDeleteFile(app *App, w http.ResponseWriter, r *http.Request) error {
|
||||
vars := mux.Vars(r)
|
||||
fileName := vars["filename"]
|
||||
slug := vars["slug"]
|
||||
user := getUserSession(app, r)
|
||||
filePath := filepath.Join(app.cfg.Server.MediaParentDir, mediaDir, user.Username, slug) + "/" + fileName
|
||||
err := os.Remove(filePath)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return ErrFileNotFound
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleViewMeta(app *App, w http.ResponseWriter, r *http.Request) error {
|
||||
vars := mux.Vars(r)
|
||||
action := vars["action"]
|
||||
|
@ -185,9 +277,163 @@ func handleViewMeta(app *App, w http.ResponseWriter, r *http.Request) error {
|
|||
return ErrPostNotFound
|
||||
}
|
||||
appData.Flashes, _ = getSessionFlashes(app, w, r, nil)
|
||||
user := getUserSession(app, r)
|
||||
|
||||
if slug == "" {
|
||||
slug, _ = getSlugFromActionId(app, action)
|
||||
}
|
||||
|
||||
mediaDirectoryPath := filepath.Join(app.cfg.Server.MediaParentDir, mediaDir,
|
||||
user.Username, slug)
|
||||
appData.Post.MediaFilesList, _ = getFilesListInPath(mediaDirectoryPath)
|
||||
if err = templates["edit-meta"].ExecuteTemplate(w, "edit-meta", appData); err != nil {
|
||||
log.Error("Unable to execute template: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getNewFileName(path string, originalFieName string) (string, error) {
|
||||
u, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
log.Error("Unable to generate uuid: %v", err)
|
||||
return "", err
|
||||
}
|
||||
extension := filepath.Ext(originalFieName)
|
||||
return u.String() + extension, nil
|
||||
}
|
||||
|
||||
func getFilesListInPath(path string) ([]string, error) {
|
||||
var files []string
|
||||
entries, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
files = append(files, "/" + path + "/" + entry.Name())
|
||||
}
|
||||
}
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func handleGetFile(app *App, w http.ResponseWriter, r *http.Request) error {
|
||||
vars := mux.Vars(r)
|
||||
slug := vars["slug"]
|
||||
author := vars["author"]
|
||||
filename := vars["filename"]
|
||||
mediaDirectoryPath := filepath.Join(app.cfg.Server.MediaParentDir, mediaDir,
|
||||
author, slug, filename)
|
||||
filePath := mediaDirectoryPath
|
||||
file, err := http.Dir("").Open(filePath)
|
||||
if err != nil {
|
||||
http.Error(w, "File not found", http.StatusNotFound)
|
||||
return nil
|
||||
}
|
||||
defer file.Close()
|
||||
fileInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to get file information", http.StatusInternalServerError)
|
||||
return nil
|
||||
}
|
||||
w.Header().Set("Content-Disposition", "attachment; filename="+fileInfo.Name())
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(fileInfo.Size(), 10))
|
||||
http.ServeContent(w, r, fileInfo.Name(), fileInfo.ModTime(), file)
|
||||
return nil
|
||||
}
|
||||
|
||||
func calculateDirectoryTotalSize(dirPath string) (int64, error) {
|
||||
var totalSize int64
|
||||
|
||||
err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
totalSize += info.Size()
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return totalSize, err
|
||||
}
|
||||
|
||||
func handleUploadMedia(app *App, w http.ResponseWriter, r *http.Request) error {
|
||||
maxUploadSize := app.cfg.App.MediaMaxSize * 1024 * 1024
|
||||
r.Body = http.MaxBytesReader(w, r.Body, maxUploadSize)
|
||||
if err := r.ParseMultipartForm(maxUploadSize); err != nil {
|
||||
errMsg := fmt.Sprintf("File size limit exceeded. The limit is: %d MB",
|
||||
app.cfg.App.MediaMaxSize)
|
||||
http.Error(w, errMsg, http.StatusBadRequest)
|
||||
return nil
|
||||
}
|
||||
|
||||
fileSize := r.ContentLength
|
||||
|
||||
if err := okToEdit(app, w, r); err != nil {
|
||||
return err
|
||||
}
|
||||
vars := mux.Vars(r)
|
||||
slug := vars["slug"]
|
||||
|
||||
if slug == "" {
|
||||
actionId := vars["action"]
|
||||
if actionId == "" {
|
||||
return ErrPostNotFound
|
||||
}
|
||||
var err error
|
||||
slug, err = getSlugFromActionId(app, actionId)
|
||||
if slug == "" || err != nil {
|
||||
return ErrPostNotFound
|
||||
}
|
||||
}
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return nil
|
||||
}
|
||||
file, handler, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
http.Error(w, "Error retrieving the file", http.StatusInternalServerError)
|
||||
return nil
|
||||
}
|
||||
defer file.Close()
|
||||
user := getUserSession(app, r)
|
||||
mediaDirectoryPath := filepath.Join(app.cfg.Server.MediaParentDir, mediaDir,
|
||||
user.Username, slug)
|
||||
err = os.MkdirAll(mediaDirectoryPath, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
totalSize, err := calculateDirectoryTotalSize(mediaDirectoryPath)
|
||||
totalMediaSpace := app.cfg.App.TotalMediaSpace * 1024 * 1024
|
||||
if totalSize + fileSize > totalMediaSpace {
|
||||
errMsg := fmt.Sprintf("Your upload space limit has been exceeded. Your limit is: %d MB",
|
||||
app.cfg.App.TotalMediaSpace)
|
||||
http.Error(w, errMsg, http.StatusBadRequest)
|
||||
return nil
|
||||
}
|
||||
|
||||
newFileName, _ := getNewFileName(mediaDirectoryPath, handler.Filename)
|
||||
newFilePath := filepath.Join(mediaDirectoryPath, newFileName)
|
||||
dst, err := os.Create(newFilePath)
|
||||
if err != nil {
|
||||
http.Error(w, "Error saving the file", http.StatusInternalServerError)
|
||||
return nil
|
||||
}
|
||||
defer dst.Close()
|
||||
_, err = io.Copy(dst, file)
|
||||
if err != nil {
|
||||
http.Error(w, "Error copying the file", http.StatusInternalServerError)
|
||||
return nil
|
||||
}
|
||||
response := map[string]string{
|
||||
"message": "File uploaded successfully!",
|
||||
"path": newFilePath,
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(response)
|
||||
return nil
|
||||
}
|
||||
|
|
35
posts.go
35
posts.go
|
@ -13,6 +13,8 @@ package writefreely
|
|||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"path/filepath"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/writefreely/writefreely/spam"
|
||||
"html/template"
|
||||
|
@ -21,6 +23,7 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
"os"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/guregu/null"
|
||||
|
@ -163,6 +166,7 @@ type (
|
|||
Language sql.NullString
|
||||
OwnerID int64
|
||||
CollectionID sql.NullInt64
|
||||
MediaFilesList []string
|
||||
|
||||
Found bool
|
||||
Gone bool
|
||||
|
@ -650,6 +654,8 @@ func newPost(app *App, w http.ResponseWriter, r *http.Request) error {
|
|||
}
|
||||
collID = coll.ID
|
||||
}
|
||||
slug := getSlugFromPost(*p.Title, *p.Content, p.Language.String)
|
||||
p.Slug = &slug
|
||||
// TODO: return PublicPost from createPost
|
||||
newPost.Post, err = app.db.CreatePost(userID, collID, p)
|
||||
}
|
||||
|
@ -821,6 +827,13 @@ func deletePost(app *App, w http.ResponseWriter, r *http.Request) error {
|
|||
vars := mux.Vars(r)
|
||||
friendlyID := vars["post"]
|
||||
editToken := r.FormValue("token")
|
||||
var err error
|
||||
|
||||
user := getUserSession(app, r)
|
||||
slug, err := getSlugFromActionId(app, friendlyID)
|
||||
if err == nil {
|
||||
deleteMediaFilesOfPost(app, user.Username, slug)
|
||||
}
|
||||
|
||||
var ownerID int64
|
||||
var u *User
|
||||
|
@ -834,7 +847,6 @@ func deletePost(app *App, w http.ResponseWriter, r *http.Request) error {
|
|||
|
||||
var res sql.Result
|
||||
var t *sql.Tx
|
||||
var err error
|
||||
var collID sql.NullInt64
|
||||
var coll *Collection
|
||||
var pp *PublicPost
|
||||
|
@ -933,6 +945,15 @@ func deletePost(app *App, w http.ResponseWriter, r *http.Request) error {
|
|||
return impart.HTTPError{Status: http.StatusNoContent}
|
||||
}
|
||||
|
||||
func deleteMediaFilesOfPost(app *App, username, slug string) {
|
||||
mediaDirectoryPath := filepath.Join(app.cfg.Server.MediaParentDir, mediaDir,
|
||||
username, slug)
|
||||
err := os.RemoveAll(mediaDirectoryPath)
|
||||
if err != nil {
|
||||
log.Error("Deleting media directory of %s failed: %v", username, err)
|
||||
}
|
||||
}
|
||||
|
||||
// addPost associates a post with the authenticated user.
|
||||
func addPost(app *App, w http.ResponseWriter, r *http.Request) error {
|
||||
var ownerID int64
|
||||
|
@ -1325,6 +1346,18 @@ func (p *SubmittedPost) isFontValid() bool {
|
|||
return valid
|
||||
}
|
||||
|
||||
func getSlugFromActionId(app *App, actionID string) (string, error) {
|
||||
var slug string
|
||||
err := app.db.QueryRow("SELECT slug FROM posts WHERE id = ?", actionID).Scan(&slug)
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
return "", errors.New("Post not found")
|
||||
case err != nil:
|
||||
return "", errors.New("Unable to fetch post")
|
||||
}
|
||||
return slug, nil
|
||||
}
|
||||
|
||||
func getRawPost(app *App, friendlyID string) *RawPost {
|
||||
var content, font, title string
|
||||
var isRTL sql.NullBool
|
||||
|
|
|
@ -113,6 +113,10 @@ func InitRoutes(apper Apper, r *mux.Router) *mux.Router {
|
|||
me.HandleFunc("/invites", handler.User(handleViewUserInvites)).Methods("GET")
|
||||
me.HandleFunc("/logout", handler.Web(viewLogout, UserLevelNone)).Methods("GET")
|
||||
|
||||
if apper.App().cfg.App.AllowUploadMedia {
|
||||
write.HandleFunc("/media/{author}/{slug}/{filename}", handler.All(handleGetFile)).Methods("GET")
|
||||
}
|
||||
|
||||
write.HandleFunc("/api/me", handler.All(viewMeAPI)).Methods("GET")
|
||||
apiMe := write.PathPrefix("/api/me/").Subrouter()
|
||||
apiMe.HandleFunc("/", handler.All(viewMeAPI)).Methods("GET")
|
||||
|
@ -203,6 +207,7 @@ func InitRoutes(apper Apper, r *mux.Router) *mux.Router {
|
|||
// All the existing stuff
|
||||
write.HandleFunc(draftEditPrefix+"/{action}/edit", handler.Web(handleViewPad, UserLevelUser)).Methods("GET")
|
||||
write.HandleFunc(draftEditPrefix+"/{action}/meta", handler.Web(handleViewMeta, UserLevelUser)).Methods("GET")
|
||||
write.HandleFunc(draftEditPrefix+"/{action}/meta/mediafile/", handler.Web(handleUploadMedia, UserLevelUser)).Methods("POST")
|
||||
// Collections
|
||||
if apper.App().cfg.App.SingleUser {
|
||||
RouteCollections(handler, write.PathPrefix("/").Subrouter())
|
||||
|
@ -233,6 +238,8 @@ func RouteCollections(handler *Handler, r *mux.Router) {
|
|||
r.HandleFunc("/{slug}", handler.CollectionPostOrStatic)
|
||||
r.HandleFunc("/{slug}/edit", handler.Web(handleViewPad, UserLevelUser))
|
||||
r.HandleFunc("/{slug}/edit/meta", handler.Web(handleViewMeta, UserLevelUser))
|
||||
r.HandleFunc("/{slug}/edit/meta/mediafile/{filename}", handler.Web(handleDeleteFile, UserLevelUser)).Methods("DELETE")
|
||||
r.HandleFunc("/{slug}/edit/meta/mediafile/", handler.Web(handleUploadMedia, UserLevelUser)).Methods("POST")
|
||||
r.HandleFunc("/{slug}/", handler.Web(handleCollectionPostRedirect, UserLevelReader)).Methods("GET")
|
||||
}
|
||||
|
||||
|
|
|
@ -265,10 +265,83 @@
|
|||
</dl>
|
||||
<input type="hidden" name="web" value="true" />
|
||||
</form>
|
||||
|
||||
<dt><label>Media Files List</label></dt></br>
|
||||
<ul id="mediaFilesList"></ul>
|
||||
|
||||
<form id="uploadForm">
|
||||
<input type="file" id="fileInput" />
|
||||
<button type="button" onclick="uploadFile()">Upload</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="/js/h.js"></script>
|
||||
|
||||
<script>
|
||||
function uploadFile() {
|
||||
const fileInput = document.getElementById('fileInput');
|
||||
const file = fileInput.files[0];
|
||||
if (!file) {
|
||||
alert('Please select a file to upload.');
|
||||
return;
|
||||
}
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
const url = "meta/mediafile/"
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
}).then(response => response.json())
|
||||
.then(data => {
|
||||
alert('File uploaded successfully, path: /' + data.path);
|
||||
location.reload();
|
||||
}).catch(error => {
|
||||
alert('An error occurred during file upload.');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function getFileNameFromPath(filePath) {
|
||||
const parts = filePath.split("/");
|
||||
return parts.pop();
|
||||
}
|
||||
|
||||
function postDeleteMediafile(fileName) {
|
||||
const url = "meta/mediafile/" + fileName;
|
||||
fetch(url, {
|
||||
method: 'DELETE',
|
||||
headers: {},
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
console.error(response);
|
||||
} else {
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const valueListElement = document.getElementById("mediaFilesList");
|
||||
{{.Post.MediaFilesList}}.forEach((value) => {
|
||||
const listItemElement = document.createElement("li");
|
||||
listItemElement.textContent = value;
|
||||
valueListElement.appendChild(listItemElement);
|
||||
const buttonElement = document.createElement("button");
|
||||
buttonElement.textContent = "Remove";
|
||||
buttonElement.addEventListener("click", () => {
|
||||
const confirmResult = confirm("Are you sure to remove: " + value + "?");
|
||||
if (confirmResult) {
|
||||
fileName = getFileNameFromPath(value)
|
||||
postDeleteMediafile(fileName);
|
||||
} else {}
|
||||
});
|
||||
listItemElement.appendChild(buttonElement);
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function updateMeta() {
|
||||
if ({{.Silenced}}) {
|
||||
alert("Your account is silenced, so you can't edit posts.");
|
||||
|
|
Loading…
Reference in New Issue