diff --git a/.env b/.env new file mode 100644 index 0000000000000000000000000000000000000000..6a1ca89e91d03b60218f83ce831a863a25da2331 --- /dev/null +++ b/.env @@ -0,0 +1,5 @@ +MONGO_URI=mongodb+srv://secapp-tp:hepiaschooltp@cluster0.pkjspwr.mongodb.net/ +#MONGO_URI=mongodb+srv://yug:HUDDwcbVSuDzmDXG@cluster0.ttzwnxf.mongodb.net/ +SENDGRID_API_KEY=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 +SMTP_FROM_ADDRESS=notifications@mstd.dansmonorage.blue +PORT=5500 diff --git a/main.go b/main.go index efa8205ebe693a74d6f8151a2895689a7c0fae23..a22e9303ae5f1679c9be84b7cb1a3e52f0d09702 100644 --- a/main.go +++ b/main.go @@ -12,15 +12,20 @@ import ( "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/bson/primitive" "strconv" "time" "github.com/go-gomail/gomail" "io" "mime/multipart" + "encoding/json" + "strings" ) var usersCollection *mongo.Collection var postsCollection *mongo.Collection +var privateMessagesCollection *mongo.Collection +var tokensCollection *mongo.Collection var URI string var messages []models.Post var err error @@ -341,6 +346,7 @@ func main() { fmt.Println("Connected successfully") usersCollection = client.Database("authentication").Collection("users") postsCollection = client.Database("mydb").Collection("messages") + privateMessagesCollection = client.Database("mydb").Collection("private_messages") fs := http.FileServer(http.Dir("./view")) http.Handle("/", fs) http.HandleFunc("/signin", signInHandler) @@ -350,12 +356,511 @@ func main() { http.HandleFunc("/reset-password", handlePasswordReset) http.HandleFunc("/post", handlePost) http.HandleFunc("/messages", messagesHandler) + http.HandleFunc("/editbyadmin", editbyAdminHandler) http.HandleFunc("/edit", editHandler) http.HandleFunc("/admin", adminHandler) http.HandleFunc("/delete", deleteHandler) + http.HandleFunc("/admin-change-password", adminChangePasswordHandler) + http.HandleFunc("/private-messages", privateMessagesHandler) + http.HandleFunc("/send-private-message", sendPrivateMessageHandler) + + http.HandleFunc("/api/messages", messagesAPIHandler) + http.HandleFunc("/api/message/", IDmessagesAPIHandler) + http.HandleFunc("/api/message", postPublicMessageHandler) + http.HandleFunc("/generate-api-token", generateAPITokenHandler) + log.Fatal(http.ListenAndServe(":5500", nil)) } +func postPublicMessageHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + // Check the XAPITOKEN header + token := r.Header.Get("XAPITOKEN") + if token == "" { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + // Verify the API token + var result struct { + Username string `bson:"username"` + IsAdmin string `bson:"is_admin"` + } + // Connect to the MongoDB database + clientOptions := options.Client().ApplyURI(URI) + client, err := mongo.Connect(context.Background(), clientOptions) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer client.Disconnect(context.Background()) + + tokensCollection = client.Database("Token").Collection("tokens") + err = tokensCollection.FindOne(context.Background(), bson.M{"token": token}).Decode(&result) + if err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + // Check if the user is the token owner + fmt.Println("printing result") + fmt.Println(result) + + // Get the message data from the REST request body + + /*var message models.Post + err = json.NewDecoder(r.Body).Decode(&message) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + }*/ + message := r.FormValue("message") + // Create a document that contains the message + doc := bson.M{"message": message} + // Insert the message into the database + postsCollection = client.Database("mydb").Collection("messages") + _, err = postsCollection.InsertOne(context.Background(), doc) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +func IDmessagesAPIHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + // Get the message ID from the URL + idStr := strings.TrimPrefix(r.URL.Path, "/api/message/") + // Convert the string ID to an ObjectID + id, err := primitive.ObjectIDFromHex(idStr) + if err != nil { + http.Error(w, "Invalid ID", http.StatusBadRequest) + return + } + fmt.Println("printing id") + fmt.Println(id) + // Check the XAPITOKEN header + token := r.Header.Get("XAPITOKEN") + if token == "" { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + // Verify the API token + var result struct { + Username string `bson:"username"` + IsAdmin string `bson:"is_admin"` + } + // Connect to the MongoDB database + clientOptions := options.Client().ApplyURI(URI) + client, err := mongo.Connect(context.Background(), clientOptions) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer client.Disconnect(context.Background()) + + tokensCollection = client.Database("Token").Collection("tokens") + err = tokensCollection.FindOne(context.Background(), bson.M{"token": token}).Decode(&result) + if err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + + // Check if the user is not an admin + var message bson.M + if result.IsAdmin == "false" { + // check if the message id is that of the user and its token + err := privateMessagesCollection.FindOne(context.Background(), bson.M{"_id": id}).Decode(&message) + fmt.Println("printing message") + fmt.Println(message) + if err != nil { + return + } + if message["sender"] != result.Username && message["receiver"] != result.Username { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + + return + } + // return the message + err = json.NewEncoder(w).Encode(message) + return + } + // if the user is an admin return the message + err = privateMessagesCollection.FindOne(context.Background(), bson.M{"_id": id}).Decode(&message) + if err != nil { + return + } + fmt.Println("printing message") + fmt.Println(message) + err = json.NewEncoder(w).Encode(message) + +} + +func getMessage(client *mongo.Client, messageID string) (bson.M, error) { + messagesCollection := client.Database("yourDatabase").Collection("messages") + + var message bson.M + err := messagesCollection.FindOne(context.Background(), bson.M{"_id": messageID}).Decode(&message) + if err != nil { + return nil, err + } + + return message, nil +} + +func messagesAPIHandler(w http.ResponseWriter, r *http.Request) { + // Handle the API request here + if r.Method != http.MethodGet { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + + // Check the XAPITOKEN header + token := r.Header.Get("XAPITOKEN") + + if token == "" { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + + // Verify the API token + var result struct { + Username string `bson:"username"` + IsAdmin string `bson:"is_admin"` + } + // Connect to the MongoDB database + clientOptions := options.Client().ApplyURI(URI) + client, err := mongo.Connect(context.Background(), clientOptions) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer client.Disconnect(context.Background()) + + tokensCollection = client.Database("Token").Collection("tokens") + err = tokensCollection.FindOne(context.Background(), bson.M{"token": token}).Decode(&result) + if err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + fmt.Println("printing result") + fmt.Println(result) + fmt.Println("token is not empty") + // Check if the user is an admin + if result.IsAdmin != "false" { + // Retrieve all messages from the database if the user is an admin + fmt.Println("I am not an admin") + messages, err := getAllPrivateMessagesAdmin() + fmt.Println("printing messages") + fmt.Println(messages) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + // send the messages back to the user RESTfully + err = json.NewEncoder(w).Encode(messages) + } + // Retrieve the user's messages from the database if the user is not an admin + messages, err := getAllPrivateMessages(result.Username) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + // send the messages back to the user RESTfully + err = json.NewEncoder(w).Encode(messages) + +} + +func getAllPrivateMessagesAdmin() ([]models.PrivateMessage, error) { + fmt.Println("Entered getAllPrivateMessagesAdmin") + // Connect to the MongoDB database + clientOptions := options.Client().ApplyURI(URI) + client, err := mongo.Connect(context.Background(), clientOptions) + if err != nil { + return nil, err + } + defer client.Disconnect(context.Background()) + + // Retrieve all private messages from the database + var messages []models.PrivateMessage + cursor, err := privateMessagesCollection.Find(context.Background(), bson.M{}) + if err != nil { + return nil, err + } + defer cursor.Close(context.Background()) + for cursor.Next(context.Background()) { + var message models.PrivateMessage + err := cursor.Decode(&message) + if err != nil { + return nil, err + } + messages = append(messages, message) + } + fmt.Println("printing messages from getAllPrivateMessagesAdmin") + fmt.Println(messages) + return messages, nil +} + +func generateAPIToken(username string) string { + // Get the current time + now := time.Now() + + // Combine the username and the current time to create the token + token := fmt.Sprintf("%s_%d", username, now.Unix()) + + return token +} + +func generateAPITokenHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + // Get the username from the cookie + cookie, err := r.Cookie("username") + if err != nil { + http.Redirect(w, r, "/signin", http.StatusSeeOther) + return + } + username := cookie.Value + var isAdmin string = "false" + + // Generate a new API token + token := generateAPIToken(username) + // Connect to the MongoDB database + clientOptions := options.Client().ApplyURI(URI) + client, err := mongo.Connect(context.Background(), clientOptions) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer client.Disconnect(context.Background()) + + // Check if the user is an admin + user, err := getUser(username) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if user.Role != "admin" { + isAdmin = "false" + } else { + isAdmin = "true" + } + + // Save the API token to the MongoDB database + tokensCollection := client.Database("Token").Collection("tokens") + // Delete the user's old API token from the database if it exists + _, err = tokensCollection.DeleteOne(context.Background(), bson.M{"username": username}) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Insert the token into the database + _, err = tokensCollection.InsertOne(context.TODO(), map[string]string{ + "username": username, + "token": token, + "is_admin": isAdmin, + }) + + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Display the API token to the user + w.Write([]byte("Your new API token is: " + token)) +} + +func privateMessagesAPIHandler(w http.ResponseWriter, r *http.Request) { + // Handle the API request here + +} + +func privateMessagesHandler(w http.ResponseWriter, r *http.Request) { + // Get the username from the cookie + cookie, err := r.Cookie("username") + if err != nil { + http.Redirect(w, r, "/signin", http.StatusSeeOther) + return + } + username := cookie.Value + + // Get the private messages from the database + messages, err := getAllPrivateMessages(username) + fmt.Println("printing messages") + fmt.Println(messages) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + // Convert the Content field to template.HTML + for i := range messages { + messages[i].Content = template.HTML(messages[i].Content) + } + // Create a data structure to hold the messages + data := struct { + PrivateMessages []models.PrivateMessage + }{ + PrivateMessages: messages, + } + + // Render the DM.html page + tmpl := template.Must(template.ParseFiles("view/DM.html")) + tmpl.Execute(w, data) +} + +func getAllPrivateMessages(username string) ([]models.PrivateMessage, error) { + // Connect to the MongoDB database + clientOptions := options.Client().ApplyURI(URI) + client, err := mongo.Connect(context.Background(), clientOptions) + if err != nil { + return nil, err + } + defer client.Disconnect(context.Background()) + + // Retrieve all private messages from the database + var messages []models.PrivateMessage + cursor, err := privateMessagesCollection.Find(context.Background(), bson.M{"$or": []bson.M{ + bson.M{"sender": username}, + bson.M{"receiver": username}, + }}) + if err != nil { + return nil, err + } + defer cursor.Close(context.Background()) + for cursor.Next(context.Background()) { + var message models.PrivateMessage + err := cursor.Decode(&message) + if err != nil { + return nil, err + } + messages = append(messages, message) + } + + return messages, nil +} +func getPrivateMessages(username string) ([]models.PrivateMessage, error) { + // Connect to the MongoDB database + clientOptions := options.Client().ApplyURI(URI) + client, err := mongo.Connect(context.Background(), clientOptions) + if err != nil { + return nil, err + } + defer client.Disconnect(context.Background()) + + // Retrieve all private messages from the database + var messages []models.PrivateMessage + cursor, err := privateMessagesCollection.Find(context.Background(), bson.M{"$or": []bson.M{ + bson.M{"sender": username}, + bson.M{"receiver": username}, + }}) + if err != nil { + return nil, err + } + defer cursor.Close(context.Background()) + for cursor.Next(context.Background()) { + var message models.PrivateMessage + err := cursor.Decode(&message) + if err != nil { + return nil, err + } + messages = append(messages, message) + } + + return messages, nil +} + +func sendPrivateMessage(sender, receiver, content string) error { + // Create a new private message object + message := models.PrivateMessage{ + Sender: sender, + Receiver: receiver, + Content: template.HTML(content), + Timestamp: time.Now(), + } + + // Connect to the MongoDB database + clientOptions := options.Client().ApplyURI(URI) + client, err := mongo.Connect(context.Background(), clientOptions) + if err != nil { + return err + } + defer client.Disconnect(context.Background()) + + // Insert the message into the database + _, err = privateMessagesCollection.InsertOne(context.Background(), message) + if err != nil { + return err + } + + return nil +} + +func sendPrivateMessageHandler(w http.ResponseWriter, r *http.Request) { + // Get the username from the cookie + cookie, err := r.Cookie("username") + if err != nil { + http.Redirect(w, r, "/signin", http.StatusSeeOther) + return + } + sender := cookie.Value + + // Get the receiver and content from the form data + receiver := r.FormValue("receiver") + content := r.FormValue("content") + + // Send the private message + err = sendPrivateMessage(sender, receiver, content) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Redirect the user back to the private messages page + http.Redirect(w, r, "/private-messages", http.StatusSeeOther) +} + +func adminChangePasswordHandler(w http.ResponseWriter, r *http.Request) { + // Check if the user is an admin + cookie, err := r.Cookie("username") + if err != nil { + http.Redirect(w, r, "/signin", http.StatusSeeOther) + return + } + username := cookie.Value + user, err := getUser(username) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if user.Role != "admin" { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + + // Get the username and password from the form data + usernameToChange := r.FormValue("username") + password := r.FormValue("password") + + // Update the user's password in the database + _,err = updateEmailAndPassword(usernameToChange, "", password) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Redirect the user back to the admin page + http.Redirect(w, r, "/admin", http.StatusSeeOther) +} + //deleteUser function func deleteUser(username string) error { @@ -679,6 +1184,163 @@ func saveAvatarFile(username, filename string, file multipart.File) error { return nil } +// create updateEmailAndPassword +func updateEmailAndPassword(username, email, password string) (models.User, error) { + // Connect to the MongoDB database + clientOptions := options.Client().ApplyURI(URI) + client, err := mongo.Connect(context.Background(), clientOptions) + if err != nil { + return models.User{}, err + } + defer client.Disconnect(context.Background()) + + // Update the user's avatar URL in the database + _, err = usersCollection.UpdateOne(context.Background(), bson.M{"username": username}, bson.M{"$set": bson.M{"email": email, "password": password}}) + if err != nil { + return models.User{}, err + } + + user, err:= getUser(username) + if(err != nil) { + return models.User{}, err + } + user.Email = email + user.Password = password + + + return user, nil +} + +func editbyAdminHandler(w http.ResponseWriter, r *http.Request) { + // Check if the user is an admin + cookie, err := r.Cookie("username") + if err != nil { + http.Redirect(w, r, "/signin", http.StatusSeeOther) + return + } + username := cookie.Value + user, err := getUser(username) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if user.Role != "admin" { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + + // Get the username, email, and password from the form data + usernameToUpdate := r.FormValue("username") + email := r.FormValue("email") + password := r.FormValue("password") + + // Update the email and password of the user in the database + _,err = updateEmailAndPassword(usernameToUpdate, email, password) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Redirect the user back to the admin page + http.Redirect(w, r, "/admin", http.StatusSeeOther) +} + +func editbyAdminHandler_old(w http.ResponseWriter, r *http.Request) { + // Check if the user is an admin + cookie, err := r.Cookie("username") + if err != nil { + http.Redirect(w, r, "/signin", http.StatusSeeOther) + return + } + username := cookie.Value + user, err := getUser(username) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if user.Role != "admin" { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + + // Get the username to delete from the form data + usernameToEdit := r.FormValue("username") + + + // Edit the user from the database + userEdit, err := getUser(usernameToEdit) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Handle form submission + if r.Method == "POST" { + // Parse the form data + err := r.ParseMultipartForm(32 << 20) // 32 MB + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Update the user's information in the database + userEdit.FullName = r.FormValue("fullname") + userEdit.Email = r.FormValue("email") + userEdit.Age, err = strconv.Atoi(r.FormValue("age")) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + userEdit.Bio = r.FormValue("bio") + userEdit.Role = r.FormValue("role") + err = updateUser(userEdit) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Upload the new avatar file (if provided) + file, handler, err := r.FormFile("avatar") + if err == nil { + defer file.Close() + + // Save the file to disk + err = saveAvatarFile(userEdit.Username, handler.Filename, file) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Update the user's avatar URL in the database + userEdit.Avatar = fmt.Sprintf("/uploads/%s/%s", userEdit.Username, handler.Filename) + err = updateUser(userEdit) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } + + } + + // Render the edit page with the user's information + tmpl, err := template.ParseFiles("./view/edit.html") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + err = tmpl.Execute(w, struct { + User models.User + }{ + User: user, + }) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Redirect the user back to the admin page + http.Redirect(w, r, "/admin", http.StatusSeeOther) +} func editHandler(w http.ResponseWriter, r *http.Request) { // Get the user's username from the cookie @@ -817,8 +1479,7 @@ func getUserMessages(username string) ([]models.Post, error) { messages = append(messages, message) } - fmt.Println("printing messages from user" + username) - fmt.Println(messages) + return messages, nil diff --git a/models/attachment.go b/models/attachment.go new file mode 100644 index 0000000000000000000000000000000000000000..3f6f92aef8579cae950817e214e65a9a079f4833 --- /dev/null +++ b/models/attachment.go @@ -0,0 +1,11 @@ +package models + +import ( + "go.mongodb.org/mongo-driver/bson/primitive" +) + +type Attachment struct { + ID primitive.ObjectID `bson:"_id,omitempty"` + PostID primitive.ObjectID `bson:"postid"` + Description *string `json:"description"` +} diff --git a/models/private_message.go b/models/private_message.go new file mode 100644 index 0000000000000000000000000000000000000000..d57b132fede627ccb81b7076bd0fe6f30c5af439 --- /dev/null +++ b/models/private_message.go @@ -0,0 +1,14 @@ +package models + +import ( + "time" + "html/template" +) + +type PrivateMessage struct { + ID string `bson:"_id,omitempty"` + Sender string `bson:"sender"` + Receiver string `bson:"receiver"` + Content template.HTML `bson:"content"` + Timestamp time.Time `bson:"timestamp"` +} \ No newline at end of file diff --git a/output b/output new file mode 100755 index 0000000000000000000000000000000000000000..af9ba38241307c9d14cc480e33b32b58495ef669 Binary files /dev/null and b/output differ diff --git a/uploads/admin_rom.jpeg b/uploads/admin_rom.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..00eeca5138c54a4135aebb357c98d8885eec6acf Binary files /dev/null and b/uploads/admin_rom.jpeg differ diff --git a/uploads/testoo_hug-difficult.png b/uploads/testoo_hug-difficult.png new file mode 100644 index 0000000000000000000000000000000000000000..9e68b32495f5a850c444b967f3d22ce9f3dcc21a Binary files /dev/null and b/uploads/testoo_hug-difficult.png differ diff --git a/view/DM.html b/view/DM.html new file mode 100644 index 0000000000000000000000000000000000000000..2263ddcf4e199e7c8ff1bf072c6cadb7eec4aecd --- /dev/null +++ b/view/DM.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> + +<head> + <title>Direct Messages</title> +</head> + +<body> + <h1>Direct Messages</h1> + <form method="POST" action="/send-private-message"> + <label for="receiver">To:</label> + <input type="text" name="receiver" required><br> + <label for="content">Message:</label> + <textarea name="content" required></textarea><br> + <button type="submit">Send</button> + </form> + <h2>Your Messages</h2> + <ul> + {{range .PrivateMessages}} + <li> + <p>From: {{.Sender}} To: {{.Receiver}}</p> + <p>Message: {{.Content}}</p> + <p>Time: {{.Timestamp}}</p> + </li> + {{end}} + </ul> + <a href="/profile">Back to Profile</a> +</body> + +</html> \ No newline at end of file diff --git a/view/admin.html b/view/admin.html new file mode 100644 index 0000000000000000000000000000000000000000..6767df189a47761d8d991ee2a3a4ca7a086c6c74 --- /dev/null +++ b/view/admin.html @@ -0,0 +1,37 @@ +<!DOCTYPE html> +<html> + +<head> + <title>Admin</title> +</head> + +<body> + <h1>Admin</h1> + <table> + <thead> + <tr> + <th>Username</th> + <th>Email</th> + <th>IsAdmin</th> + <th>Actions</th> + </tr> + </thead> + <tbody> + {{range .Users}} + <tr> + <td>{{.Username}}</td> + <td>{{.Email}}</td> + <td>{{.Role}}</td> + <td> + <a href="/editbyadmin?username={{.Username}}">Edit</a> + <a href="/delete?username={{.Username}}">Delete/Disable</a> + <a href="/reset?username={{.Username}}">Reset Password</a> + </td> + </tr> + {{end}} + </tbody> + </table> + <a href="/profile">Back to Home</a> +</body> + +</html> \ No newline at end of file diff --git a/view/delete.html b/view/delete.html new file mode 100644 index 0000000000000000000000000000000000000000..7064a79c0c8e85d617dbcab4be10e00b348f5d38 --- /dev/null +++ b/view/delete.html @@ -0,0 +1,37 @@ +<!DOCTYPE html> +<html> + +<head> + <title>Admin</title> +</head> + +<body> + <h1>Admin</h1> + <table> + <thead> + <tr> + <th>Username</th> + <th>Email</th> + <th>IsAdmin</th> + <th>Actions</th> + </tr> + </thead> + <tbody> + {{range .Users}} + <tr> + <td>{{.Username}}</td> + <td>{{.Email}}</td> + <td>{{.IsAdmin}}</td> + <td> + <a href="/edit?username={{.Username}}">Edit</a> + <a href="/delete?username={{.Username}}">Delete/Disable</a> + <a href="/reset?username={{.Username}}">Reset Password</a> + </td> + </tr> + {{end}} + </tbody> + </table> + <a href="/">Back to Home</a> +</body> + +</html> \ No newline at end of file diff --git a/view/edit.html b/view/edit.html new file mode 100644 index 0000000000000000000000000000000000000000..7179c0355c25625ad3a9e7418abb6c7e3d0efa97 --- /dev/null +++ b/view/edit.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> + +<head> + <title>Edit Profile</title> +</head> + +<body> + <h1>Edit Profile</h1> + <form action="/edit" method="post" enctype="multipart/form-data"> + <label for="fullname">Full Name:</label> + <input type="text" id="fullname" name="fullname" value="{{.User.FullName}}"><br><br> + <label for="email">Email:</label> + <input type="email" id="email" name="email" value="{{.User.Email}}"><br><br> + <label for="avatar">Avatar:</label> + <input type="file" id="avatar" name="avatar"><br><br> + <input type="submit" value="Save"> + </form> +</body> + +</html> \ No newline at end of file diff --git a/view/editbyadmin.html b/view/editbyadmin.html new file mode 100644 index 0000000000000000000000000000000000000000..2cdf7144b3857009b6b0c51338ba37baa5ec7f96 --- /dev/null +++ b/view/editbyadmin.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> + +<head> + <title>Edit User by Admin</title> +</head> + +<body> + <h1>Edit User by Admin</h1> + <form method="POST" action="/editbyadmin"> + <input type="hidden" name="username" value="{{.Username}}"> + <label for="email">Email:</label> + <input type="email" name="email" value="{{.Email}}" required><br> + <label for="password">New Password:</label> + <input type="password" name="password" required><br> + <button type="submit">Save</button> + <a href="/admin">Cancel</a> + </form> +</body> + +</html> \ No newline at end of file diff --git a/view/generate_API.html b/view/generate_API.html new file mode 100644 index 0000000000000000000000000000000000000000..9b6d75702e6bc746e06c61e0a0d07bf6dba352c9 --- /dev/null +++ b/view/generate_API.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> + +<head> + <title>Generate API Token</title> +</head> + +<body> + <h1>Your API Token</h1> + <p id="token"></p> + <button onclick="generateAPIToken()">Generate API Token</button> + + <script> + function generateAPIToken() { + fetch('/api/generate-token', { + method: 'GET', + credentials: 'include', // Include cookies + }) + .then(response => response.text()) + .then(token => { + document.getElementById('token').textContent = 'Your new API token is: ' + token; + }) + .catch(error => { + console.error('Error:', error); + }); + } + </script> +</body> + +</html> \ No newline at end of file diff --git a/view/messages.html b/view/messages.html new file mode 100644 index 0000000000000000000000000000000000000000..858481df7d3ff7d3a473fc08bc0745819391715a --- /dev/null +++ b/view/messages.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> + +<head> + <title>Messages</title> +</head> + + +<body> + <h1>Messages</h1> + <ul> + {{range .Messages}} + <li>{{.Title}}</li> + <p>{{.Content}}</p> + <p>{{.Username}}</p> + <p>{{.CreatedAt}}</p> + {{end}} + </ul> + <a href="/profile">Back to Profile</a> +</body> + +</html> \ No newline at end of file diff --git a/view/profile.html b/view/profile.html index 727589aed683c6f4f088e36462f618964664e18a..104ab2ed1a0e82a17df7006ac5114c50d7de3d6c 100644 --- a/view/profile.html +++ b/view/profile.html @@ -109,12 +109,14 @@ <a href="/messages">Messages</a> <h2>Avatar</h2> {{if .User.Avatar}} - <img src="/uploads/{{.User.Avatar}}" alt="avatar" class="profile-photo"> + <img src="/uploads/" {{.User.Avatar}} alt="avatar" class="profile-photo"> {{else}} <img src="https://mstd.dansmonorage.blue/system/site_uploads/files/000/000/002/original/mascot.png" alt="avatar" class="profile-photo"> {{end}} <a href="/edit?username={{.User.Username}}">EditProfile</a> + <a href="/generate-api-token">Generate API Token</a> + <a href="/admin">Admin</a>