parent
a4a959d875
commit
5a9bf4f32b
4 changed files with 175 additions and 9 deletions
|
@ -1,12 +1,4 @@
|
||||||
U0 @slon_api_v1_custom_emojis_get(SlonHttpSession* session)
|
U0 @slon_api_v1_custom_emojis_get(SlonHttpSession* session)
|
||||||
{
|
{
|
||||||
// SLON_SCRATCH_BUFFER_AND_REQUEST_JSON
|
session->send(db->a("custom_emojis"));
|
||||||
|
|
||||||
if (@slon_api_authorized(session)) {
|
|
||||||
// SLON_AUTH_ACCOUNT_ID
|
|
||||||
// FIXME: Implement this
|
|
||||||
session->send(SLON_EMPTY_JSON_ARRAY);
|
|
||||||
} else {
|
|
||||||
session->status(401);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -270,6 +270,30 @@ U0 @slon_admin_delete_announcement(SlonHttpSession* session)
|
||||||
session->send(SLON_EMPTY_JSON_OBJECT);
|
session->send(SLON_EMPTY_JSON_OBJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U0 @slon_admin_delete_custom_emoji(SlonHttpSession* session)
|
||||||
|
{
|
||||||
|
SLON_SCRATCH_BUFFER_AND_REQUEST_JSON
|
||||||
|
no_warn scratch_buffer;
|
||||||
|
|
||||||
|
U8* shortcode = request_json->@("shortcode");
|
||||||
|
U8* filename = request_json->@("filename");
|
||||||
|
JsonArray* custom_emojis = db->a("custom_emojis");
|
||||||
|
JsonObject* emoji = NULL;
|
||||||
|
I64 i;
|
||||||
|
if (shortcode && filename) {
|
||||||
|
@slon_api_async_delete_from_catbox(filename);
|
||||||
|
for (i = 0; i < custom_emojis->length; i++) {
|
||||||
|
emoji = custom_emojis->o(i);
|
||||||
|
if (!StrICmp(shortcode, emoji->@("shortcode"))) {
|
||||||
|
custom_emojis->remove(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@slon_db_save_custom_emojis_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
|
||||||
|
@ -315,6 +339,60 @@ U0 @slon_admin_new_announcement(SlonHttpSession* session)
|
||||||
session->send(SLON_EMPTY_JSON_OBJECT);
|
session->send(SLON_EMPTY_JSON_OBJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U0 @slon_admin_new_custom_emoji(SlonHttpSession* session)
|
||||||
|
{
|
||||||
|
SLON_SCRATCH_BUFFER_AND_REQUEST_JSON
|
||||||
|
no_warn scratch_buffer;
|
||||||
|
|
||||||
|
SlonMultipartFile* file = request_json->@("image-file");
|
||||||
|
if (!file || !file->buffer || !file->size || !file->content_type) {
|
||||||
|
session->send(Json.Parse("{\"error\":\"image file not present or corrupt/invalid type\"}", session->mem_task));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject* emoji = Json.CreateObject(slon_db_mem_task);
|
||||||
|
emoji->set("shortcode", request_json->@("shortcode"), JSON_STRING);
|
||||||
|
emoji->set("visible_in_picker", request_json->@("visible-in-picker"), JSON_BOOLEAN);
|
||||||
|
|
||||||
|
U8* category = request_json->@("category");
|
||||||
|
if (category && StrLen(category)) {
|
||||||
|
emoji->set("category", category, JSON_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
U8* image_id = @slon_api_generate_unique_id(session);
|
||||||
|
U8* ext = StrFind("image/", file->content_type) + 6;
|
||||||
|
|
||||||
|
StrPrint(scratch_buffer, "%s/%s.%s", SLON_MEDIA_PATH, image_id, ext);
|
||||||
|
FileWrite(scratch_buffer, file->buffer, file->size);
|
||||||
|
|
||||||
|
JsonKey* key = @slon_calloc(session, sizeof(JsonKey));
|
||||||
|
|
||||||
|
SlonCatboxUpload* cb = CAlloc(sizeof(SlonCatboxUpload), slon_mem_task);
|
||||||
|
cb->key = key;
|
||||||
|
cb->filepath = StrNew(scratch_buffer, slon_mem_task);
|
||||||
|
|
||||||
|
session->send(SLON_EMPTY_JSON_OBJECT);
|
||||||
|
|
||||||
|
// NOTE: This is synchronous, despite the function name
|
||||||
|
@slon_api_async_upload_to_catbox(cb);
|
||||||
|
Del(scratch_buffer);
|
||||||
|
|
||||||
|
if (key->value) {
|
||||||
|
AdamLog("cb->key->value: %s\n", key->value);
|
||||||
|
emoji->set("url", key->value, JSON_STRING);
|
||||||
|
emoji->set("static_url", key->value, JSON_STRING);
|
||||||
|
db->a("custom_emojis")->append(emoji);
|
||||||
|
@slon_db_save_custom_emojis_to_disk;
|
||||||
|
session->send(SLON_EMPTY_JSON_OBJECT);
|
||||||
|
} else {
|
||||||
|
session->send(Json.Parse("{\"error\":\"upload to catbox failed\"}", session->mem_task));
|
||||||
|
}
|
||||||
|
|
||||||
|
@slon_free(session, image_id);
|
||||||
|
Free(key->value);
|
||||||
|
@slon_free(session, key);
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
|
@ -382,6 +460,11 @@ U0 @slon_admin_server_get(SlonHttpSession* session)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!StrICmp("/delete/custom-emoji", session->path())) {
|
||||||
|
@slon_admin_delete_custom_emoji(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;
|
||||||
|
@ -392,6 +475,11 @@ U0 @slon_admin_server_get(SlonHttpSession* session)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!StrICmp("/manage/custom-emojis", session->path())) {
|
||||||
|
session->send(db->a("custom_emojis"));
|
||||||
|
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;
|
||||||
|
@ -445,6 +533,10 @@ U0 @slon_admin_server_post(SlonHttpSession* session)
|
||||||
@slon_http_parse_request_as_json(session);
|
@slon_http_parse_request_as_json(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (String.BeginsWith("multipart/form-data", session->header("content-type"))) {
|
||||||
|
@slon_http_parse_request_as_multipart_form_data(session);
|
||||||
|
}
|
||||||
|
|
||||||
if (!StrICmp("/setup/instance", session->path()) || !StrICmp("/save/instance", session->path())) {
|
if (!StrICmp("/setup/instance", session->path()) || !StrICmp("/save/instance", session->path())) {
|
||||||
@slon_admin_setup_instance(session);
|
@slon_admin_setup_instance(session);
|
||||||
return;
|
return;
|
||||||
|
@ -465,6 +557,11 @@ U0 @slon_admin_server_post(SlonHttpSession* session)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!StrICmp("/new/custom-emoji", session->path())) {
|
||||||
|
@slon_admin_new_custom_emoji(session);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
session->status(404);
|
session->status(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,13 @@ U0 @slon_db_load_announcements_from_disk()
|
||||||
db->set("announcements", Json.ParseFile(scratch_buffer, slon_db_mem_task), JSON_ARRAY);
|
db->set("announcements", Json.ParseFile(scratch_buffer, slon_db_mem_task), JSON_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U0 @slon_db_load_custom_emojis_from_disk()
|
||||||
|
{
|
||||||
|
U8 scratch_buffer[256];
|
||||||
|
StrPrint(scratch_buffer, "%s/custom_emojis.json", SLON_DB_PATH);
|
||||||
|
db->set("custom_emojis", 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];
|
||||||
|
@ -264,6 +271,13 @@ U0 @slon_db_save_announcements_to_disk()
|
||||||
Json.DumpToFile(scratch_buffer, db->a("announcements"), slon_db_mem_task);
|
Json.DumpToFile(scratch_buffer, db->a("announcements"), slon_db_mem_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U0 @slon_db_save_custom_emojis_to_disk()
|
||||||
|
{
|
||||||
|
U8 scratch_buffer[256];
|
||||||
|
StrPrint(scratch_buffer, "%s/custom_emojis.json", SLON_DB_PATH);
|
||||||
|
Json.DumpToFile(scratch_buffer, db->a("custom_emojis"), 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];
|
||||||
|
@ -375,6 +389,7 @@ U0 @slon_db_save_to_disk()
|
||||||
@slon_db_save_actors_to_disk();
|
@slon_db_save_actors_to_disk();
|
||||||
@slon_db_save_announcements_to_disk();
|
@slon_db_save_announcements_to_disk();
|
||||||
@slon_db_save_apps_to_disk();
|
@slon_db_save_apps_to_disk();
|
||||||
|
@slon_db_save_custom_emojis_to_disk();
|
||||||
@slon_db_save_favourites_to_disk();
|
@slon_db_save_favourites_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();
|
||||||
|
@ -393,6 +408,7 @@ U0 @slon_db_load_from_defaults()
|
||||||
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("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("custom_emojis", Json.CreateArray(slon_db_mem_task), JSON_ARRAY);
|
||||||
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);
|
||||||
db->set("private_keys_binary", Json.CreateObject(slon_db_mem_task), JSON_OBJECT);
|
db->set("private_keys_binary", Json.CreateObject(slon_db_mem_task), JSON_OBJECT);
|
||||||
|
@ -423,6 +439,7 @@ U0 @slon_db_load_from_disk()
|
||||||
@slon_db_load_actors_from_disk();
|
@slon_db_load_actors_from_disk();
|
||||||
@slon_db_load_announcements_from_disk();
|
@slon_db_load_announcements_from_disk();
|
||||||
@slon_db_load_apps_from_disk();
|
@slon_db_load_apps_from_disk();
|
||||||
|
@slon_db_load_custom_emojis_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();
|
||||||
db->set("private_keys_binary", Json.CreateObject(slon_db_mem_task), JSON_OBJECT);
|
db->set("private_keys_binary", Json.CreateObject(slon_db_mem_task), JSON_OBJECT);
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
<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="manageAnnouncements()" id="menuitem-announcements">Announcements</a></li>
|
||||||
|
<li><a onclick="manageCustomEmojis()" id="menuitem-customemojis">Custom Emoji</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>
|
||||||
|
@ -115,6 +116,34 @@
|
||||||
setContent(html);
|
setContent(html);
|
||||||
setActiveLink("announcements");
|
setActiveLink("announcements");
|
||||||
}
|
}
|
||||||
|
async function manageCustomEmojis() {
|
||||||
|
clearActiveLinks();
|
||||||
|
const request = new Request("/manage/custom-emojis");
|
||||||
|
const response = await fetch(request);
|
||||||
|
const custom_emojis = await response.json();
|
||||||
|
let html = "<h4 class=\"title is-4\">Custom Emojis</h4><div class=spacer></div>";
|
||||||
|
|
||||||
|
for (let i = 0; i < custom_emojis.length; i++) {
|
||||||
|
let filename_split = custom_emojis[i]["url"].split('/')
|
||||||
|
html += "<div class=\"is-inline-block\"><img src=\"" + custom_emojis[i]["url"] + "\" style=\"width:48px;height:48px\"><br>" + custom_emojis[i]["shortcode"] + "<br><button onclick=\"confirmDeleteCustomEmoji('" + custom_emojis[i]["shortcode"] + "', '" + filename_split[filename_split.length-1] + "')\">Delete</button></div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
html += "<form id=\"emoji-form\"action=\"javascript:saveNewCustomEmoji()\"><div>";
|
||||||
|
|
||||||
|
html += "<div class=\"section is-inline-block\" style=\"width:420px;vertical-align:top\">";
|
||||||
|
html += "<label class=label>Shortcode</label><div class=control><input name=shortcode id=shortcode class=input placeholder=my-cool-emoji required autocomplete=off></div><div class=spacer></div>";
|
||||||
|
html += "<label class=label>Image</label><div class=control><input onchange=updateBase64Image(this) name=image-file id=image-file type=file required autocomplete=off> <img id=image-thumb style=\"display:none\" width=48 height=48></div><div class=spacer></div>";
|
||||||
|
html += "<label class=label>Visible in picker</label><div class=control><input name=visible-in-picker id=visible-in-picker type=checkbox checked></div><div class=spacer></div>";
|
||||||
|
html += "<label class=label>Category</label><div class=control><input name=category id=category class=input placeholder=\"Cool Emojis\" required autocomplete=off></div><div class=spacer></div>";
|
||||||
|
html += "</div>";
|
||||||
|
|
||||||
|
html += "</div>";
|
||||||
|
html += "<div class=\"control next\"><input class=\"button is-link\" type=submit value=New Custom Emoji></div>"
|
||||||
|
html += "</div></form>";
|
||||||
|
|
||||||
|
setContent(html);
|
||||||
|
setActiveLink("customemojis");
|
||||||
|
}
|
||||||
async function manageInstance() {
|
async function manageInstance() {
|
||||||
clearActiveLinks();
|
clearActiveLinks();
|
||||||
const request = new Request("/manage/instance");
|
const request = new Request("/manage/instance");
|
||||||
|
@ -218,6 +247,14 @@
|
||||||
manageAccounts(0);
|
manageAccounts(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async function confirmDeleteCustomEmoji(shortcode, filename) {
|
||||||
|
if (confirm("Are you sure you want to delete :" + shortcode + ": ?")) {
|
||||||
|
const request = new Request("/delete/custom-emoji?shortcode=" + shortcode + "&filename=" + filename);
|
||||||
|
const response = await fetch(request);
|
||||||
|
const empty_json = await response.json();
|
||||||
|
manageCustomEmojis();
|
||||||
|
}
|
||||||
|
}
|
||||||
function createNewAnnouncement() {
|
function createNewAnnouncement() {
|
||||||
clearActiveLinks();
|
clearActiveLinks();
|
||||||
let html = "<h4 class=\"title is-4\">New Announcement</h4><div class=spacer></div>";
|
let html = "<h4 class=\"title is-4\">New Announcement</h4><div class=spacer></div>";
|
||||||
|
@ -307,6 +344,17 @@
|
||||||
alert(JSON.stringify(json));
|
alert(JSON.stringify(json));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async function saveNewCustomEmoji() {
|
||||||
|
const form = document.getElementById('emoji-form');
|
||||||
|
const formData = new FormData(form);
|
||||||
|
const response = await fetch('/new/custom-emoji', { method: 'POST', body: formData, signal: AbortSignal.timeout(15000) });
|
||||||
|
const json = await response.json();
|
||||||
|
if (!Object.keys(json).length) {
|
||||||
|
manageCustomEmojis();
|
||||||
|
} else {
|
||||||
|
alert(JSON.stringify(json));
|
||||||
|
}
|
||||||
|
}
|
||||||
async function saveInstance() {
|
async function saveInstance() {
|
||||||
let data = {};
|
let data = {};
|
||||||
let fields = document.getElementsByTagName("input");
|
let fields = document.getElementsByTagName("input");
|
||||||
|
@ -339,6 +387,18 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
function updateBase64Image(el) {
|
||||||
|
let reader = new FileReader();
|
||||||
|
reader.readAsDataURL(el.files[0]);
|
||||||
|
reader.addEventListener(
|
||||||
|
"load",
|
||||||
|
() => {
|
||||||
|
el.base64 = reader.result;
|
||||||
|
document.getElementById("image-thumb").src = reader.result;
|
||||||
|
document.getElementById("image-thumb").style = "";
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
const formatTime = milliseconds => {
|
const formatTime = milliseconds => {
|
||||||
const seconds = Math.floor((milliseconds / 1000) % 60);
|
const seconds = Math.floor((milliseconds / 1000) % 60);
|
||||||
const minutes = Math.floor((milliseconds / 1000 / 60) % 60);
|
const minutes = Math.floor((milliseconds / 1000 / 60) % 60);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue