Skip to content

Commit 66cf2ed

Browse files
committed
Add edit button to announcements
1 parent cf35a77 commit 66cf2ed

File tree

4 files changed

+276
-4
lines changed

4 files changed

+276
-4
lines changed

include/ff.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,8 @@ namespace ff {
405405
limhamn::http::server::response handle_api_update_profile(const limhamn::http::server::request& request, database& db);
406406
limhamn::http::server::response handle_api_get_profile(const limhamn::http::server::request& request, database& db);
407407
limhamn::http::server::response handle_api_get_announcements(const limhamn::http::server::request& request, database& db);
408-
limhamn::http::server::response handle_api_delete_announcements(const limhamn::http::server::request& request, database& db);
408+
limhamn::http::server::response handle_api_delete_announcement(const limhamn::http::server::request& request, database& db);
409+
limhamn::http::server::response handle_api_edit_announcement(const limhamn::http::server::request& request, database& db);
409410
limhamn::http::server::response handle_api_create_announcement(const limhamn::http::server::request& request, database& db);
410411
limhamn::http::server::response handle_api_rate_forwarder_endpoint(const limhamn::http::server::request& request, database& db);
411412
limhamn::http::server::response handle_api_rate_file_endpoint(const limhamn::http::server::request& request, database& db);

js/ff.js

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1113,12 +1113,91 @@ function get_announcements() {
11131113
}
11141114

11151115
if (is_admin) {
1116+
const edit_button = document.createElement('button');
1117+
edit_button.innerHTML = 'Edit';
1118+
edit_button.className = 'edit-announcement-button';
1119+
edit_button.onclick = (event) => {
1120+
play_click();
1121+
event.stopPropagation();
1122+
const create = create_window('edit-announcement-window');
1123+
1124+
const title = document.createElement('h1');
1125+
title.innerHTML = 'Edit announcement';
1126+
title.className = 'floating_window_title';
1127+
1128+
const paragraph = document.createElement('p');
1129+
paragraph.innerHTML = 'Please edit the title and text for the announcement.';
1130+
1131+
const title_input = document.createElement('input');
1132+
title_input.type = 'text';
1133+
title_input.name = 'title';
1134+
title_input.placeholder = 'Title';
1135+
title_input.className = 'announcement-input';
1136+
title_input.id = 'announcement-title';
1137+
title_input.value = announcement.title;
1138+
1139+
const text_input = document.createElement('textarea');
1140+
text_input.name = 'text';
1141+
text_input.placeholder = 'Text (markdown)';
1142+
text_input.className = 'announcement-input';
1143+
text_input.id = 'announcement-text';
1144+
text_input.style.height = '200px';
1145+
text_input.style.width = '80%';
1146+
text_input.value = announcement.text_markdown;
1147+
1148+
const submit_button = document.createElement('button');
1149+
submit_button.innerHTML = 'Submit';
1150+
submit_button.className = 'create-announcement-button';
1151+
submit_button.onclick = () => {
1152+
play_click();
1153+
const json = {
1154+
announcement_id: announcement.index,
1155+
title: title_input.value,
1156+
text_markdown: text_input.value,
1157+
};
1158+
1159+
fetch('/api/edit_announcement', {
1160+
method: 'POST',
1161+
headers: {
1162+
'Content-Type': 'application/json',
1163+
},
1164+
body: JSON.stringify(json),
1165+
})
1166+
.then(() => {
1167+
if (json.error_str) {
1168+
show_register(json.error_str);
1169+
return;
1170+
}
1171+
hide_all_windows();
1172+
get_announcements();
1173+
})
1174+
.catch((error) => {
1175+
console.error('Error:', error);
1176+
});
1177+
}
1178+
1179+
create.appendChild(title);
1180+
create.appendChild(paragraph);
1181+
create.appendChild(document.createElement('br'));
1182+
create.appendChild(document.createElement('br'));
1183+
create.appendChild(title_input);
1184+
create.appendChild(document.createElement('br'));
1185+
create.appendChild(document.createElement('br'));
1186+
create.appendChild(text_input);
1187+
create.appendChild(document.createElement('br'));
1188+
create.appendChild(document.createElement('br'));
1189+
create.appendChild(submit_button);
1190+
1191+
document.body.appendChild(create);
1192+
}
1193+
div.appendChild(edit_button);
1194+
11161195
const delete_button = document.createElement('button');
11171196
delete_button.innerHTML = 'Delete';
11181197
delete_button.className = 'delete-announcement-button';
11191198
delete_button.onclick = (event) => {
11201199
play_click();
1121-
event.stopPropagation(); // prevent the announcement from being clicked
1200+
event.stopPropagation();
11221201
fetch('/api/delete_announcement', {
11231202
method: 'POST',
11241203
headers: {

src/ff.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,8 @@ void ff::start_server() {
282282
{"/api/get_profile", ff::handle_api_get_profile},
283283
{"/api/create_announcement", ff::handle_api_create_announcement},
284284
{"/api/get_announcements", ff::handle_api_get_announcements},
285-
{"/api/delete_announcement", ff::handle_api_delete_announcements},
285+
{"/api/delete_announcement", ff::handle_api_delete_announcement},
286+
{"/api/edit_announcement", ff::handle_api_edit_announcement},
286287
{"/api/stay_logged_in", ff::handle_api_stay_logged_in},
287288
{"/api/try_logout", ff::handle_api_try_logout_endpoint},
288289
};

src/path_handlers.cpp

Lines changed: 192 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1801,7 +1801,7 @@ limhamn::http::server::response ff::handle_api_get_announcements(const limhamn::
18011801
return response;
18021802
}
18031803

1804-
limhamn::http::server::response ff::handle_api_delete_announcements(const limhamn::http::server::request& request, database& db) {
1804+
limhamn::http::server::response ff::handle_api_delete_announcement(const limhamn::http::server::request& request, database& db) {
18051805
limhamn::http::server::response response{};
18061806
response.content_type = "application/json";
18071807

@@ -1976,6 +1976,197 @@ limhamn::http::server::response ff::handle_api_delete_announcements(const limham
19761976
}
19771977
}
19781978

1979+
limhamn::http::server::response ff::handle_api_edit_announcement(const limhamn::http::server::request& request, database& db) {
1980+
limhamn::http::server::response response{};
1981+
response.content_type = "application/json";
1982+
1983+
const auto get_username = [&request]() -> std::string {
1984+
if (request.session.find("username") != request.session.end()) {
1985+
return request.session.at("username");
1986+
}
1987+
1988+
try {
1989+
const auto json = nlohmann::json::parse(request.body);
1990+
if (json.find("username") != json.end() && json.at("username").is_string()) {
1991+
return json.at("username").get<std::string>();
1992+
}
1993+
} catch (const std::exception&) {
1994+
// ignore
1995+
}
1996+
1997+
return "";
1998+
};
1999+
2000+
const auto get_key = [&request]() -> std::string {
2001+
if (request.session.find("key") != request.session.end()) {
2002+
return request.session.at("key");
2003+
}
2004+
2005+
try {
2006+
const auto json = nlohmann::json::parse(request.body);
2007+
if (json.find("key") != json.end() && json.at("key").is_string()) {
2008+
return json.at("key").get<std::string>();
2009+
}
2010+
} catch (const std::exception&) {
2011+
// ignore
2012+
}
2013+
2014+
return "";
2015+
};
2016+
2017+
const std::string username{get_username()};
2018+
const std::string key{get_key()};
2019+
2020+
if (username.empty() || key.empty()) {
2021+
#ifdef FF_DEBUG
2022+
logger.write_to_log(limhamn::logger::type::notice, "Username or key is empty.\n");
2023+
#endif
2024+
nlohmann::json json;
2025+
json["error_str"] = "Username or key is empty.";
2026+
json["error"] = "FF_INVALID_CREDENTIALS";
2027+
response.http_status = 400;
2028+
response.body = json.dump();
2029+
return response;
2030+
}
2031+
2032+
if (!ff::verify_key(db, username, key)) {
2033+
#ifdef FF_DEBUG
2034+
logger.write_to_log(limhamn::logger::type::notice, "Invalid credentials.\n");
2035+
#endif
2036+
nlohmann::json json;
2037+
json["error_str"] = "Invalid credentials.";
2038+
json["error"] = "FF_INVALID_CREDENTIALS";
2039+
response.http_status = 400;
2040+
response.body = json.dump();
2041+
return response;
2042+
}
2043+
2044+
if (ff::get_user_type(db, username) != ff::UserType::Administrator) {
2045+
nlohmann::json json;
2046+
json["error"] = "FF_NOT_AUTHORIZED";
2047+
json["error_str"] = "You are not authorized to access this endpoint.";
2048+
response.http_status = 403;
2049+
response.body = json.dump();
2050+
return response;
2051+
}
2052+
2053+
if (request.body.empty()) {
2054+
#ifdef FF_DEBUG
2055+
logger.write_to_log(limhamn::logger::type::notice, "No body.\n");
2056+
#endif
2057+
nlohmann::json json;
2058+
json["error_str"] = "No body.";
2059+
json["error"] = "FF_NO_BODY";
2060+
response.http_status = 400;
2061+
response.body = json.dump();
2062+
return response;
2063+
}
2064+
if (request.method != "POST") {
2065+
#ifdef FF_DEBUG
2066+
logger.write_to_log(limhamn::logger::type::notice, "Not a POST request.\n");
2067+
#endif
2068+
nlohmann::json json;
2069+
json["error_str"] = "Not a POST request.";
2070+
json["error"] = "FF_INVALID_METHOD";
2071+
response.http_status = 400;
2072+
response.body = json.dump();
2073+
return response;
2074+
}
2075+
2076+
nlohmann::json input;
2077+
try {
2078+
input = nlohmann::json::parse(request.body);
2079+
} catch (const std::exception&) {
2080+
#ifdef FF_DEBUG
2081+
logger.write_to_log(limhamn::logger::type::notice, "Failed to parse JSON.\n");
2082+
#endif
2083+
nlohmann::json json;
2084+
json["error_str"] = "Invalid JSON received";
2085+
json["error"] = "FF_INVALID_JSON";
2086+
response.http_status = 400;
2087+
response.body = json.dump();
2088+
return response;
2089+
}
2090+
2091+
if (input.find("announcement_id") == input.end() || !input.at("announcement_id").is_number_integer()) {
2092+
nlohmann::json json;
2093+
json["error"] = "FF_INVALID_JSON";
2094+
json["error_str"] = "Invalid JSON received";
2095+
response.http_status = 400;
2096+
response.body = json.dump();
2097+
return response;
2098+
}
2099+
2100+
const auto query = db.query("SELECT * FROM general WHERE id=1;");
2101+
if (query.empty()) {
2102+
nlohmann::json ret;
2103+
ret["error"] = "FF_SERVER_ERROR";
2104+
ret["error_str"] = "Server failed, no idea why. general is empty";
2105+
2106+
response.content_type = "application/json";
2107+
response.http_status = 400;
2108+
response.body = ret.dump();
2109+
return response;
2110+
}
2111+
2112+
if (query.at(0).find("json") == query.at(0).end()) {
2113+
nlohmann::json ret;
2114+
ret["error"] = "FF_SERVER_ERROR";
2115+
ret["error_str"] = "Server failed, no idea why.";
2116+
2117+
response.content_type = "application/json";
2118+
response.http_status = 400;
2119+
response.body = ret.dump();
2120+
return response;
2121+
}
2122+
2123+
try {
2124+
auto json = nlohmann::json::parse(query.at(0).at("json"));
2125+
if (json.contains("announcements") && json.at("announcements").is_array()) {
2126+
auto& announcements = json["announcements"];
2127+
const int announcement_id = input.at("announcement_id").get<int>();
2128+
if (announcement_id < 0 || announcement_id >= static_cast<int>(announcements.size())) {
2129+
nlohmann::json ret;
2130+
ret["error"] = "FF_INVALID_JSON";
2131+
ret["error_str"] = "Invalid announcement_id.";
2132+
response.http_status = 400;
2133+
response.body = ret.dump();
2134+
return response;
2135+
}
2136+
auto& announcement = announcements[announcement_id];
2137+
if (input.find("title") != input.end() && input.at("title").is_string()) {
2138+
announcement["title"] = input.at("title").get<std::string>();
2139+
}
2140+
if (input.find("text_markdown") != input.end() && input.at("text_markdown").is_string()) {
2141+
announcement["text_markdown"] = input.at("text_markdown").get<std::string>();
2142+
maddy::Parser parser;
2143+
std::istringstream stream{input.at("text_markdown").get<std::string>()};
2144+
announcement["text_html"] = parser.Parse(stream);
2145+
}
2146+
if (input.find("text_html") != input.end() && input.at("text_html").is_string()) {
2147+
announcement["text_html"] = input.at("text_html").get<std::string>();
2148+
}
2149+
if (input.find("publish_timestamp") != input.end() && input.at("publish_timestamp").is_number_integer()) {
2150+
announcement["publish_timestamp"] = input.at("publish_timestamp").get<int64_t>();
2151+
}
2152+
announcement["author"] = username;
2153+
}
2154+
db.exec("UPDATE general SET json = ? WHERE id = 1", json.dump());
2155+
response.http_status = 204;
2156+
return response;
2157+
} catch (const std::exception&) {
2158+
nlohmann::json ret;
2159+
ret["error"] = "FF_SERVER_ERROR";
2160+
ret["error_str"] = "Server failed, no idea why.";
2161+
2162+
response.content_type = "application/json";
2163+
response.http_status = 400;
2164+
response.body = ret.dump();
2165+
2166+
return response;
2167+
}
2168+
}
2169+
19792170

19802171
limhamn::http::server::response ff::handle_api_rate_file_endpoint(const limhamn::http::server::request& request, database& db) {
19812172
limhamn::http::server::response response{};

0 commit comments

Comments
 (0)