Commit graph

13 commits

Author SHA1 Message Date
30242ae470 Fix timezone mismatch: store/compare scheduled_at in UTC
JS was sending browser-local time; dispatcher compared against server UTC,
so posts scheduled in UTC+3 appeared 3h in the future to the dispatcher.

- JS helpers: utcToDate, utcToLocalInput, localInputToUTC
- All scheduled_at values sent to server are now converted to UTC
- Stored values are displayed converted back to browser local time
- relTime and fmtDT parse stored UTC timestamps correctly
- dispatch-social.php: gmdate() for $now (UTC) + sent_at

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 21:07:42 +03:00
9af6326be2 Add startup diagnostics to dispatch-social for debugging
Logs now=, due_targets=, pending_posts= and per-post details (scheduled,
status, target count, DUE/future) so Dispatch now button shows useful output.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 20:55:11 +03:00
24c9deef94 Auto-check platform image toggles when image is uploaded
include_image was always 0 because users had to manually tick the
per-platform image checkbox after uploading — not obvious. Now uploading
an image auto-checks all targets; users can still uncheck individually.

Also removes debug logging from dispatch-social.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 19:43:29 +03:00
b792535dd0 Add image debug logging to dispatch-social
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 19:40:56 +03:00
4767fe0109 Fix image posting for Discord and Mastodon
Discord: payload_json was missing the attachments array, so uploaded
files were orphaned and not shown in the message (Discord API v10 requirement).

Mastodon: media_ids[] sent as URL-encoded form was unreliable — switch to
JSON body. Also poll /api/v1/media/:id when upload returns 202 (async) to
wait until the image is processed before attaching it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 19:35:03 +03:00
8ab9b7bbe2 Fix scheduled_at datetime format mismatch
datetime-local sends ISO format with T separator; normalize to space on save
and use SQLite datetime() in dispatcher query to handle both formats.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 17:55:11 +03:00
30d2b53075 Fix dispatcher timezone: use local time to match datetime-local form input
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 17:45:28 +03:00
ac5c262bfb Add Social Scheduler — global social media post scheduling
- New /social page with left/right layout (form + post list)
- Social topbar link
- Tables: social_posts, social_targets (project-agnostic posts, per-target project refs)
- CRUD: create, edit, duplicate, delete, retry
- Image upload (JPEG/PNG/GIF/WebP, 10MB max) stored in data/social-uploads/
- Per-platform image toggle (Discord multipart, Mastodon /api/v2/media, LinkedIn Assets API)
- bin/dispatch-social.php cron dispatcher (every minute via /etc/cron.d)
- Settings: eligible projects section to enable bot projects as social account sources
- Platforms: Discord (webhook), Mastodon, LinkedIn personal profile

Cron setup:
  * * * * * www-data /usr/bin/php /opt/hackmancms/bin/dispatch-social.php >> /var/log/hackman_social.log 2>&1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 17:01:03 +03:00
45b9e15152 Improve LinkedIn UI and scheduling robustness
- When LinkedIn is connected, replace the Connect button with a pencil
  (test post to first personal profile) and a reconnect arrow icon
- Add Process Now button to the Schedule tab that shells out to the cron
  script on demand and shows its output inline
- Add flock() to the cron script to prevent overlapping runs
- Fix cron install path comment to match deployed location

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 15:17:26 +03:00
30b21b6214 Add scheduled social posts, Discord channels config, and LinkedIn personal posting fix
- Scheduled posts: new Schedule tab with multi-platform post scheduling (Discord,
  Mastodon, LinkedIn); SQLite queue with per-target delivery tracking and retry;
  cron script in bin/process-scheduled-posts.php processes due targets inline
- Discord channels: new config section for webhook-based channels used as scheduled
  post targets; webhook URLs stored in .env as DISCORD_WEBHOOK_<KEY>
- LinkedIn: fix botcompose_post to use member_id (urn:li:person) for personal
  profiles instead of hardcoded org author; filter org pages out of compose UI
  and RSS modal picker since org posting is unsupported; label org pages clearly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 15:14:03 +03:00
e1f7fb14fc Simplify deploy.sh to run in place on the server
Removes local/prod cases — script now just does git pull, writes BUILD,
and runs migrate wherever it's executed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 12:32:28 +03:00
f6e768c246 Expand bot/automated-tool filter in site log importer
Add empty UA early return and a comprehensive list of bot signals covering
HTTP libraries, SEO platforms, uptime monitors, security scanners, AI
crawlers, and generic scanner vocabulary.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 19:29:29 +03:00
60ca58f5ba Init 2026-05-03 20:56:15 +03:00