package main import ( "database/sql" "encoding/json" "fmt" "io" "log" "net/http" "os" "path/filepath" "strings" "time" ) func ListFiles(w http.ResponseWriter, r *http.Request) { userSession, err := validateSession(w, r) if err != nil { // Handle the error as needed handleInternalServerError(err) return } userFolder := filepath.Join(fileUploadPath, userSession.username) successParam := r.URL.Query().Get("success") successMessage := "" if successParam == "1" { successMessage = "Upload was successful!" } if successParam == "2" { successMessage = "File creation was successful!" } // Open the user's directory userDir, err := os.Open(userFolder) if err != nil { if os.IsNotExist(err) { // Directory does not exist, create it log.Println(userSession.username + "'s directory does not exist. Creating it!") createUserFolder(userSession.username) // Open the newly created user directory userDir, err = os.Open(userFolder) if err != nil { log.Printf("Error opening user directory: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } } else { // Other error occurred while opening the directory log.Printf("Error opening user directory: %v", err) // Handle the error as needed handleInternalServerError(err) return } } defer userDir.Close() // Read the names of files in the directory fileNames, err := userDir.Readdirnames(-1) if err != nil { log.Printf("Error reading file names in directory: %v", err) // Handle the error as needed handleInternalServerError(err) return } type File struct { Filename string CreationTime int64 LastEdited int64 } var files []File for _, fileName := range fileNames { if strings.HasSuffix(fileName, ".html") || strings.HasSuffix(fileName, ".md") { file := File{ Filename: fileName, } userUUID, err := getUserUUID(userSession.username) if err != nil { log.Printf("Error getting user UUID: %v", err) // Handle the error as needed handleInternalServerError(err) return } err = db.QueryRow("SELECT EXTRACT(epoch FROM creation_time)::bigint, EXTRACT(epoch FROM last_edited)::bigint FROM files WHERE user_id = $1 AND filename = $2", userUUID, fileName).Scan(&file.CreationTime, &file.LastEdited) if err == sql.ErrNoRows { // No rows found, handle the case as needed log.Printf("No rows found for file: %s", fileName) currentTime := time.Now().Unix() err = insertFileIntoDatabase(userSession.username, fileName, currentTime, currentTime, currentTime) if err != nil { log.Printf("Error inserting file into the database: %v", err) // Handle the error as needed handleInternalServerError(err) return } http.Redirect(w, r, "/home", http.StatusSeeOther) // Redirect or do something else return } else if err != nil { log.Printf("Error retrieving file timestamps from the database: %v", err) log.Printf("Asking %s to create a new file", userSession.username) http.Redirect(w, r, "/welcome", http.StatusSeeOther) return } files = append(files, file) } } name, err := getName(userSession.username) if err != nil { log.Printf("Error retrieving preferred name from the database: %v", err) } data := struct { Username string SuccessMessage string Files []File }{ Username: name, Files: files, SuccessMessage: successMessage, } renderTemplate(w, "list.html", data) } func UploadFile(w http.ResponseWriter, r *http.Request) { userSession, err := validateSession(w, r) if err != nil { // Handle the error as needed return } if r.Method == http.MethodPost { reader, err := r.MultipartReader() if err != nil { log.Printf("Error creating multipart reader: %v", err) http.Error(w, "Bad Request", http.StatusBadRequest) return } for { part, err := reader.NextPart() if err == io.EOF { break } if err != nil { log.Printf("Error reading part: %v", err) http.Error(w, "Bad Request", http.StatusBadRequest) return } // Check the file extension to allow only .md or .html files fileExt := filepath.Ext(part.FileName()) if fileExt != ".md" && fileExt != ".html" { log.Printf("Invalid file format: %s", part.FileName()) http.Error(w, "Invalid File Format. Only .md and .html files are allowed.", http.StatusBadRequest) return } userFolder := filepath.Join(fileUploadPath, userSession.username) // Generate a unique filename by appending sequential numbers if needed filename := part.FileName() count := 1 for { filePath := filepath.Join(userFolder, filename) if _, err := os.Stat(filePath); os.IsNotExist(err) { break } filename = fmt.Sprintf("%s_%d%s", strings.TrimSuffix(part.FileName(), filepath.Ext(part.FileName())), count, filepath.Ext(part.FileName())) count++ } // Save the file to disk in the user's folder filePath := filepath.Join(userFolder, filename) destFile, err := os.Create(filePath) if err != nil { log.Printf("Error creating destination file: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } _, err = io.Copy(destFile, part) if err != nil { log.Printf("Error saving file to disk: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } destFile.Close() // Insert the file record into the database with creation time currentTime := time.Now().Unix() err = insertFileIntoDatabase(userSession.username, filename, currentTime, currentTime, currentTime) if err != nil { log.Printf("Error inserting file into database: %v", err) http.Error(w, "Internal Server Error when inserting file into database", http.StatusInternalServerError) return } } http.Redirect(w, r, "/home?success=1", http.StatusSeeOther) } } func createNewFile(w http.ResponseWriter, r *http.Request) { userSession, err := validateSession(w, r) if err != nil { // Handle the error as needed return } // Parse the form data to obtain the filename if err := r.ParseForm(); err != nil { http.Error(w, "Bad Request", http.StatusBadRequest) return } filename := r.FormValue("newFileName") // Ensure the file has the ".md" extension if !strings.HasSuffix(filename, ".md") { filename += ".md" } // Construct the file path userFolder := filepath.Join(fileUploadPath, userSession.username) filePath := filepath.Join(userFolder, filename) // Check if the file already exists if _, err := os.Stat(filePath); !os.IsNotExist(err) { // File with the same name already exists http.Error(w, "File already exists", http.StatusConflict) return } // Create and open the file for writing file, err := os.Create(filePath) if err != nil { log.Printf("Error creating file: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } defer file.Close() // Insert the file record into the database with creation time currentTime := time.Now().Unix() err = insertFileIntoDatabase(userSession.username, filename, currentTime, currentTime, currentTime) if err != nil { log.Printf("Error inserting file into the database: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } // Redirect to editing the newly created file http.Redirect(w, r, "/edit?filename="+filename, http.StatusSeeOther) } func DeleteFiles(w http.ResponseWriter, r *http.Request) { userSession, err := validateSession(w, r) if err != nil { // Handle the error as needed return } if r.Method == http.MethodPost { // Parse the JSON request body to get the list of files to delete var request struct { Files []string `json:"files"` } // Print the list of files to delete for _, filename := range request.Files { fmt.Println("File to delete:", filename) } if err := json.NewDecoder(r.Body).Decode(&request); err != nil { http.Error(w, "Bad Request, make an issue at https://git.privacyquest.net", http.StatusBadRequest) return } // Delete each selected file from the database and the filesystem for _, filename := range request.Files { userFolder := filepath.Join(fileUploadPath, userSession.username) filePath := filepath.Join(userFolder, filename) // Delete the file from the database if err := deleteFileFromDatabase(userSession.username, filename); err != nil { // Handle the error as needed log.Printf("Error deleting file record: %v", err) } // Delete the file from the filesystem if err := os.Remove(filePath); err != nil { // Handle the error as needed log.Printf("Error deleting file from filesystem: %v", err) } } // Send a success response w.WriteHeader(http.StatusOK) } } func makeFolder(folderPath string) error { err := os.MkdirAll(folderPath, os.ModePerm) if err != nil { return err } return nil } func createUserFolder(username string) { userFolder := filepath.Join(fileUploadPath, username) err := makeFolder(userFolder) if err != nil { log.Printf("Error creating user folder: %v", err) } }