2023-11-21 04:10:40 +00:00
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
2024-06-26 15:33:47 +00:00
handleInternalServerError ( err )
2023-11-21 04:10:40 +00:00
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
2024-06-26 15:33:47 +00:00
handleInternalServerError ( err )
2023-11-21 04:10:40 +00:00
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
2024-06-26 15:33:47 +00:00
handleInternalServerError ( err )
2023-11-21 04:10:40 +00:00
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
2024-06-26 15:33:47 +00:00
handleInternalServerError ( err )
2023-11-21 04:10:40 +00:00
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
2024-06-26 15:33:47 +00:00
handleInternalServerError ( err )
2023-11-21 04:10:40 +00:00
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
2024-06-26 17:49:20 +00:00
Files [ ] File
2023-11-21 04:10:40 +00:00
} {
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
}
2024-06-26 17:49:20 +00:00
destFile . Close ( )
2023-11-21 04:10:40 +00:00
// 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 )
2024-06-26 17:49:20 +00:00
http . Error ( w , "Internal Server Error when inserting file into database" , http . StatusInternalServerError )
2023-11-21 04:10:40 +00:00
return
}
}
2024-06-26 17:49:20 +00:00
http . Redirect ( w , r , "/home?success=1" , http . StatusSeeOther )
2023-11-21 04:10:40 +00:00
}
}
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 {
2024-06-26 15:33:47 +00:00
http . Error ( w , "Bad Request, make an issue at https://git.privacyquest.net" , http . StatusBadRequest )
2023-11-21 04:10:40 +00:00
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 )
}
}