Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa07fe0edd | ||
|
|
67874636d2 | ||
|
|
c316c39860 | ||
|
|
a4197dab4b | ||
|
|
8453d82ee4 |
+31
-7
@@ -32,11 +32,26 @@ function build_filters(array $opts): array {
|
||||
}
|
||||
}
|
||||
|
||||
// Max age filter
|
||||
$max_age_days = intval($opts['max_age_days'] ?? 0);
|
||||
if ($max_age_days > 0) {
|
||||
$conds[] = 'e.created_at < EXTRACT(EPOCH FROM NOW())::BIGINT - :max_age_seconds';
|
||||
$params[':max_age_seconds'] = $max_age_days * 86400;
|
||||
// Date/time range filter (supports YYYY-MM-DD or YYYY-MM-DD HH:MM)
|
||||
$from_date = $opts['from_date'] ?? '';
|
||||
$to_date = $opts['to_date'] ?? '';
|
||||
if ($from_date !== '') {
|
||||
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $from_date)) {
|
||||
$conds[] = 'e.created_at >= EXTRACT(EPOCH FROM :from_date::date)::BIGINT';
|
||||
$params[':from_date'] = $from_date;
|
||||
} elseif (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/', $from_date)) {
|
||||
$conds[] = 'e.created_at >= EXTRACT(EPOCH FROM :from_date::timestamp)::BIGINT';
|
||||
$params[':from_date'] = $from_date . ':00';
|
||||
}
|
||||
}
|
||||
if ($to_date !== '') {
|
||||
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $to_date)) {
|
||||
$conds[] = 'e.created_at < (EXTRACT(EPOCH FROM :to_date::date)::BIGINT + 86400)';
|
||||
$params[':to_date'] = $to_date;
|
||||
} elseif (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/', $to_date)) {
|
||||
$conds[] = 'e.created_at < EXTRACT(EPOCH FROM :to_date::timestamp)::BIGINT';
|
||||
$params[':to_date'] = $to_date . ':00';
|
||||
}
|
||||
}
|
||||
|
||||
// Follows filter
|
||||
@@ -69,7 +84,8 @@ if ($method === 'GET') {
|
||||
$opts = [
|
||||
'follows_filter' => $_GET['follows_filter'] ?? 'all',
|
||||
'kinds' => $_GET['kinds'] ?? '',
|
||||
'max_age_days' => intval($_GET['max_age_days'] ?? 0),
|
||||
'from_date' => $_GET['from_date'] ?? '',
|
||||
'to_date' => $_GET['to_date'] ?? '',
|
||||
'max_events' => intval($_GET['max_events'] ?? 0),
|
||||
];
|
||||
|
||||
@@ -167,7 +183,8 @@ if ($method === 'POST') {
|
||||
$opts = [
|
||||
'follows_filter' => $body['follows_filter'] ?? 'all',
|
||||
'kinds' => $body['kinds'] ?? [],
|
||||
'max_age_days' => intval($body['max_age_days'] ?? 0),
|
||||
'from_date' => $body['from_date'] ?? '',
|
||||
'to_date' => $body['to_date'] ?? '',
|
||||
'max_events' => intval($body['max_events'] ?? 0),
|
||||
];
|
||||
|
||||
@@ -273,6 +290,13 @@ if ($method === 'POST') {
|
||||
? intval($expected_bytes * ($deleted_count / $expected_count))
|
||||
: 0;
|
||||
|
||||
// Clear stats cache so the dashboard reflects changes immediately
|
||||
$cache_dir = __DIR__ . '/../cache';
|
||||
foreach (['stats_kinds.json', 'stats_pubkeys.json'] as $cache_file) {
|
||||
$path = $cache_dir . '/' . $cache_file;
|
||||
if (is_file($path)) @unlink($path);
|
||||
}
|
||||
|
||||
json_response([
|
||||
'deleted_count' => $deleted_count,
|
||||
'freed_bytes' => $freed_bytes,
|
||||
|
||||
@@ -22,7 +22,7 @@ function fmt_bytes(int $bytes): string {
|
||||
if ($method === 'GET') {
|
||||
try {
|
||||
$rows = $pdo->query(
|
||||
"SELECT id, name, follows_filter, kinds, max_age_days, max_events,\n"
|
||||
"SELECT id, name, follows_filter, kinds, from_date, to_date, max_events,\n"
|
||||
. " last_preview_count, last_preview_size_bytes,\n"
|
||||
. " last_executed_at, created_at, updated_at\n"
|
||||
. " FROM cleanup_saved_queries\n"
|
||||
@@ -50,7 +50,8 @@ if ($method === 'GET') {
|
||||
'name' => $r['name'],
|
||||
'follows_filter' => $r['follows_filter'],
|
||||
'kinds' => $kinds,
|
||||
'max_age_days' => intval($r['max_age_days']),
|
||||
'from_date' => $r['from_date'] ?? '',
|
||||
'to_date' => $r['to_date'] ?? '',
|
||||
'max_events' => intval($r['max_events']),
|
||||
'last_preview_count' => intval($r['last_preview_count']),
|
||||
'last_preview_size_human' => fmt_bytes(intval($r['last_preview_size_bytes'])),
|
||||
@@ -101,8 +102,9 @@ if ($method === 'POST') {
|
||||
// PostgreSQL array literal
|
||||
$kinds_pg = '{' . implode(',', $kinds) . '}';
|
||||
|
||||
$max_age_days = intval($body['max_age_days'] ?? 0);
|
||||
$max_events = intval($body['max_events'] ?? 0);
|
||||
$from_date = $body['from_date'] ?? '';
|
||||
$to_date = $body['to_date'] ?? '';
|
||||
$max_events = intval($body['max_events'] ?? 0);
|
||||
|
||||
try {
|
||||
if ($id) {
|
||||
@@ -112,7 +114,8 @@ if ($method === 'POST') {
|
||||
. " SET name = :name,\n"
|
||||
. " follows_filter = :follows_filter,\n"
|
||||
. " kinds = :kinds::integer[],\n"
|
||||
. " max_age_days = :max_age_days,\n"
|
||||
. " from_date = :from_date,\n"
|
||||
. " to_date = :to_date,\n"
|
||||
. " max_events = :max_events,\n"
|
||||
. " updated_at = EXTRACT(EPOCH FROM NOW())::BIGINT\n"
|
||||
. " WHERE id = :id"
|
||||
@@ -122,20 +125,22 @@ if ($method === 'POST') {
|
||||
':name' => $name,
|
||||
':follows_filter' => $follows_filter,
|
||||
':kinds' => $kinds_pg,
|
||||
':max_age_days' => $max_age_days,
|
||||
':from_date' => $from_date,
|
||||
':to_date' => $to_date,
|
||||
':max_events' => $max_events,
|
||||
]);
|
||||
} else {
|
||||
// Insert new
|
||||
$stmt = $pdo->prepare(
|
||||
"INSERT INTO cleanup_saved_queries\n"
|
||||
. " (name, follows_filter, kinds, max_age_days, max_events)\n"
|
||||
. " (name, follows_filter, kinds, from_date, to_date, max_events)\n"
|
||||
. "VALUES (:name, :follows_filter, :kinds::integer[],\n"
|
||||
. " :max_age_days, :max_events)\n"
|
||||
. " :from_date, :to_date, :max_events)\n"
|
||||
. "ON CONFLICT (name) DO UPDATE SET\n"
|
||||
. " follows_filter = EXCLUDED.follows_filter,\n"
|
||||
. " kinds = EXCLUDED.kinds,\n"
|
||||
. " max_age_days = EXCLUDED.max_age_days,\n"
|
||||
. " from_date = EXCLUDED.from_date,\n"
|
||||
. " to_date = EXCLUDED.to_date,\n"
|
||||
. " max_events = EXCLUDED.max_events,\n"
|
||||
. " updated_at = EXTRACT(EPOCH FROM NOW())::BIGINT"
|
||||
);
|
||||
@@ -143,7 +148,8 @@ if ($method === 'POST') {
|
||||
':name' => $name,
|
||||
':follows_filter' => $follows_filter,
|
||||
':kinds' => $kinds_pg,
|
||||
':max_age_days' => $max_age_days,
|
||||
':from_date' => $from_date,
|
||||
':to_date' => $to_date,
|
||||
':max_events' => $max_events,
|
||||
]);
|
||||
$id = $pdo->lastInsertId();
|
||||
@@ -186,7 +192,7 @@ if ($method === 'POST') {
|
||||
// Load the saved query
|
||||
try {
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT id, name, follows_filter, kinds, max_age_days, max_events\n"
|
||||
"SELECT id, name, follows_filter, kinds, from_date, to_date, max_events\n"
|
||||
. " FROM cleanup_saved_queries\n"
|
||||
. " WHERE id = :id"
|
||||
);
|
||||
@@ -225,10 +231,25 @@ if ($method === 'POST') {
|
||||
$conds[] = 'e.kind IN (' . implode(',', $kind_placeholders) . ')';
|
||||
}
|
||||
|
||||
$max_age_days = intval($query['max_age_days']);
|
||||
if ($max_age_days > 0) {
|
||||
$conds[] = 'e.created_at < EXTRACT(EPOCH FROM NOW())::BIGINT - :max_age_seconds';
|
||||
$params[':max_age_seconds'] = $max_age_days * 86400;
|
||||
$from_date = $query['from_date'] ?? '';
|
||||
$to_date = $query['to_date'] ?? '';
|
||||
if ($from_date !== '') {
|
||||
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $from_date)) {
|
||||
$conds[] = 'e.created_at >= EXTRACT(EPOCH FROM :from_date::date)::BIGINT';
|
||||
$params[':from_date'] = $from_date;
|
||||
} elseif (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/', $from_date)) {
|
||||
$conds[] = 'e.created_at >= EXTRACT(EPOCH FROM :from_date::timestamp)::BIGINT';
|
||||
$params[':from_date'] = $from_date . ':00';
|
||||
}
|
||||
}
|
||||
if ($to_date !== '') {
|
||||
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $to_date)) {
|
||||
$conds[] = 'e.created_at < (EXTRACT(EPOCH FROM :to_date::date)::BIGINT + 86400)';
|
||||
$params[':to_date'] = $to_date;
|
||||
} elseif (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/', $to_date)) {
|
||||
$conds[] = 'e.created_at < EXTRACT(EPOCH FROM :to_date::timestamp)::BIGINT';
|
||||
$params[':to_date'] = $to_date . ':00';
|
||||
}
|
||||
}
|
||||
|
||||
$follows_filter = $query['follows_filter'];
|
||||
@@ -301,6 +322,13 @@ if ($method === 'POST') {
|
||||
]);
|
||||
} catch (PDOException $e) {}
|
||||
|
||||
// Clear stats cache so the dashboard reflects changes immediately
|
||||
$cache_dir = __DIR__ . '/../cache';
|
||||
foreach (['stats_kinds.json', 'stats_pubkeys.json'] as $cache_file) {
|
||||
$path = $cache_dir . '/' . $cache_file;
|
||||
if (is_file($path)) @unlink($path);
|
||||
}
|
||||
|
||||
json_response([
|
||||
'deleted_count' => $deleted_count,
|
||||
'freed_bytes' => $freed_bytes,
|
||||
|
||||
+36
-11
@@ -702,9 +702,11 @@ async function loadCleanupQueries() {
|
||||
: q.follows_filter === 'follows' ? 'Follows'
|
||||
: 'Non-follows';
|
||||
const kindsStr = q.kinds && q.kinds.length > 0 ? q.kinds.join(', ') : 'all';
|
||||
const ageStr = q.max_age_days > 0 ? q.max_age_days + 'd' : '∞';
|
||||
const dateStr = (q.from_date || q.to_date)
|
||||
? `${q.from_date || '…'} → ${q.to_date || '…'}`
|
||||
: 'no date bound';
|
||||
const limitStr = q.max_events > 0 ? q.max_events.toLocaleString() : '∞';
|
||||
const filters = `${filterLabel} | kinds: ${kindsStr} | age: ${ageStr} | max: ${limitStr}`;
|
||||
const filters = `${filterLabel} | kinds: ${kindsStr} | ${dateStr} | max: ${limitStr}`;
|
||||
const previewInfo = q.last_preview_count > 0
|
||||
? `${q.last_preview_count.toLocaleString()} evts (${q.last_preview_size_human})`
|
||||
: '—';
|
||||
@@ -733,22 +735,34 @@ function newCleanupQuery() {
|
||||
r.checked = r.value === 'all';
|
||||
});
|
||||
document.getElementById('cleanup-kinds').value = '';
|
||||
document.getElementById('cleanup-max-age').value = '0';
|
||||
document.getElementById('cleanup-from-date').value = '';
|
||||
document.getElementById('cleanup-from-time').value = '';
|
||||
document.getElementById('cleanup-to-date').value = '';
|
||||
document.getElementById('cleanup-to-time').value = '';
|
||||
document.getElementById('cleanup-max-events').value = '0';
|
||||
document.getElementById('cleanup-results-group').style.display = 'none';
|
||||
document.getElementById('cleanup-name').focus();
|
||||
}
|
||||
|
||||
// ── Combine date + time inputs into a single datetime string ───────────
|
||||
function combineDateTime(dateId, timeId) {
|
||||
const dateVal = document.getElementById(dateId).value;
|
||||
const timeVal = document.getElementById(timeId).value;
|
||||
if (!dateVal) return '';
|
||||
return timeVal ? dateVal + ' ' + timeVal : dateVal;
|
||||
}
|
||||
|
||||
// ── Read filter values from the form ───────────────────────────────────
|
||||
function readCleanupFilters() {
|
||||
const followsEl = document.querySelector('input[name="cleanup-follows"]:checked');
|
||||
const follows_filter = followsEl ? followsEl.value : 'all';
|
||||
const kindsRaw = document.getElementById('cleanup-kinds').value.trim();
|
||||
const kinds = kindsRaw ? kindsRaw.split(',').map(s => parseInt(s.trim(), 10)).filter(n => !isNaN(n) && n > 0) : [];
|
||||
const max_age_days = parseInt(document.getElementById('cleanup-max-age').value, 10) || 0;
|
||||
const from_date = combineDateTime('cleanup-from-date', 'cleanup-from-time');
|
||||
const to_date = combineDateTime('cleanup-to-date', 'cleanup-to-time');
|
||||
const max_events = parseInt(document.getElementById('cleanup-max-events').value, 10) || 0;
|
||||
const name = document.getElementById('cleanup-name').value.trim();
|
||||
return { name, follows_filter, kinds, max_age_days, max_events };
|
||||
return { name, follows_filter, kinds, from_date, to_date, max_events };
|
||||
}
|
||||
|
||||
// ── Preview ────────────────────────────────────────────────────────────
|
||||
@@ -757,7 +771,8 @@ async function previewCleanup(queryId) {
|
||||
const params = new URLSearchParams();
|
||||
params.set('follows_filter', filters.follows_filter);
|
||||
if (filters.kinds.length > 0) params.set('kinds', filters.kinds.join(','));
|
||||
if (filters.max_age_days > 0) params.set('max_age_days', String(filters.max_age_days));
|
||||
if (filters.from_date) params.set('from_date', filters.from_date);
|
||||
if (filters.to_date) params.set('to_date', filters.to_date);
|
||||
if (filters.max_events > 0) params.set('max_events', String(filters.max_events));
|
||||
if (queryId) params.set('query_id', String(queryId));
|
||||
|
||||
@@ -835,7 +850,8 @@ async function saveCleanupQuery() {
|
||||
name: filters.name,
|
||||
follows_filter: filters.follows_filter,
|
||||
kinds: filters.kinds,
|
||||
max_age_days: filters.max_age_days,
|
||||
from_date: filters.from_date,
|
||||
to_date: filters.to_date,
|
||||
max_events: filters.max_events,
|
||||
};
|
||||
|
||||
@@ -864,7 +880,8 @@ async function executeCleanup() {
|
||||
const params = new URLSearchParams();
|
||||
params.set('follows_filter', filters.follows_filter);
|
||||
if (filters.kinds.length > 0) params.set('kinds', filters.kinds.join(','));
|
||||
if (filters.max_age_days > 0) params.set('max_age_days', String(filters.max_age_days));
|
||||
if (filters.from_date) params.set('from_date', filters.from_date);
|
||||
if (filters.to_date) params.set('to_date', filters.to_date);
|
||||
if (filters.max_events > 0) params.set('max_events', String(filters.max_events));
|
||||
|
||||
try {
|
||||
@@ -893,7 +910,8 @@ async function executeCleanupConfirmed() {
|
||||
const body = {
|
||||
follows_filter: filters.follows_filter,
|
||||
kinds: filters.kinds,
|
||||
max_age_days: filters.max_age_days,
|
||||
from_date: filters.from_date,
|
||||
to_date: filters.to_date,
|
||||
max_events: filters.max_events,
|
||||
dry_run: false,
|
||||
};
|
||||
@@ -942,7 +960,13 @@ async function loadSavedCleanupQuery(id) {
|
||||
r.checked = r.value === q.follows_filter;
|
||||
});
|
||||
document.getElementById('cleanup-kinds').value = (q.kinds || []).join(', ');
|
||||
document.getElementById('cleanup-max-age').value = q.max_age_days;
|
||||
// Split stored datetime into date + time parts
|
||||
const fromParts = (q.from_date || '').split(' ');
|
||||
document.getElementById('cleanup-from-date').value = fromParts[0] || '';
|
||||
document.getElementById('cleanup-from-time').value = fromParts[1] || '';
|
||||
const toParts = (q.to_date || '').split(' ');
|
||||
document.getElementById('cleanup-to-date').value = toParts[0] || '';
|
||||
document.getElementById('cleanup-to-time').value = toParts[1] || '';
|
||||
document.getElementById('cleanup-max-events').value = q.max_events;
|
||||
document.getElementById('cleanup-results-group').style.display = 'none';
|
||||
|
||||
@@ -985,7 +1009,8 @@ async function runSavedCleanupExecute(id) {
|
||||
const msg = `Query: ${name}\n`
|
||||
+ `Follows: ${q.follows_filter}\n`
|
||||
+ `Kinds: ${(q.kinds || []).join(', ') || 'all'}\n`
|
||||
+ `Max age: ${q.max_age_days > 0 ? q.max_age_days + ' days' : 'no limit'}\n`
|
||||
+ `From: ${q.from_date || 'no bound'}\n`
|
||||
+ `To: ${q.to_date || 'no bound'}\n`
|
||||
+ `Max events: ${q.max_events > 0 ? q.max_events.toLocaleString() : 'no limit'}`;
|
||||
document.getElementById('cleanup-confirm-msg').textContent = msg;
|
||||
document.getElementById('cleanup-confirm-btn').onclick = async () => {
|
||||
|
||||
@@ -281,6 +281,39 @@ body {
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Cleanup Date/Time Inputs */
|
||||
.datetime-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.cleanup-date-input {
|
||||
font-family: var(--font-family);
|
||||
font-size: 13px;
|
||||
padding: 4px 6px;
|
||||
border: var(--border-width) solid var(--border-color);
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--secondary-color);
|
||||
color: var(--primary-color);
|
||||
width: 160px;
|
||||
}
|
||||
.cleanup-time-input {
|
||||
font-family: var(--font-family);
|
||||
font-size: 13px;
|
||||
padding: 4px 6px;
|
||||
border: var(--border-width) solid var(--border-color);
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--secondary-color);
|
||||
color: var(--primary-color);
|
||||
width: 110px;
|
||||
}
|
||||
.datetime-hint {
|
||||
font-size: 11px;
|
||||
color: var(--muted-color);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Cleanup Confirmation Modal */
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
[{"kind":9734,"count":110,"pct":27},{"kind":1,"count":82,"pct":20.1},{"kind":7,"count":64,"pct":15.7},{"kind":6,"count":60,"pct":14.7},{"kind":9735,"count":40,"pct":9.8},{"kind":30023,"count":21,"pct":5.1},{"kind":3,"count":21,"pct":5.1},{"kind":0,"count":10,"pct":2.5}]
|
||||
[{"kind":1,"count":501,"pct":56.8},{"kind":7,"count":200,"pct":22.7},{"kind":9734,"count":110,"pct":12.5},{"kind":6,"count":30,"pct":3.4},{"kind":9735,"count":20,"pct":2.3},{"kind":3,"count":11,"pct":1.2},{"kind":0,"count":10,"pct":1.1}]
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
[{"pubkey":"4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa","name":"","count":65,"pct":15.9},{"pubkey":"fafcce41dbb17750b783ad2fe6606df2bf70955b5bc5a1a78afcc7be16b26ab0","name":"Random User 2","count":23,"pct":5.6},{"pubkey":"df0bbae9124f119fdd8922bfa43f2656e2deb34dae16a4188cd0e00d12f48d85","name":"Random User 1","count":23,"pct":5.6},{"pubkey":"253ec263fa72cfa593a33ee4dfa3b3d833668d0f3f3e12cb88ff1109c05bb712","name":"Random User 4","count":22,"pct":5.4},{"pubkey":"b05fb80ef9960911dabf97f10b182591c008b667cc4513284f1c5b7df302622b","name":"Random User 3","count":22,"pct":5.4},{"pubkey":"d6b61be8dd5a669221c1770ee49cc97b3e221567d576420f762db5700755e9bd","name":"Random User 10","count":21,"pct":5.1},{"pubkey":"d0943be7ba866370027df8d9a2d6a757392f1880f344b42471aac0571d1d11a5","name":"Random User 6","count":21,"pct":5.1},{"pubkey":"4d6e38f64387f93d9af8f3ae99fcde23e5538f84340f515fe464d0c42ba81fe1","name":"Random User 5","count":21,"pct":5.1},{"pubkey":"81929c19ddd81808a62247eb619e9548fdea9f4064e2e057a2ac4fc6002571d0","name":"Random User 9","count":21,"pct":5.1},{"pubkey":"8640249396606e31ee2cbedc6011513c6bcf3466c7bdaaacbec96c27706357dd","name":"Random User 8","count":21,"pct":5.1},{"pubkey":"cff3d98aa4ffc84e8b01ecaf6fdd9a30c270cf0af2af30ed516bebd039e6fcef","name":"Random User 7","count":21,"pct":5.1},{"pubkey":"493d211f170111a35d8c4028e74f3550936c1f3273803ead00d8d2e529a4b967","name":"","count":14,"pct":3.4},{"pubkey":"550f9c4484b7dd365f4c3df1a3b709599346f9c3221cdb476896eb08fbd92fd0","name":"","count":14,"pct":3.4},{"pubkey":"7d14ef6a945885d67af97dda0b54959d93b3ee0a652a05bedca856fb1449daf5","name":"","count":13,"pct":3.2},{"pubkey":"4f649d5815be5c8ddd10f56d7e9d05e7ab5a93b5e9b66d5dd854de9300baf1ec","name":"","count":13,"pct":3.2},{"pubkey":"7cfcbf945c83dae3e7b4d0ddfaf36f6bb7dbd47e6f88f4d4b736982d19a0e728","name":"","count":12,"pct":2.9},{"pubkey":"d30ab858062ff661f0ce91abd79759718239c315eedbadefa62115f175e35b1b","name":"","count":12,"pct":2.9},{"pubkey":"a5deff416bf0085763c4b7bb0d6c895db13348d3028b2136f42d6e2358c8de9b","name":"","count":12,"pct":2.9},{"pubkey":"9de0cb3cf82b7e30d01db7f9909d727778a86fc04486d8b2e747bf0a01d3d439","name":"","count":12,"pct":2.9},{"pubkey":"213e6b7a4537d406d5584552ed8901712cb3bc2d1f04948ef808a9ad9578dc6a","name":"","count":12,"pct":2.9}]
|
||||
[{"pubkey":"4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa","name":"","count":182,"pct":20.6},{"pubkey":"eff555c8453f665bb54f907188aefba0e85c29aa9f5c30fa13d78d003c71265c","name":"Random User 4","count":70,"pct":7.9},{"pubkey":"9a90e4db8996e235a5bf1501013149d5f250b60e79336b69035f0b4dab8a4302","name":"Random User 9","count":70,"pct":7.9},{"pubkey":"b80c8c5fb175c50fe97d3a63658fa8b5dcc3e20da22dff8cef54317f6fe25394","name":"Random User 7","count":70,"pct":7.9},{"pubkey":"3d68fc5c3ddf8feef6cb6345817e4c6e421b5d292bef0be8d9a4809a23a4f0f5","name":"Random User 1","count":70,"pct":7.9},{"pubkey":"1c38f0e5446b8f5d7bc074f9f4b7afe85980706e765a5b1a3e4a52504e521ec1","name":"Random User 6","count":70,"pct":7.9},{"pubkey":"084857a219f6d73ec30fb90376e6f30161b07cd5d2130dffe47d32f229610b8a","name":"Random User 5","count":70,"pct":7.9},{"pubkey":"71691b130642de5af2b7f0a5ecf4eb374c46d913dbc72bc802005b24f9e87e11","name":"Random User 8","count":70,"pct":7.9},{"pubkey":"8d8b59e842e1529e0c448f05e570eccca82d9ca4500b758c9d44f478e96e8cdf","name":"Random User 10","count":70,"pct":7.9},{"pubkey":"f4bd9e04029c11440d545ffa66aeac45b87becf4075e2f321b0f5e8c30f187c2","name":"Random User 2","count":70,"pct":7.9},{"pubkey":"f2c0cadeee26653d9d2acd3788f6cc26d19b680d439640501eb1545afb94dd56","name":"Random User 3","count":70,"pct":7.9}]
|
||||
+14
-2
@@ -453,8 +453,20 @@ $display_name = $relay_version ? ($relay_name . ' ' . $relay_version) : $relay_n
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="cleanup-max-age">Max Age (days, 0 = no limit):</label>
|
||||
<input type="number" id="cleanup-max-age" value="0" min="0" style="width:120px">
|
||||
<label>From (delete events after this):</label>
|
||||
<div class="datetime-group">
|
||||
<input type="date" id="cleanup-from-date" class="cleanup-date-input">
|
||||
<input type="time" id="cleanup-from-time" class="cleanup-time-input">
|
||||
<span class="datetime-hint">leave empty for no bound</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>To (delete events before this):</label>
|
||||
<div class="datetime-group">
|
||||
<input type="date" id="cleanup-to-date" class="cleanup-date-input">
|
||||
<input type="time" id="cleanup-to-time" class="cleanup-time-input">
|
||||
<span class="datetime-hint">leave empty for no bound</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="cleanup-max-events">Max Events (0 = no limit):</label>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -209,6 +209,24 @@ if [ -n "$RELAY_KEY" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Load test keys from .test_keys file if USE_TEST_KEYS is true and no explicit keys given
|
||||
if [ "$USE_TEST_KEYS" = true ] && [ -z "$ADMIN_KEY" ] && [ -z "$RELAY_KEY" ]; then
|
||||
if [ -f ".test_keys" ]; then
|
||||
echo "Reading test keys from .test_keys file..."
|
||||
source .test_keys
|
||||
ADMIN_KEY=$(echo "$ADMIN_PUBKEY" | tr -d "'")
|
||||
RELAY_KEY=$(echo "$SERVER_PRIVKEY" | tr -d "'")
|
||||
echo "Using admin pubkey from .test_keys: ${ADMIN_KEY:0:16}..."
|
||||
echo "Using relay privkey from .test_keys: ${RELAY_KEY:0:16}..."
|
||||
else
|
||||
echo "ERROR: .test_keys file not found"
|
||||
echo "Please create a .test_keys file with the following format:"
|
||||
echo " ADMIN_PUBKEY='your_admin_public_key_hex'"
|
||||
echo " SERVER_PRIVKEY='your_relay_private_key_hex'"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Validate port if provided
|
||||
if [ -n "$PORT_OVERRIDE" ]; then
|
||||
if ! [[ "$PORT_OVERRIDE" =~ ^[0-9]+$ ]] || [ "$PORT_OVERRIDE" -lt 1 ] || [ "$PORT_OVERRIDE" -gt 65535 ]; then
|
||||
|
||||
+2
-2
@@ -13,8 +13,8 @@
|
||||
// Using CRELAY_ prefix to avoid conflicts with nostr_core_lib VERSION macros
|
||||
#define CRELAY_VERSION_MAJOR 2
|
||||
#define CRELAY_VERSION_MINOR 1
|
||||
#define CRELAY_VERSION_PATCH 30
|
||||
#define CRELAY_VERSION "v2.1.30"
|
||||
#define CRELAY_VERSION_PATCH 35
|
||||
#define CRELAY_VERSION "v2.1.35"
|
||||
|
||||
// Relay metadata (authoritative source for NIP-11 information)
|
||||
#define RELAY_NAME "C-Relay-PG"
|
||||
|
||||
+2
-1
@@ -752,7 +752,8 @@ static const char* const EMBEDDED_PG_SCHEMA_SQL =
|
||||
" follows_filter TEXT NOT NULL DEFAULT 'all'\n"
|
||||
" CHECK (follows_filter IN ('all', 'follows', 'non_follows')),\n"
|
||||
" kinds INTEGER[] NOT NULL DEFAULT '{}',\n"
|
||||
" max_age_days INTEGER NOT NULL DEFAULT 0,\n"
|
||||
" from_date TEXT NOT NULL DEFAULT '',\n"
|
||||
" to_date TEXT NOT NULL DEFAULT '',\n"
|
||||
" max_events INTEGER NOT NULL DEFAULT 0,\n"
|
||||
" last_preview_count INTEGER NOT NULL DEFAULT 0,\n"
|
||||
" last_preview_size_bytes BIGINT NOT NULL DEFAULT 0,\n"
|
||||
|
||||
Reference in New Issue
Block a user