parent
6e9f86b4ae
commit
475e648feb
11 changed files with 345 additions and 0 deletions
162
Slon/Api/V1/Announcements.HC
Normal file
162
Slon/Api/V1/Announcements.HC
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
// Internally, "reactions" is stored as { "emoji": [ "account_id", "account_id", ...]}
|
||||||
|
// This is presented to the client as: "reactions": [{ "name": "emoji", "count": (count), "me": (true|false) }, ...]
|
||||||
|
|
||||||
|
U0 @slon_api_v1_announcements_delete(SlonHttpSession* session)
|
||||||
|
{
|
||||||
|
if (@slon_api_authorized(session)) {
|
||||||
|
SLON_AUTH_ACCOUNT_ID
|
||||||
|
|
||||||
|
if (session->path_count() < 6) {
|
||||||
|
session->status(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
I64 i;
|
||||||
|
U8* id = session->path(3);
|
||||||
|
U8* verb = session->path(4);
|
||||||
|
U8* emoji = @slon_http_decode_urlencoded_string(session, session->path(5));
|
||||||
|
|
||||||
|
JsonObject* announcement = @slon_api_announcement_by_id(id);
|
||||||
|
if (!announcement) {
|
||||||
|
@slon_free(session, emoji);
|
||||||
|
session->status(404);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!StrICmp("reactions", verb)) {
|
||||||
|
JsonArray* emoji_array = announcement->o("reactions")->a(emoji);
|
||||||
|
Bool save_announcements = FALSE;
|
||||||
|
if (emoji_array && emoji_array->contains(account_id)) {
|
||||||
|
for (i = 0; i < emoji_array->length; i++) {
|
||||||
|
if (!StrICmp(account_id, emoji_array->@(i))) {
|
||||||
|
emoji_array->remove(i);
|
||||||
|
if (!emoji_array->length) {
|
||||||
|
announcement->o("reactions")->unset(emoji);
|
||||||
|
}
|
||||||
|
@slon_db_save_announcements_to_disk;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@slon_free(session, emoji);
|
||||||
|
session->send(SLON_EMPTY_JSON_OBJECT);
|
||||||
|
} else {
|
||||||
|
session->status(401);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 @slon_api_v1_announcements_get(SlonHttpSession* session)
|
||||||
|
{
|
||||||
|
if (@slon_api_authorized(session)) {
|
||||||
|
SLON_AUTH_ACCOUNT_ID
|
||||||
|
|
||||||
|
JsonArray* announcements = Json.CreateArray(session->mem_task);
|
||||||
|
JsonArray* iter_array = db->a("announcements");
|
||||||
|
JsonObject* announcement = NULL;
|
||||||
|
JsonKey* reaction_key = NULL;
|
||||||
|
JsonObject* reaction_object = NULL;
|
||||||
|
|
||||||
|
I64 i;
|
||||||
|
for (i = 0; i < iter_array->length; i++) {
|
||||||
|
announcement = Json.Clone(iter_array->o(i), session->mem_task);
|
||||||
|
if (announcement->a("read_users")->contains(account_id)) {
|
||||||
|
announcement->set("read", TRUE, JSON_BOOLEAN);
|
||||||
|
}
|
||||||
|
announcement->unset("read_users");
|
||||||
|
JsonArray* reactions_array = Json.CreateArray(session->mem_task);
|
||||||
|
reaction_key = announcement->o("reactions")->keys;
|
||||||
|
while (reaction_key) {
|
||||||
|
reaction_object = Json.CreateObject(session->mem_task);
|
||||||
|
reaction_object->set("name", reaction_key->name, JSON_STRING);
|
||||||
|
reaction_object->set("count", reaction_key->value(JsonArray*)->length, JSON_NUMBER);
|
||||||
|
reaction_object->set("me", reaction_key->value(JsonArray*)->contains(account_id), JSON_BOOLEAN);
|
||||||
|
reactions_array->append(reaction_object);
|
||||||
|
reaction_key = reaction_key->next;
|
||||||
|
}
|
||||||
|
announcement->set("reactions", reactions_array, JSON_ARRAY);
|
||||||
|
|
||||||
|
announcements->append(announcement);
|
||||||
|
}
|
||||||
|
|
||||||
|
session->send(announcements);
|
||||||
|
} else {
|
||||||
|
session->status(401);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 @slon_api_v1_announcements_post(SlonHttpSession* session)
|
||||||
|
{
|
||||||
|
if (@slon_api_authorized(session)) {
|
||||||
|
SLON_AUTH_ACCOUNT_ID
|
||||||
|
|
||||||
|
if (session->path_count() < 5) {
|
||||||
|
session->status(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
U8* id = session->path(3);
|
||||||
|
U8* verb = session->path(4);
|
||||||
|
|
||||||
|
JsonObject* announcement = @slon_api_announcement_by_id(id);
|
||||||
|
if (!announcement) {
|
||||||
|
session->status(404);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!StrICmp("dismiss", verb)) {
|
||||||
|
if (!announcement->a("read_users")->contains(account_id)) {
|
||||||
|
announcement->a("read_users")->append(account_id);
|
||||||
|
@slon_db_save_announcements_to_disk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
session->send(SLON_EMPTY_JSON_OBJECT);
|
||||||
|
} else {
|
||||||
|
session->status(401);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 @slon_api_v1_announcements_put(SlonHttpSession* session)
|
||||||
|
{
|
||||||
|
if (@slon_api_authorized(session)) {
|
||||||
|
SLON_AUTH_ACCOUNT_ID
|
||||||
|
|
||||||
|
if (session->path_count() < 6) {
|
||||||
|
session->status(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
U8* id = session->path(3);
|
||||||
|
U8* verb = session->path(4);
|
||||||
|
U8* emoji = @slon_http_decode_urlencoded_string(session, session->path(5));
|
||||||
|
|
||||||
|
JsonObject* announcement = @slon_api_announcement_by_id(id);
|
||||||
|
if (!announcement) {
|
||||||
|
@slon_free(session, emoji);
|
||||||
|
session->status(404);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!StrICmp("reactions", verb)) {
|
||||||
|
JsonArray* emoji_array = announcement->o("reactions")->a(emoji);
|
||||||
|
Bool save_announcements = FALSE;
|
||||||
|
if (!emoji_array) {
|
||||||
|
emoji_array = Json.CreateArray(slon_db_mem_task);
|
||||||
|
announcement->o("reactions")->set(emoji, emoji_array, JSON_ARRAY);
|
||||||
|
save_announcements = TRUE;
|
||||||
|
}
|
||||||
|
if (!emoji_array->contains(account_id)) {
|
||||||
|
emoji_array->append(account_id);
|
||||||
|
save_announcements = TRUE;
|
||||||
|
}
|
||||||
|
if (save_announcements) {
|
||||||
|
@slon_db_save_announcements_to_disk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@slon_free(session, emoji);
|
||||||
|
session->send(SLON_EMPTY_JSON_OBJECT);
|
||||||
|
} else {
|
||||||
|
session->status(401);
|
||||||
|
}
|
||||||
|
}
|
4
Slon/Endpoints/Delete/Announcements.HC
Normal file
4
Slon/Endpoints/Delete/Announcements.HC
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
if (String.BeginsWith("/api/v1/announcements", session->path())) {
|
||||||
|
@slon_api_v1_announcements_delete(session);
|
||||||
|
return;
|
||||||
|
}
|
4
Slon/Endpoints/Get/Announcements.HC
Normal file
4
Slon/Endpoints/Get/Announcements.HC
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
if (!StrICmp("/api/v1/announcements", session->path())) {
|
||||||
|
@slon_api_v1_announcements_get(session);
|
||||||
|
return;
|
||||||
|
}
|
4
Slon/Endpoints/Post/Announcements.HC
Normal file
4
Slon/Endpoints/Post/Announcements.HC
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
if (String.BeginsWith("/api/v1/announcements", session->path())) {
|
||||||
|
@slon_api_v1_announcements_post(session);
|
||||||
|
return;
|
||||||
|
}
|
4
Slon/Endpoints/Put/Announcements.HC
Normal file
4
Slon/Endpoints/Put/Announcements.HC
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
if (String.BeginsWith("/api/v1/announcements", session->path())) {
|
||||||
|
@slon_api_v1_announcements_put(session);
|
||||||
|
return;
|
||||||
|
}
|
|
@ -248,6 +248,28 @@ U0 @slon_admin_delete_account(SlonHttpSession* session)
|
||||||
session->send(SLON_EMPTY_JSON_OBJECT);
|
session->send(SLON_EMPTY_JSON_OBJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U0 @slon_admin_delete_announcement(SlonHttpSession* session)
|
||||||
|
{
|
||||||
|
SLON_SCRATCH_BUFFER_AND_REQUEST_JSON
|
||||||
|
no_warn scratch_buffer;
|
||||||
|
|
||||||
|
if (!request_json->@("id"))
|
||||||
|
return;
|
||||||
|
I64 i;
|
||||||
|
JsonArray* announcements = db->a("announcements");
|
||||||
|
JsonObject* announcement = NULL;
|
||||||
|
for (i = 0; i < announcements->length; i++) {
|
||||||
|
announcement = announcements->o(i);
|
||||||
|
if (announcement && !StrICmp(request_json->@("id"), announcement->@("id"))) {
|
||||||
|
AdamLog("deleting announcement %d\n", i);
|
||||||
|
announcements->remove(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@slon_db_save_announcements_to_disk;
|
||||||
|
session->send(SLON_EMPTY_JSON_OBJECT);
|
||||||
|
}
|
||||||
|
|
||||||
U0 @slon_admin_new_account(SlonHttpSession* session)
|
U0 @slon_admin_new_account(SlonHttpSession* session)
|
||||||
{
|
{
|
||||||
SLON_SCRATCH_BUFFER_AND_REQUEST_JSON
|
SLON_SCRATCH_BUFFER_AND_REQUEST_JSON
|
||||||
|
@ -262,6 +284,38 @@ U0 @slon_admin_new_account(SlonHttpSession* session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U0 @slon_admin_new_announcement(SlonHttpSession* session)
|
||||||
|
{
|
||||||
|
SLON_SCRATCH_BUFFER_AND_REQUEST_JSON
|
||||||
|
|
||||||
|
if (request_json->@("content")) {
|
||||||
|
U8* id = @slon_api_generate_unique_id(session);
|
||||||
|
U8* timestamp = @slon_api_timestamp_from_cdate(session, Now);
|
||||||
|
JsonObject* announcement = Json.CreateObject(slon_db_mem_task);
|
||||||
|
announcement->set("id", id, JSON_STRING);
|
||||||
|
announcement->set("content", request_json->@("content"), JSON_STRING);
|
||||||
|
announcement->set("starts_at", NULL, JSON_NULL);
|
||||||
|
announcement->set("ends_at", NULL, JSON_NULL);
|
||||||
|
announcement->set("all_day", FALSE, JSON_BOOLEAN);
|
||||||
|
announcement->set("published_at", timestamp, JSON_STRING);
|
||||||
|
announcement->set("updated_at", timestamp, JSON_STRING);
|
||||||
|
announcement->set("read", FALSE, JSON_BOOLEAN);
|
||||||
|
announcement->set("read_users", Json.CreateArray(slon_db_mem_task), JSON_ARRAY);
|
||||||
|
announcement->set("mentions", SLON_EMPTY_JSON_ARRAY, JSON_ARRAY);
|
||||||
|
announcement->set("statuses", SLON_EMPTY_JSON_ARRAY, JSON_ARRAY);
|
||||||
|
announcement->set("tags", Json.CreateArray(slon_db_mem_task), JSON_ARRAY);
|
||||||
|
announcement->set("emojis", Json.CreateArray(slon_db_mem_task), JSON_ARRAY);
|
||||||
|
// Internally, "reactions" is { "emoji": [ "account_id", "account_id", ... ]}
|
||||||
|
// This is presented to the client as: "reactions": [ { "name": "emoji", "count": xxx, "me": true/false }, ... ]
|
||||||
|
announcement->set("reactions", Json.CreateObject(slon_db_mem_task), JSON_OBJECT);
|
||||||
|
db->a("announcements")->append(announcement);
|
||||||
|
@slon_db_save_announcements_to_disk;
|
||||||
|
@slon_free(session, id);
|
||||||
|
@slon_free(session, timestamp);
|
||||||
|
}
|
||||||
|
session->send(SLON_EMPTY_JSON_OBJECT);
|
||||||
|
}
|
||||||
|
|
||||||
U0 @slon_admin_manage_accounts(SlonHttpSession* session)
|
U0 @slon_admin_manage_accounts(SlonHttpSession* session)
|
||||||
{
|
{
|
||||||
SLON_SCRATCH_BUFFER_AND_REQUEST_JSON
|
SLON_SCRATCH_BUFFER_AND_REQUEST_JSON
|
||||||
|
@ -324,14 +378,26 @@ U0 @slon_admin_server_get(SlonHttpSession* session)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!StrICmp("/delete/announcement", session->path())) {
|
||||||
|
@slon_admin_delete_announcement(session);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!StrICmp("/manage/accounts", session->path())) {
|
if (!StrICmp("/manage/accounts", session->path())) {
|
||||||
@slon_admin_manage_accounts(session);
|
@slon_admin_manage_accounts(session);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!StrICmp("/manage/announcements", session->path())) {
|
||||||
|
session->send(db->a("announcements"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!StrICmp("/manage/instance", session->path())) {
|
if (!StrICmp("/manage/instance", session->path())) {
|
||||||
session->send(db->o("instance"));
|
session->send(db->o("instance"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!StrICmp("/manage/settings", session->path())) {
|
if (!StrICmp("/manage/settings", session->path())) {
|
||||||
session->send(db->o("settings"));
|
session->send(db->o("settings"));
|
||||||
return;
|
return;
|
||||||
|
@ -395,6 +461,11 @@ U0 @slon_admin_server_post(SlonHttpSession* session)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!StrICmp("/new/announcement", session->path())) {
|
||||||
|
@slon_admin_new_announcement(session);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
session->status(404);
|
session->status(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -645,6 +645,7 @@ U0 @slon_http_handle_delete_request(SlonHttpSession* session)
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
||||||
|
#include "Endpoints/Delete/Announcements";
|
||||||
#include "Endpoints/Delete/Statuses";
|
#include "Endpoints/Delete/Statuses";
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
@ -664,6 +665,7 @@ U0 @slon_http_handle_get_request(SlonHttpSession* session)
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
||||||
#include "Endpoints/Get/Accounts";
|
#include "Endpoints/Get/Accounts";
|
||||||
|
#include "Endpoints/Get/Announcements";
|
||||||
#include "Endpoints/Get/ActivityPub";
|
#include "Endpoints/Get/ActivityPub";
|
||||||
#include "Endpoints/Get/Blocks";
|
#include "Endpoints/Get/Blocks";
|
||||||
#include "Endpoints/Get/Bookmarks";
|
#include "Endpoints/Get/Bookmarks";
|
||||||
|
@ -735,6 +737,7 @@ U0 @slon_http_handle_post_request(SlonHttpSession* session)
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
||||||
#include "Endpoints/Post/Accounts";
|
#include "Endpoints/Post/Accounts";
|
||||||
|
#include "Endpoints/Post/Announcements";
|
||||||
#include "Endpoints/Post/ActivityPub";
|
#include "Endpoints/Post/ActivityPub";
|
||||||
#include "Endpoints/Post/Apps";
|
#include "Endpoints/Post/Apps";
|
||||||
#include "Endpoints/Post/Markers";
|
#include "Endpoints/Post/Markers";
|
||||||
|
@ -763,6 +766,7 @@ U0 @slon_http_handle_put_request(SlonHttpSession* session)
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
||||||
|
#include "Endpoints/Put/Announcements";
|
||||||
#include "Endpoints/Put/Media";
|
#include "Endpoints/Put/Media";
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
|
@ -9,6 +9,7 @@ WinMax(Fs);
|
||||||
#include "Modules/Api";
|
#include "Modules/Api";
|
||||||
|
|
||||||
#include "Api/V1/Accounts";
|
#include "Api/V1/Accounts";
|
||||||
|
#include "Api/V1/Announcements";
|
||||||
#include "Api/V1/Apps";
|
#include "Api/V1/Apps";
|
||||||
#include "Api/V1/Blocks";
|
#include "Api/V1/Blocks";
|
||||||
#include "Api/V1/Bookmarks";
|
#include "Api/V1/Bookmarks";
|
||||||
|
|
|
@ -133,6 +133,20 @@ JsonObject* @slon_api_account_by_remote_actor(U8* remote_actor)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JsonObject* @slon_api_announcement_by_id(U8* id)
|
||||||
|
{
|
||||||
|
if (!id || !StrLen(id))
|
||||||
|
return NULL;
|
||||||
|
JsonArray* announcements = db->a("announcements");
|
||||||
|
I64 i;
|
||||||
|
for (i = 0; i < announcements->length; i++) {
|
||||||
|
if (!StrICmp(announcements->o(i)->@("id"), id)) {
|
||||||
|
return announcements->o(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
U0 @slon_api_async_upload_to_catbox(SlonCatboxUpload* cb)
|
U0 @slon_api_async_upload_to_catbox(SlonCatboxUpload* cb)
|
||||||
{
|
{
|
||||||
if (!cb) {
|
if (!cb) {
|
||||||
|
|
|
@ -51,6 +51,13 @@ U0 @slon_db_load_apps_from_disk()
|
||||||
db->set("apps", Json.ParseFile(scratch_buffer, slon_db_mem_task), JSON_OBJECT);
|
db->set("apps", Json.ParseFile(scratch_buffer, slon_db_mem_task), JSON_OBJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U0 @slon_db_load_announcements_from_disk()
|
||||||
|
{
|
||||||
|
U8 scratch_buffer[256];
|
||||||
|
StrPrint(scratch_buffer, "%s/announcements.json", SLON_DB_PATH);
|
||||||
|
db->set("announcements", Json.ParseFile(scratch_buffer, slon_db_mem_task), JSON_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
U0 @slon_db_load_instance_from_disk()
|
U0 @slon_db_load_instance_from_disk()
|
||||||
{
|
{
|
||||||
U8 scratch_buffer[256];
|
U8 scratch_buffer[256];
|
||||||
|
@ -230,6 +237,13 @@ U0 @slon_db_save_apps_to_disk()
|
||||||
Json.DumpToFile(scratch_buffer, db->o("apps"), slon_db_mem_task);
|
Json.DumpToFile(scratch_buffer, db->o("apps"), slon_db_mem_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U0 @slon_db_save_announcements_to_disk()
|
||||||
|
{
|
||||||
|
U8 scratch_buffer[256];
|
||||||
|
StrPrint(scratch_buffer, "%s/announcements.json", SLON_DB_PATH);
|
||||||
|
Json.DumpToFile(scratch_buffer, db->a("announcements"), slon_db_mem_task);
|
||||||
|
}
|
||||||
|
|
||||||
U0 @slon_db_save_instance_to_disk()
|
U0 @slon_db_save_instance_to_disk()
|
||||||
{
|
{
|
||||||
U8 scratch_buffer[256];
|
U8 scratch_buffer[256];
|
||||||
|
@ -328,6 +342,7 @@ U0 @slon_db_save_to_disk()
|
||||||
{
|
{
|
||||||
@slon_db_save_accounts_to_disk();
|
@slon_db_save_accounts_to_disk();
|
||||||
@slon_db_save_actors_to_disk();
|
@slon_db_save_actors_to_disk();
|
||||||
|
@slon_db_save_announcements_to_disk();
|
||||||
@slon_db_save_apps_to_disk();
|
@slon_db_save_apps_to_disk();
|
||||||
@slon_db_save_followers_to_disk();
|
@slon_db_save_followers_to_disk();
|
||||||
@slon_db_save_following_to_disk();
|
@slon_db_save_following_to_disk();
|
||||||
|
@ -344,6 +359,7 @@ U0 @slon_db_load_from_defaults()
|
||||||
{
|
{
|
||||||
db->set("accounts", Json.CreateArray(slon_db_mem_task), JSON_ARRAY);
|
db->set("accounts", Json.CreateArray(slon_db_mem_task), JSON_ARRAY);
|
||||||
db->set("actors", Json.CreateObject(slon_db_mem_task), JSON_OBJECT);
|
db->set("actors", Json.CreateObject(slon_db_mem_task), JSON_OBJECT);
|
||||||
|
db->set("announcements", Json.CreateArray(slon_db_mem_task), JSON_ARRAY);
|
||||||
db->set("apps", Json.CreateObject(slon_db_mem_task), JSON_OBJECT);
|
db->set("apps", Json.CreateObject(slon_db_mem_task), JSON_OBJECT);
|
||||||
db->set("idempotency_keys", Json.CreateObject(slon_db_mem_task), JSON_OBJECT);
|
db->set("idempotency_keys", Json.CreateObject(slon_db_mem_task), JSON_OBJECT);
|
||||||
db->set("private_keys", Json.CreateObject(slon_db_mem_task), JSON_OBJECT);
|
db->set("private_keys", Json.CreateObject(slon_db_mem_task), JSON_OBJECT);
|
||||||
|
@ -372,6 +388,7 @@ U0 @slon_db_load_from_disk()
|
||||||
{
|
{
|
||||||
@slon_db_load_accounts_from_disk();
|
@slon_db_load_accounts_from_disk();
|
||||||
@slon_db_load_actors_from_disk();
|
@slon_db_load_actors_from_disk();
|
||||||
|
@slon_db_load_announcements_from_disk();
|
||||||
@slon_db_load_apps_from_disk();
|
@slon_db_load_apps_from_disk();
|
||||||
db->set("idempotency_keys", Json.CreateObject(slon_db_mem_task), JSON_OBJECT);
|
db->set("idempotency_keys", Json.CreateObject(slon_db_mem_task), JSON_OBJECT);
|
||||||
@slon_db_load_private_keys_from_disk();
|
@slon_db_load_private_keys_from_disk();
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
<p class="menu-label">Manage</p>
|
<p class="menu-label">Manage</p>
|
||||||
<ul class="menu-list">
|
<ul class="menu-list">
|
||||||
<li><a onclick="manageAccounts(0)" id="menuitem-accounts">Accounts</a></li>
|
<li><a onclick="manageAccounts(0)" id="menuitem-accounts">Accounts</a></li>
|
||||||
|
<li><a onclick="manageAnnouncements()" id="menuitem-announcements">Announcements</a></li>
|
||||||
<li><a onclick="manageInstance()" id="menuitem-instance">Instance</a></li>
|
<li><a onclick="manageInstance()" id="menuitem-instance">Instance</a></li>
|
||||||
<li><a onclick="manageSettings()" id="menuitem-settings">Settings</a></li>
|
<li><a onclick="manageSettings()" id="menuitem-settings">Settings</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -95,6 +96,25 @@
|
||||||
setContent(html);
|
setContent(html);
|
||||||
setActiveLink("accounts");
|
setActiveLink("accounts");
|
||||||
}
|
}
|
||||||
|
async function manageAnnouncements() {
|
||||||
|
clearActiveLinks();
|
||||||
|
const request = new Request("/manage/announcements");
|
||||||
|
const response = await fetch(request);
|
||||||
|
const announcements = await response.json();
|
||||||
|
let html = "<h4 class=\"title is-4\">Announcements</h4><div class=spacer></div><div>";
|
||||||
|
if (announcements.length) {
|
||||||
|
html += announcements.length + " announcement(s)</div><div class=spacer></div>";
|
||||||
|
html += "<table class=table><thead><tr><th>id</th><th>published_at</th><th>updated_at</th><th>content</th><th>delete</th></tr></head><tbody>";
|
||||||
|
for (let i = 0; i < announcements.length; i++) {
|
||||||
|
html += "<tr><td>" + announcements[i]["id"] + "</td><td>" + announcements[i]["published_at"] + "</td><td>" + announcements[i]["updated_at"] + "</td><td>" + announcements[i]["content"] + "</td><td style=\"text-align:center\"><a href=\"javascript:confirmDeleteAnnouncement('" + announcements[i]["id"] + "');\">❌</a></td><tr>";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
html += "No announcements</div><div class=spacer></div>";
|
||||||
|
}
|
||||||
|
html += "<br><br><input onclick=createNewAnnouncement() class=button type=button value=\"New Announcement\">";
|
||||||
|
setContent(html);
|
||||||
|
setActiveLink("announcements");
|
||||||
|
}
|
||||||
async function manageInstance() {
|
async function manageInstance() {
|
||||||
clearActiveLinks();
|
clearActiveLinks();
|
||||||
const request = new Request("/manage/instance");
|
const request = new Request("/manage/instance");
|
||||||
|
@ -182,6 +202,14 @@
|
||||||
const response = await fetch(request);
|
const response = await fetch(request);
|
||||||
manageSettings();
|
manageSettings();
|
||||||
}
|
}
|
||||||
|
async function confirmDeleteAnnouncement(id) {
|
||||||
|
if (confirm("Are you sure you want to delete announcement id " + id + " ?")) {
|
||||||
|
const request = new Request("/delete/announcement?id=" + id);
|
||||||
|
const response = await fetch(request);
|
||||||
|
const empty_json = await response.json();
|
||||||
|
manageAnnouncements();
|
||||||
|
}
|
||||||
|
}
|
||||||
async function confirmDeleteUser(user, id) {
|
async function confirmDeleteUser(user, id) {
|
||||||
if (confirm("Are you sure you want to delete '" + user + "' ?")) {
|
if (confirm("Are you sure you want to delete '" + user + "' ?")) {
|
||||||
const request = new Request("/delete/account?id=" + id);
|
const request = new Request("/delete/account?id=" + id);
|
||||||
|
@ -190,6 +218,23 @@
|
||||||
manageAccounts(0);
|
manageAccounts(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function createNewAnnouncement() {
|
||||||
|
clearActiveLinks();
|
||||||
|
let html = "<h4 class=\"title is-4\">New Announcement</h4><div class=spacer></div>";
|
||||||
|
|
||||||
|
html += "<form action=\"javascript:saveNewAnnouncement()\"><div>";
|
||||||
|
|
||||||
|
html += "<div class=\"section is-inline-block\" style=\"width:420px;vertical-align:top\">";
|
||||||
|
html += "<textarea class=\"textarea\" placeholder=\"content goes here\" id=\"announcement-content\"></textarea>";
|
||||||
|
html += "</div>";
|
||||||
|
|
||||||
|
html += "</div>";
|
||||||
|
html += "<div class=\"control next\"><input class=\"button is-link\" type=submit value=Save></div>"
|
||||||
|
html += "</div></form>";
|
||||||
|
|
||||||
|
setContent(html);
|
||||||
|
setActiveLink("announcements");
|
||||||
|
}
|
||||||
function manageNewUser() {
|
function manageNewUser() {
|
||||||
clearActiveLinks();
|
clearActiveLinks();
|
||||||
let html = "<h4 class=\"title is-4\">New User</h4><div class=spacer></div>";
|
let html = "<h4 class=\"title is-4\">New User</h4><div class=spacer></div>";
|
||||||
|
@ -216,6 +261,21 @@
|
||||||
setContent(html);
|
setContent(html);
|
||||||
setActiveLink("accounts");
|
setActiveLink("accounts");
|
||||||
}
|
}
|
||||||
|
async function saveNewAnnouncement() {
|
||||||
|
let data = {"content": document.getElementById("announcement-content").value};
|
||||||
|
const request = new Request("/new/announcement", {
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(data)
|
||||||
|
});
|
||||||
|
const response = await fetch(request);
|
||||||
|
const json = await response.json();
|
||||||
|
if (!Object.keys(json).length) {
|
||||||
|
manageAnnouncements();
|
||||||
|
} else {
|
||||||
|
alert(JSON.stringify(json));
|
||||||
|
}
|
||||||
|
}
|
||||||
async function saveNewUser() {
|
async function saveNewUser() {
|
||||||
let data = {};
|
let data = {};
|
||||||
let fields = document.getElementsByTagName("input");
|
let fields = document.getElementsByTagName("input");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue