HackmanCMS/views/social.php
Bashy 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

90 lines
3.8 KiB
PHP

<?php
$page_title = 'Social';
$nav_active = 'social';
include ROOT . '/views/_header.php';
?>
<h2 class="h4 mb-4"><i class="bi bi-calendar-week me-2"></i>Social Scheduler</h2>
<div class="row g-4" id="socialPage">
<!-- ── LEFT: Compose form ─────────────────────────────────────────── -->
<div class="col-lg-4">
<div class="card" id="socialFormCard" style="position:sticky;top:1rem">
<div class="card-header d-flex align-items-center gap-2">
<span id="socialFormTitle">Schedule a post</span>
<button class="btn btn-xs btn-outline-secondary ms-auto d-none" id="socialCancelEditBtn">
<i class="bi bi-x-lg me-1"></i>Cancel
</button>
</div>
<div class="card-body">
<input type="hidden" id="socialEditId">
<div class="mb-3">
<label class="form-label small">Content</label>
<textarea id="socialContent" class="form-control form-control-sm font-monospace"
rows="7" placeholder="What's on your mind?"></textarea>
</div>
<div class="mb-3">
<label class="form-label small">Schedule for</label>
<input type="datetime-local" id="socialScheduledAt" class="form-control form-control-sm">
</div>
<!-- Image -->
<div class="mb-3">
<div class="d-flex align-items-center mb-2">
<span class="small">Image <span class="text-muted">(optional)</span></span>
<div class="ms-auto d-flex gap-1">
<button type="button" class="btn btn-xs btn-outline-secondary" id="socialUploadBtn">
<i class="bi bi-image me-1"></i>Upload
</button>
<button type="button" class="btn btn-xs btn-outline-danger d-none" id="socialRemoveImageBtn">
<i class="bi bi-x"></i> Remove
</button>
</div>
</div>
<input type="file" id="socialImageInput" accept="image/jpeg,image/png,image/gif,image/webp" class="d-none">
<input type="hidden" id="socialImagePath">
<div id="socialImagePreview" class="d-none">
<img id="socialImageThumb" src="" alt="" class="img-fluid rounded border" style="max-height:140px;object-fit:contain">
<div class="text-muted small mt-1" id="socialImageNote">Toggle per-platform below</div>
</div>
</div>
<!-- Platform targets -->
<div class="mb-3">
<label class="form-label small">Platforms</label>
<div id="socialTargets">
<div class="text-muted small">Loading…</div>
</div>
</div>
<div id="socialFormError" class="alert alert-danger py-2 small d-none mb-3"></div>
<button type="button" class="btn btn-primary w-100" id="socialSubmitBtn">
<i class="bi bi-calendar-plus me-1"></i>Schedule
</button>
</div>
</div>
</div>
<!-- ── RIGHT: Post list ───────────────────────────────────────────── -->
<div class="col-lg-8">
<div class="d-flex align-items-center mb-3 gap-2">
<h5 class="mb-0">Posts</h5>
<div class="ms-auto btn-group btn-group-sm">
<button class="btn btn-outline-secondary active" id="socialFilterPending">Pending</button>
<button class="btn btn-outline-secondary" id="socialFilterAll">All</button>
</div>
<button class="btn btn-sm btn-outline-secondary" id="socialRefreshBtn" title="Refresh">
<i class="bi bi-arrow-clockwise"></i>
</button>
</div>
<div id="socialPostsList">
<div class="text-muted small">Loading…</div>
</div>
</div>
</div>
<?php include ROOT . '/views/_footer.php'; ?>