changes
This commit is contained in:
parent
feab14a5be
commit
890fa31ed4
BIN
chatserver
Normal file
BIN
chatserver
Normal file
Binary file not shown.
@ -114,6 +114,32 @@ body {
|
|||||||
right: calc(30%);
|
right: calc(30%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-button {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--timestamp-color);
|
||||||
|
padding: 2px 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message:hover .delete-button {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-button:hover {
|
||||||
|
background: var(--pum-button-inactive-fg);
|
||||||
|
}
|
||||||
|
|
||||||
.settings-icon, .users-icon, .theme-icon{
|
.settings-icon, .users-icon, .theme-icon{
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
function toggleSettings() {
|
function toggleSettings() {
|
||||||
const panel = document.getElementById("settings-panel");
|
const panel = document.getElementById("settings-panel");
|
||||||
panel.style.display = panel.style.display === "none" ? "block" : "none";
|
panel.style.display = panel.style.display === "block"
|
||||||
|
? "none"
|
||||||
|
: "block";
|
||||||
if (panel.style.display === "block") {
|
if (panel.style.display === "block") {
|
||||||
const username = document.getElementById("username");
|
const username = document.getElementById("username");
|
||||||
username.focus();
|
username.focus();
|
||||||
@ -11,7 +13,9 @@ function toggleSettings() {
|
|||||||
|
|
||||||
function toggleUsers() {
|
function toggleUsers() {
|
||||||
const panel = document.getElementById("users-panel");
|
const panel = document.getElementById("users-panel");
|
||||||
panel.style.display = panel.style.display === "none" ? "block" : "none";
|
panel.style.display = panel.style.display === "block"
|
||||||
|
? "none"
|
||||||
|
: "block";
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleTheme() {
|
function toggleTheme() {
|
||||||
@ -23,6 +27,30 @@ function toggleTheme() {
|
|||||||
localStorage.setItem("theme", newTheme);
|
localStorage.setItem("theme", newTheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function deleteMessage(messageId) {
|
||||||
|
if (confirm("Delete this message?")) {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/messages", {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ messageId: messageId }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
// Refresh messages
|
||||||
|
console.log("Message deleted successfully");
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
console.error("Failed to delete message");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error deleting message:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener("click", function (event) {
|
document.addEventListener("click", function (event) {
|
||||||
const settingsPanel = document.getElementById("settings-panel");
|
const settingsPanel = document.getElementById("settings-panel");
|
||||||
const settingsButton = document.querySelector(".settings-button");
|
const settingsButton = document.querySelector(".settings-button");
|
||||||
@ -134,9 +162,16 @@ async function loadMessages() {
|
|||||||
"div",
|
"div",
|
||||||
);
|
);
|
||||||
messageDiv.className = "message";
|
messageDiv.className = "message";
|
||||||
const [username, content] = msg.innerHTML.split(
|
const [
|
||||||
"<br>",
|
messageId,
|
||||||
);
|
username,
|
||||||
|
timestamp,
|
||||||
|
content,
|
||||||
|
] = msg
|
||||||
|
.innerHTML.split(
|
||||||
|
"<br>",
|
||||||
|
);
|
||||||
|
|
||||||
const linkedContent = content.replace(
|
const linkedContent = content.replace(
|
||||||
/(?![^<]*>)(https?:\/\/[^\s<]+)/g,
|
/(?![^<]*>)(https?:\/\/[^\s<]+)/g,
|
||||||
function (url) {
|
function (url) {
|
||||||
@ -176,11 +211,30 @@ async function loadMessages() {
|
|||||||
return `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`;
|
return `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
messageDiv.innerHTML =
|
|
||||||
'<div class="username">' + username +
|
let deleteHtml = "";
|
||||||
"</div>" +
|
|
||||||
'<div class="content">' +
|
const usernameDiv = document.createElement(
|
||||||
linkedContent + "</div>";
|
"div",
|
||||||
|
);
|
||||||
|
usernameDiv.innerHTML = username;
|
||||||
|
compareUsername = usernameDiv.textContent;
|
||||||
|
|
||||||
|
if (
|
||||||
|
compareUsername ===
|
||||||
|
document.getElementById(
|
||||||
|
"current-user",
|
||||||
|
).textContent
|
||||||
|
) {
|
||||||
|
deleteHtml =
|
||||||
|
`<button class="delete-button" onclick="deleteMessage('${messageId}')" style="display: inline;">🗑️</button>`;
|
||||||
|
}
|
||||||
|
messageDiv.innerHTML = `
|
||||||
|
<div class="message-header">
|
||||||
|
<div class="username">${username} ${timestamp} ${deleteHtml}</div>
|
||||||
|
</div>
|
||||||
|
<div class="content">${linkedContent}</div>`;
|
||||||
|
|
||||||
messagesDiv.appendChild(messageDiv);
|
messagesDiv.appendChild(messageDiv);
|
||||||
});
|
});
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
|
59
main.go
59
main.go
@ -182,26 +182,6 @@ func (db *Database) MessagesGet() []Message {
|
|||||||
var username string
|
var username string
|
||||||
rows.Scan(&id, &ip_address, &content, &created_at, &username)
|
rows.Scan(&id, &ip_address, &content, &created_at, &username)
|
||||||
|
|
||||||
// TODO: Implement better message parsing for admin commands
|
|
||||||
// TESTING:
|
|
||||||
// if msgId, ok := strings.CutPrefix(content, "@delete message id"); ok {
|
|
||||||
// msgId = strings.TrimSpace(msgId)
|
|
||||||
// go func() {
|
|
||||||
// db.MessageDeleteId(msgId)
|
|
||||||
// // db.MessageDeleteId(id)
|
|
||||||
// }()
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
// TESTING:
|
|
||||||
// if msgId, ok := strings.CutPrefix(content, "@delete user messages"); ok {
|
|
||||||
// msgId = strings.TrimSpace(msgId)
|
|
||||||
// go func() {
|
|
||||||
// db.UserMessagesDelete(ip_address)
|
|
||||||
// // db.MessageDeleteId(id)
|
|
||||||
// }()
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
|
|
||||||
message := Message{
|
message := Message{
|
||||||
Id: id,
|
Id: id,
|
||||||
Content: content,
|
Content: content,
|
||||||
@ -288,6 +268,18 @@ func (db *Database) MessageDeleteId(id string) {
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func (db *Database) MessageDeleteIfOwner(id string, ip string) (int, error) {
|
||||||
|
res, err := db.db.Exec("DELETE FROM messages WHERE id = ? AND ip_address = ?", id, ip)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
affected, err := res.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(affected), nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (db *Database) DeleteOldMessages(ageMinutes int) {
|
func (db *Database) DeleteOldMessages(ageMinutes int) {
|
||||||
if ageMinutes <= 0 {
|
if ageMinutes <= 0 {
|
||||||
@ -491,12 +483,11 @@ func (s *Server) handleMessages(w http.ResponseWriter, r *http.Request) {
|
|||||||
clientIP := getClientIP(r)
|
clientIP := getClientIP(r)
|
||||||
timeZone := s.Database.UserGetTimezone(clientIP)
|
timeZone := s.Database.UserGetTimezone(clientIP)
|
||||||
timeLocal := TimeStringToTimeInLocation(msg.Timestamp, timeZone)
|
timeLocal := TimeStringToTimeInLocation(msg.Timestamp, timeZone)
|
||||||
body += fmt.Sprintf(`%s<p><span class="username">%s </span><span class="timestamp">%s</span><br><span class="message">%s</span></p>`,
|
body += fmt.Sprintf(`<p>%s<br><span class="username">%s</span><br><span class="timestamp">%s</span><br><span class="message">%s</span></p>`,
|
||||||
msg.Id, msg.SenderUsername, timeLocal, msg.Content)
|
msg.Id, msg.SenderUsername, timeLocal, msg.Content)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write([]byte(getMessageTemplate(s.Config.Paths.MessagesHtmlPath, body)))
|
w.Write([]byte(getMessageTemplate(s.Config.Paths.MessagesHtmlPath, body)))
|
||||||
|
|
||||||
case http.MethodPut:
|
case http.MethodPut:
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
@ -529,6 +520,30 @@ func (s *Server) handleMessages(w http.ResponseWriter, r *http.Request) {
|
|||||||
"status": "Message received",
|
"status": "Message received",
|
||||||
"from": username,
|
"from": username,
|
||||||
})
|
})
|
||||||
|
case http.MethodDelete:
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
var req struct {
|
||||||
|
MessageId string `json:"messageId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
http.Error(w, `{"error": "Invalid JSON"}`, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
clientIP := getClientIP(r)
|
||||||
|
if affected, err := s.Database.MessageDeleteIfOwner(req.MessageId, clientIP); err != nil {
|
||||||
|
http.Error(w, `{"error": "Unauthorized"}`, http.StatusNotFound)
|
||||||
|
return
|
||||||
|
} else if affected == 0 {
|
||||||
|
http.Error(w, `{"error": "Message not found"}`, http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{
|
||||||
|
"status": "Message deleted",
|
||||||
|
})
|
||||||
default:
|
default:
|
||||||
http.Error(w, `{"error": "Method not allowed"}`, http.StatusMethodNotAllowed)
|
http.Error(w, `{"error": "Method not allowed"}`, http.StatusMethodNotAllowed)
|
||||||
return
|
return
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
- Nothing yet
|
- Nothing yet
|
||||||
### Low Priority
|
### Low Priority
|
||||||
- Mobile formatting @media
|
- Mobile formatting @media
|
||||||
- First click of user list does not register
|
|
||||||
## Backend
|
## Backend
|
||||||
### High Priority
|
### High Priority
|
||||||
- Updating messages should lazily load prior messages (pagination?)
|
- Nothing yet
|
||||||
### Mid Priority
|
### Mid Priority
|
||||||
- Nothing yet
|
- Nothing yet
|
||||||
### Low Priority
|
### Low Priority
|
||||||
- Search functionality?
|
- Search functionality?
|
||||||
- Delete messages? (in progress, capability exists, flesh this out a bit)
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user