summaryrefslogtreecommitdiff
path: root/html.c
diff options
context:
space:
mode:
Diffstat (limited to 'html.c')
-rw-r--r--html.c142
1 files changed, 125 insertions, 17 deletions
diff --git a/html.c b/html.c
index d549f75..008c05b 100644
--- a/html.c
+++ b/html.c
@@ -350,7 +350,7 @@ xs_html *html_note(snac *user, const char *summary,
350 const xs_val *mnt_only, const char *redir, 350 const xs_val *mnt_only, const char *redir,
351 const char *in_reply_to, int poll, 351 const char *in_reply_to, int poll,
352 const xs_list *att_files, const xs_list *att_alt_texts, 352 const xs_list *att_files, const xs_list *att_alt_texts,
353 int is_draft) 353 int is_draft, const char *published)
354/* Yes, this is a FUCKTON of arguments and I'm a bit embarrased */ 354/* Yes, this is a FUCKTON of arguments and I'm a bit embarrased */
355{ 355{
356 xs *action = xs_fmt("%s/admin/note", user->actor); 356 xs *action = xs_fmt("%s/admin/note", user->actor);
@@ -440,6 +440,36 @@ xs_html *html_note(snac *user, const char *summary,
440 xs_html_attr("name", "is_draft"), 440 xs_html_attr("name", "is_draft"),
441 xs_html_attr(is_draft ? "checked" : "", NULL)))); 441 xs_html_attr(is_draft ? "checked" : "", NULL))));
442 442
443 /* post date and time */
444 xs *post_date = NULL;
445 xs *post_time = NULL;
446
447 if (xs_is_string(published)) {
448 time_t t = xs_parse_iso_date(published, 0);
449
450 if (t > 0) {
451 post_date = xs_str_time(t, "%Y-%m-%d", 1);
452 post_time = xs_str_time(t, "%H:%M:%S", 1);
453 }
454 }
455
456 if (edit_id == NULL || is_draft || is_scheduled(user, edit_id)) {
457 xs_html_add(form,
458 xs_html_tag("p",
459 xs_html_text(L("Post date and time (empty, right now; in the future, schedule for later):")),
460 xs_html_sctag("br", NULL),
461 xs_html_sctag("input",
462 xs_html_attr("type", "date"),
463 xs_html_attr("value", post_date ? post_date : ""),
464 xs_html_attr("name", "post_date")),
465 xs_html_text(" "),
466 xs_html_sctag("input",
467 xs_html_attr("type", "time"),
468 xs_html_attr("value", post_time ? post_time : ""),
469 xs_html_attr("step", "1"),
470 xs_html_attr("name", "post_time"))));
471 }
472
443 if (edit_id) 473 if (edit_id)
444 xs_html_add(form, 474 xs_html_add(form,
445 xs_html_sctag("input", 475 xs_html_sctag("input",
@@ -1127,7 +1157,7 @@ xs_html *html_top_controls(snac *user)
1127 NULL, NULL, 1157 NULL, NULL,
1128 xs_stock(XSTYPE_FALSE), "", 1158 xs_stock(XSTYPE_FALSE), "",
1129 xs_stock(XSTYPE_FALSE), NULL, 1159 xs_stock(XSTYPE_FALSE), NULL,
1130 NULL, 1, NULL, NULL, 0), 1160 NULL, 1, NULL, NULL, 0, NULL),
1131 1161
1132 /** operations **/ 1162 /** operations **/
1133 xs_html_tag("details", 1163 xs_html_tag("details",
@@ -1785,7 +1815,8 @@ xs_html *html_entry_controls(snac *user, const char *actor,
1785 id, NULL, 1815 id, NULL,
1786 xs_dict_get(msg, "sensitive"), xs_dict_get(msg, "summary"), 1816 xs_dict_get(msg, "sensitive"), xs_dict_get(msg, "summary"),
1787 xs_stock(is_msg_public(msg) ? XSTYPE_FALSE : XSTYPE_TRUE), redir, 1817 xs_stock(is_msg_public(msg) ? XSTYPE_FALSE : XSTYPE_TRUE), redir,
1788 NULL, 0, att_files, att_alt_texts, is_draft(user, id))), 1818 NULL, 0, att_files, att_alt_texts, is_draft(user, id),
1819 xs_dict_get(msg, "published"))),
1789 xs_html_tag("p", NULL)); 1820 xs_html_tag("p", NULL));
1790 } 1821 }
1791 1822
@@ -1804,7 +1835,7 @@ xs_html *html_entry_controls(snac *user, const char *actor,
1804 NULL, NULL, 1835 NULL, NULL,
1805 xs_dict_get(msg, "sensitive"), xs_dict_get(msg, "summary"), 1836 xs_dict_get(msg, "sensitive"), xs_dict_get(msg, "summary"),
1806 xs_stock(is_msg_public(msg) ? XSTYPE_FALSE : XSTYPE_TRUE), redir, 1837 xs_stock(is_msg_public(msg) ? XSTYPE_FALSE : XSTYPE_TRUE), redir,
1807 id, 0, NULL, NULL, 0)), 1838 id, 0, NULL, NULL, 0, NULL)),
1808 xs_html_tag("p", NULL)); 1839 xs_html_tag("p", NULL));
1809 } 1840 }
1810 1841
@@ -2841,6 +2872,18 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only,
2841 xs_html_text(L("drafts"))))); 2872 xs_html_text(L("drafts")))));
2842 } 2873 }
2843 2874
2875 {
2876 /* show the list of scheduled posts */
2877 xs *url = xs_fmt("%s/sched", user->actor);
2878 xs_html_add(lol,
2879 xs_html_tag("li",
2880 xs_html_tag("a",
2881 xs_html_attr("href", url),
2882 xs_html_attr("class", "snac-list-link"),
2883 xs_html_attr("title", L("Scheduled posts")),
2884 xs_html_text(L("scheduled posts")))));
2885 }
2886
2844 /* the list of followed hashtags */ 2887 /* the list of followed hashtags */
2845 const char *followed_hashtags = xs_dict_get(user->config, "followed_hashtags"); 2888 const char *followed_hashtags = xs_dict_get(user->config, "followed_hashtags");
2846 2889
@@ -3141,7 +3184,7 @@ xs_html *html_people_list(snac *user, xs_list *list, const char *header, const c
3141 NULL, actor_id, 3184 NULL, actor_id,
3142 xs_stock(XSTYPE_FALSE), "", 3185 xs_stock(XSTYPE_FALSE), "",
3143 xs_stock(XSTYPE_FALSE), NULL, 3186 xs_stock(XSTYPE_FALSE), NULL,
3144 NULL, 0, NULL, NULL, 0), 3187 NULL, 0, NULL, NULL, 0, NULL),
3145 xs_html_tag("p", NULL)); 3188 xs_html_tag("p", NULL));
3146 3189
3147 xs_html_add(snac_post, snac_controls); 3190 xs_html_add(snac_post, snac_controls);
@@ -3890,6 +3933,21 @@ int html_get_handler(const xs_dict *req, const char *q_path,
3890 } 3933 }
3891 } 3934 }
3892 else 3935 else
3936 if (strcmp(p_path, "sched") == 0) { /** list of scheduled posts **/
3937 if (!login(&snac, req)) {
3938 *body = xs_dup(uid);
3939 status = HTTP_STATUS_UNAUTHORIZED;
3940 }
3941 else {
3942 xs *list = scheduled_list(&snac);
3943
3944 *body = html_timeline(&snac, list, 0, skip, show,
3945 0, L("Scheduled posts"), "", 0, error);
3946 *b_size = strlen(*body);
3947 status = HTTP_STATUS_OK;
3948 }
3949 }
3950 else
3893 if (xs_startswith(p_path, "list/")) { /** list timelines **/ 3951 if (xs_startswith(p_path, "list/")) { /** list timelines **/
3894 if (!login(&snac, req)) { 3952 if (!login(&snac, req)) {
3895 *body = xs_dup(uid); 3953 *body = xs_dup(uid);
@@ -4186,12 +4244,14 @@ int html_post_handler(const xs_dict *req, const char *q_path,
4186 snac_debug(&snac, 1, xs_fmt("web action '%s' received", p_path)); 4244 snac_debug(&snac, 1, xs_fmt("web action '%s' received", p_path));
4187 4245
4188 /* post note */ 4246 /* post note */
4189 const xs_str *content = xs_dict_get(p_vars, "content"); 4247 const char *content = xs_dict_get(p_vars, "content");
4190 const xs_str *in_reply_to = xs_dict_get(p_vars, "in_reply_to"); 4248 const char *in_reply_to = xs_dict_get(p_vars, "in_reply_to");
4191 const xs_str *to = xs_dict_get(p_vars, "to"); 4249 const char *to = xs_dict_get(p_vars, "to");
4192 const xs_str *sensitive = xs_dict_get(p_vars, "sensitive"); 4250 const char *sensitive = xs_dict_get(p_vars, "sensitive");
4193 const xs_str *summary = xs_dict_get(p_vars, "summary"); 4251 const char *summary = xs_dict_get(p_vars, "summary");
4194 const xs_str *edit_id = xs_dict_get(p_vars, "edit_id"); 4252 const char *edit_id = xs_dict_get(p_vars, "edit_id");
4253 const char *post_date = xs_dict_get_def(p_vars, "post_date", "");
4254 const char *post_time = xs_dict_get_def(p_vars, "post_time", "");
4195 int priv = !xs_is_null(xs_dict_get(p_vars, "mentioned_only")); 4255 int priv = !xs_is_null(xs_dict_get(p_vars, "mentioned_only"));
4196 int store_as_draft = !xs_is_null(xs_dict_get(p_vars, "is_draft")); 4256 int store_as_draft = !xs_is_null(xs_dict_get(p_vars, "is_draft"));
4197 xs *attach_list = xs_list_new(); 4257 xs *attach_list = xs_list_new();
@@ -4279,6 +4339,29 @@ int html_post_handler(const xs_dict *req, const char *q_path,
4279 msg = xs_dict_set(msg, "summary", xs_is_null(summary) ? "..." : summary); 4339 msg = xs_dict_set(msg, "summary", xs_is_null(summary) ? "..." : summary);
4280 } 4340 }
4281 4341
4342 if (xs_is_string(post_date) && *post_date) {
4343 xs *local_pubdate = xs_fmt("%sT%s", post_date,
4344 xs_is_string(post_time) && *post_time ? post_time : "00:00:00");
4345
4346 time_t t = xs_parse_iso_date(local_pubdate, 1);
4347
4348 if (t != 0) {
4349 xs *iso_date = xs_str_iso_date(t);
4350 msg = xs_dict_set(msg, "published", iso_date);
4351
4352 snac_debug(&snac, 1, xs_fmt("Published date: [%s]", iso_date));
4353 }
4354 else
4355 snac_log(&snac, xs_fmt("Invalid post date: [%s]", local_pubdate));
4356 }
4357
4358 /* is the published date from the future? */
4359 int future_post = 0;
4360 xs *right_now = xs_str_utctime(0, ISO_DATE_SPEC);
4361
4362 if (strcmp(xs_dict_get(msg, "published"), right_now) > 0)
4363 future_post = 1;
4364
4282 if (xs_is_null(edit_id)) { 4365 if (xs_is_null(edit_id)) {
4283 /* new message */ 4366 /* new message */
4284 const char *id = xs_dict_get(msg, "id"); 4367 const char *id = xs_dict_get(msg, "id");
@@ -4286,6 +4369,10 @@ int html_post_handler(const xs_dict *req, const char *q_path,
4286 if (store_as_draft) { 4369 if (store_as_draft) {
4287 draft_add(&snac, id, msg); 4370 draft_add(&snac, id, msg);
4288 } 4371 }
4372 else
4373 if (future_post) {
4374 schedule_add(&snac, id, msg);
4375 }
4289 else { 4376 else {
4290 c_msg = msg_create(&snac, msg); 4377 c_msg = msg_create(&snac, msg);
4291 timeline_add(&snac, id, msg); 4378 timeline_add(&snac, id, msg);
@@ -4297,7 +4384,7 @@ int html_post_handler(const xs_dict *req, const char *q_path,
4297 4384
4298 if (valid_status(object_get(edit_id, &p_msg))) { 4385 if (valid_status(object_get(edit_id, &p_msg))) {
4299 /* copy relevant fields from previous version */ 4386 /* copy relevant fields from previous version */
4300 char *fields[] = { "id", "context", "url", "published", 4387 char *fields[] = { "id", "context", "url",
4301 "to", "inReplyTo", NULL }; 4388 "to", "inReplyTo", NULL };
4302 int n; 4389 int n;
4303 4390
@@ -4313,18 +4400,34 @@ int html_post_handler(const xs_dict *req, const char *q_path,
4313 if (is_draft(&snac, edit_id)) { 4400 if (is_draft(&snac, edit_id)) {
4314 /* message was previously a draft; it's a create activity */ 4401 /* message was previously a draft; it's a create activity */
4315 4402
4316 /* set the published field to now */ 4403 /* if the date is from the past, overwrite it with right_now */
4317 xs *published = xs_str_utctime(0, ISO_DATE_SPEC); 4404 if (strcmp(xs_dict_get(msg, "published"), right_now) < 0) {
4318 msg = xs_dict_set(msg, "published", published); 4405 snac_debug(&snac, 1, xs_fmt("setting draft ancient date to %s", right_now));
4406 msg = xs_dict_set(msg, "published", right_now);
4407 }
4319 4408
4320 /* overwrite object */ 4409 /* overwrite object */
4321 object_add_ow(edit_id, msg); 4410 object_add_ow(edit_id, msg);
4322 4411
4323 c_msg = msg_create(&snac, msg); 4412 if (future_post) {
4324 timeline_add(&snac, edit_id, msg); 4413 schedule_add(&snac, edit_id, msg);
4414 }
4415 else {
4416 c_msg = msg_create(&snac, msg);
4417 timeline_add(&snac, edit_id, msg);
4418 }
4419
4325 draft_del(&snac, edit_id); 4420 draft_del(&snac, edit_id);
4326 } 4421 }
4422 else
4423 if (is_scheduled(&snac, edit_id)) {
4424 /* editing an scheduled post; just update it */
4425 schedule_add(&snac, edit_id, msg);
4426 }
4327 else { 4427 else {
4428 /* ignore the (possibly changed) published date */
4429 msg = xs_dict_set(msg, "published", xs_dict_get(p_msg, "published"));
4430
4328 /* set the updated field */ 4431 /* set the updated field */
4329 xs *updated = xs_str_utctime(0, ISO_DATE_SPEC); 4432 xs *updated = xs_str_utctime(0, ISO_DATE_SPEC);
4330 msg = xs_dict_set(msg, "updated", updated); 4433 msg = xs_dict_set(msg, "updated", updated);
@@ -4409,6 +4512,9 @@ int html_post_handler(const xs_dict *req, const char *q_path,
4409 if (is_draft(&snac, id)) 4512 if (is_draft(&snac, id))
4410 draft_del(&snac, id); 4513 draft_del(&snac, id);
4411 else 4514 else
4515 if (is_scheduled(&snac, id))
4516 schedule_del(&snac, id);
4517 else
4412 hide(&snac, id); 4518 hide(&snac, id);
4413 } 4519 }
4414 else 4520 else
@@ -4504,6 +4610,8 @@ int html_post_handler(const xs_dict *req, const char *q_path,
4504 4610
4505 draft_del(&snac, id); 4611 draft_del(&snac, id);
4506 4612
4613 schedule_del(&snac, id);
4614
4507 snac_log(&snac, xs_fmt("deleted entry %s", id)); 4615 snac_log(&snac, xs_fmt("deleted entry %s", id));
4508 } 4616 }
4509 } 4617 }