223 lines · 9.7 KB
Raw Download
1
<?php
2
require_once __DIR__ . '/../includes/auth.php';
3
require_once __DIR__ . '/../includes/db.php';
4
require_once __DIR__ . '/../includes/helpers.php';
5
6
require_login();
7
8
$notice = '';
9
$error  = '';
10
11
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
12
    csrf_verify();
13
    $action = $_POST['action'] ?? '';
14
15
    if ($action === 'logout') {
16
        logout();
17
        header('Location: ' . url('/admin/login.php'));
18
        exit;
19
    }
20
21
    // Remove the installer — only after the admin explicitly confirms the site
22
    // works. We never auto-delete: the confirmation checkbox is required.
23
    if ($action === 'remove_installer') {
24
        $installFile = dirname(__DIR__) . '/install.php';
25
        if (empty($_POST['confirm_works'])) {
26
            $error = 'Please tick the confirmation box first, so we know your site is working before removing the installer.';
27
        } elseif (!is_file($installFile)) {
28
            $notice = 'install.php is already gone — nothing to remove. You are all set.';
29
        } elseif (@unlink($installFile)) {
30
            $notice = 'install.php was deleted. Your setup is now locked down.';
31
        } else {
32
            $error = 'Could not delete install.php automatically (likely a file-permission restriction). '
33
                   . 'Please remove it by hand via FTP or your host\'s File Manager.';
34
        }
35
    }
36
37
    if ($action === 'create') {
38
        $slug = normalize_slug($_POST['slug'] ?? '');
39
        $name = trim($_POST['name'] ?? '');
40
        $desc = trim($_POST['description'] ?? '');
41
        $lang = trim($_POST['language'] ?? '');
42
43
        if (!valid_slug($slug) || $name === '') {
44
            $error = 'A valid slug and a name are required.';
45
        } elseif (get_repository_by_slug($slug)) {
46
            $error = 'That slug is already taken.';
47
        } else {
48
            create_repository($slug, $name, $desc, $lang);
49
            @mkdir(UPLOAD_DIR . '/' . $slug, 0775, true);
50
            header('Location: ' . url('/admin/dashboard.php?created=1'));
51
            exit;
52
        }
53
    }
54
55
    if ($action === 'update') {
56
        $id      = (int) ($_POST['id'] ?? 0);
57
        $name    = trim($_POST['name'] ?? '');
58
        $desc    = trim($_POST['description'] ?? '');
59
        $lang    = trim($_POST['language'] ?? '');
60
        $newSlug = normalize_slug($_POST['slug'] ?? '');
61
        $repo    = $id ? get_repository($id) : null;
62
63
        if (!$repo || $name === '') {
64
            $error = 'A name is required.';
65
        } elseif (!valid_slug($newSlug)) {
66
            $error = 'A valid slug is required.';
67
        } else {
68
            $slugTaken = get_repository_by_slug($newSlug);
69
            if ($newSlug !== $repo['slug'] && $slugTaken && (int) $slugTaken['id'] !== $id) {
70
                $error = 'That slug is already taken.';
71
            } elseif ($newSlug !== $repo['slug'] && is_dir(UPLOAD_DIR . '/' . $newSlug)) {
72
                $error = 'An uploads folder for that slug already exists.';
73
            } else {
74
                // Rename the slug (disk + DB) before saving the other fields.
75
                if ($newSlug !== $repo['slug']) {
76
                    $oldDir = UPLOAD_DIR . '/' . $repo['slug'];
77
                    $newDir = UPLOAD_DIR . '/' . $newSlug;
78
                    if (is_dir($oldDir) && !@rename($oldDir, $newDir)) {
79
                        $error = 'Could not rename the uploads folder on disk.';
80
                    } else {
81
                        rename_repository($id, $repo['slug'], $newSlug);
82
                    }
83
                }
84
                if (!$error) {
85
                    update_repository($id, $name, $desc, $lang);
86
                    header('Location: ' . url('/admin/dashboard.php?updated=1'));
87
                    exit;
88
                }
89
            }
90
        }
91
    }
92
}
93
94
if (isset($_GET['created'])) { $notice = 'Repository created.'; }
95
if (isset($_GET['updated'])) { $notice = 'Repository updated.'; }
96
if (isset($_GET['deleted'])) { $notice = 'Deleted.'; }
97
if (isset($_GET['uploaded'])) { $notice = 'Files uploaded.'; }
98
99
$editing = null;
100
if (isset($_GET['edit'])) {
101
    $editing = get_repository((int) $_GET['edit']);
102
}
103
104
$repos = get_repositories();
105
106
$page_title = 'Dashboard';
107
require __DIR__ . '/../includes/header.php';
108
?>
109
<div class="admin-bar">
110
    <h1>Dashboard</h1>
111
    <form method="post" class="inline">
112
        <?= csrf_field() ?>
113
        <input type="hidden" name="action" value="logout">
114
        <button type="submit" class="link-btn">Log out</button>
115
    </form>
116
</div>
117
118
<?php if ($notice): ?><p class="notice"><?= e($notice) ?></p><?php endif; ?>
119
<?php if ($error): ?><p class="error"><?= e($error) ?></p><?php endif; ?>
120
121
<?php if (is_file(dirname(__DIR__) . '/install.php')): ?>
122
    <div class="warn-banner">
123
        <h3>&#9888; Installer still present</h3>
124
        <p><strong>install.php</strong> is still on your server. It can rewrite your configuration and
125
        reveal setup details, so it should be deleted once your site is working. Walk through the
126
        post-launch checklist (create a repo, upload a file, view it publicly), then remove it here.</p>
127
        <form method="post" onsubmit="return confirm('Delete install.php now? This cannot be undone from here.');">
128
            <?= csrf_field() ?>
129
            <input type="hidden" name="action" value="remove_installer">
130
            <label class="confirm">
131
                <input type="checkbox" name="confirm_works" value="1">
132
                <span>I have verified my site works correctly (login, upload, and public browsing).</span>
133
            </label>
134
            <button type="submit">Delete install.php</button>
135
        </form>
136
    </div>
137
<?php endif; ?>
138
139
<?php if ($editing):
140
    $editFiles     = get_files_by_repo((int) $editing['id']);
141
    $editBreakdown = language_breakdown($editFiles);
142
    $editDetected  = $editBreakdown ? (string) array_key_first($editBreakdown) : '';
143
?>
144
    <section class="card">
145
        <h2>Edit repository</h2>
146
        <form method="post" class="form">
147
            <?= csrf_field() ?>
148
            <input type="hidden" name="action" value="update">
149
            <input type="hidden" name="id" value="<?= (int) $editing['id'] ?>">
150
            <label>Slug <input type="text" name="slug" value="<?= e($editing['slug']) ?>" required></label>
151
            <p class="muted">Renaming the slug also moves its uploaded files and changes its public URL.</p>
152
            <label>Name <input type="text" name="name" value="<?= e($editing['name']) ?>" required></label>
153
            <label>Language
154
                <input type="text" name="language" value="<?= e($editing['language']) ?>"
155
                       placeholder="<?= $editDetected !== '' ? e('Auto: ' . $editDetected) : 'Auto-detect' ?>">
156
            </label>
157
            <p class="muted">
158
                Leave blank to auto-detect from the code files.
159
                <?php if ($editBreakdown): ?>
160
                    Detected:
161
                    <?php $parts = [];
162
                        foreach ($editBreakdown as $langName => $n) { $parts[] = $langName . ' (' . $n . ')'; }
163
                        echo e(implode(', ', $parts)); ?>.
164
                <?php else: ?>
165
                    No code files detected yet.
166
                <?php endif; ?>
167
            </p>
168
            <label>Description <textarea name="description" rows="3"><?= e($editing['description']) ?></textarea></label>
169
            <div class="row">
170
                <button type="submit">Save</button>
171
                <a class="btn-secondary" href="<?= e(url('/admin/dashboard.php')) ?>">Cancel</a>
172
            </div>
173
        </form>
174
    </section>
175
<?php else: ?>
176
    <section class="card">
177
        <h2>New repository</h2>
178
        <form method="post" class="form">
179
            <?= csrf_field() ?>
180
            <input type="hidden" name="action" value="create">
181
            <label>Slug <input type="text" name="slug" placeholder="save-utils" required></label>
182
            <label>Name <input type="text" name="name" placeholder="SaveUtils" required></label>
183
            <label>Language <input type="text" name="language" placeholder="Auto-detect"></label>
184
            <p class="muted">Leave blank to auto-detect from the files after you upload them.</p>
185
            <label>Description <textarea name="description" rows="3"></textarea></label>
186
            <button type="submit">Create</button>
187
        </form>
188
    </section>
189
<?php endif; ?>
190
191
<section>
192
    <h2>Repositories</h2>
193
    <?php if (empty($repos)): ?>
194
        <p class="empty">None yet.</p>
195
    <?php else: ?>
196
        <table class="file-table">
197
            <thead><tr><th>Name</th><th>Slug</th><th>Lang</th><th>Actions</th></tr></thead>
198
            <tbody>
199
            <?php foreach ($repos as $r): ?>
200
                <tr>
201
                    <td><a href="<?= e(url('/' . $r['slug'])) ?>"><?= e($r['name']) ?></a></td>
202
                    <td class="muted">/<?= e($r['slug']) ?></td>
203
                    <td class="muted"><?= e(repo_language_display($r)) ?></td>
204
                    <td class="actions">
205
                        <a href="<?= e(url('/admin/upload.php?repo=' . urlencode($r['slug']))) ?>">Upload</a>
206
                        <a href="<?= e(url('/admin/dashboard.php?edit=' . (int) $r['id'])) ?>">Edit</a>
207
                        <form method="post" action="<?= e(url('/admin/delete.php')) ?>" class="inline"
208
                              onsubmit="return confirm('Delete repository &quot;<?= e($r['slug']) ?>&quot; and all its files?');">
209
                            <?= csrf_field() ?>
210
                            <input type="hidden" name="type" value="repo">
211
                            <input type="hidden" name="id" value="<?= (int) $r['id'] ?>">
212
                            <button type="submit" class="link-btn danger">Delete</button>
213
                        </form>
214
                    </td>
215
                </tr>
216
            <?php endforeach; ?>
217
            </tbody>
218
        </table>
219
    <?php endif; ?>
220
</section>
221
<?php
222
require __DIR__ . '/../includes/footer.php';
223