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>
This commit is contained in:
parent
45b9e15152
commit
ac5c262bfb
9 changed files with 1081 additions and 0 deletions
|
|
@ -33,6 +33,11 @@ $_page_title = isset($page_title) ? htmlspecialchars($page_title) . ' — ' : '
|
|||
<i class="bi bi-journal-text me-1"></i>Audit
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $_nav_active === 'social' ? 'active' : '' ?>" href="/social">
|
||||
<i class="bi bi-calendar-week me-1"></i>Social
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<?php $user = Auth::currentUser(); ?>
|
||||
<ul class="navbar-nav">
|
||||
|
|
|
|||
|
|
@ -71,6 +71,25 @@ $scan_paths = $db->query('SELECT * FROM scan_paths ORDER BY path')->fetchAll();
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4 mt-0">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex align-items-center gap-2">
|
||||
<i class="bi bi-calendar-week text-primary"></i> Social scheduler — eligible projects
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted small mb-3">
|
||||
Projects enabled here appear as platform sources in the Social Scheduler.
|
||||
Only Discord Bot projects with configured social accounts are useful here.
|
||||
</p>
|
||||
<div id="socialProjectsList"><div class="text-muted small">Loading…</div></div>
|
||||
<button class="btn btn-sm btn-primary mt-3" id="saveSocialProjectsBtn">Save</button>
|
||||
<span class="text-muted small ms-2 d-none" id="socialProjectsSaved">Saved</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="scanResults" class="mt-4 d-none">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h5 class="mb-0">Scan results</h5>
|
||||
|
|
|
|||
90
views/social.php
Normal file
90
views/social.php
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
<?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'; ?>
|
||||
Loading…
Add table
Add a link
Reference in a new issue