Skip to content

Commit 224aeee

Browse files
committed
Add collector credential forms to Settings page
Settings now has expandable per-service sections for entering API credentials (email/password, tokens, API URLs) without deploying containers. Enables monitoring-only users to track earnings from existing containers. Includes "Test Collection Now" button.
1 parent c7cc375 commit 224aeee

3 files changed

Lines changed: 233 additions & 13 deletions

File tree

app/static/css/style.css

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,3 +1466,46 @@ img { max-width: 100%; }
14661466
.onboarding-options { grid-template-columns: 1fr; }
14671467
.onboarding-card { padding: 1.5rem; margin: 1rem; }
14681468
}
1469+
1470+
/* ----- Collector Credential Sections ----- */
1471+
.collector-section {
1472+
border: 1px solid var(--border-color);
1473+
border-radius: 8px;
1474+
margin-bottom: 8px;
1475+
background: var(--bg-secondary);
1476+
}
1477+
.collector-section[open] {
1478+
border-color: var(--border-light);
1479+
}
1480+
.collector-header {
1481+
display: flex;
1482+
align-items: center;
1483+
justify-content: space-between;
1484+
padding: 12px 16px;
1485+
cursor: pointer;
1486+
user-select: none;
1487+
list-style: none;
1488+
}
1489+
.collector-header::-webkit-details-marker { display: none; }
1490+
.collector-header::before {
1491+
content: '';
1492+
display: inline-block;
1493+
width: 6px;
1494+
height: 6px;
1495+
border-right: 2px solid var(--text-muted);
1496+
border-bottom: 2px solid var(--text-muted);
1497+
transform: rotate(-45deg);
1498+
margin-right: 12px;
1499+
transition: transform 0.15s;
1500+
}
1501+
.collector-section[open] .collector-header::before {
1502+
transform: rotate(45deg);
1503+
}
1504+
.collector-name {
1505+
font-weight: 600;
1506+
font-size: 0.95rem;
1507+
color: var(--text-primary);
1508+
}
1509+
.collector-body {
1510+
padding: 0 16px 16px;
1511+
}

app/static/js/app.js

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,21 @@ const CP = (() => {
883883
try {
884884
const config = await api('/api/config');
885885
populateSettings(config);
886+
887+
// Populate collector credential fields from config
888+
document.querySelectorAll('.collector-input').forEach(input => {
889+
const key = input.dataset.config;
890+
if (config[key]) {
891+
// Mask passwords/tokens but show that a value exists
892+
if (input.type === 'password') {
893+
input.value = '********';
894+
input.placeholder = 'Value saved (enter new to replace)';
895+
} else {
896+
input.value = config[key];
897+
}
898+
}
899+
});
900+
updateCollectorStatuses();
886901
} catch (err) {
887902
// Settings may not be available yet
888903
}
@@ -960,10 +975,65 @@ const CP = (() => {
960975
}
961976

962977
async function editCredentials(slug) {
963-
// Open a prompt-style flow to edit credentials
964978
toast(`Edit credentials for ${slug} — coming soon`, 'info');
965979
}
966980

981+
async function saveCollectorCredentials() {
982+
const inputs = document.querySelectorAll('.collector-input');
983+
const data = {};
984+
inputs.forEach(input => {
985+
const key = input.dataset.config;
986+
const val = input.value.trim();
987+
// Only save non-empty, non-masked values
988+
if (val && val !== '********') {
989+
data[key] = val;
990+
}
991+
});
992+
993+
if (Object.keys(data).length === 0) {
994+
toast('No credentials to save', 'warning');
995+
return;
996+
}
997+
998+
try {
999+
await api('/api/config', { method: 'POST', body: { data } });
1000+
toast('Credentials saved', 'success');
1001+
updateCollectorStatuses();
1002+
} catch (err) {
1003+
toast(`Save failed: ${err.message}`, 'error');
1004+
}
1005+
}
1006+
1007+
async function testCollectors() {
1008+
const statusEl = document.getElementById('collector-save-status');
1009+
if (statusEl) statusEl.textContent = 'Running collection...';
1010+
try {
1011+
await api('/api/collect', { method: 'POST' });
1012+
toast('Collection started. Check dashboard in a moment.', 'success');
1013+
if (statusEl) statusEl.textContent = 'Collection triggered';
1014+
} catch (err) {
1015+
toast(`Collection failed: ${err.message}`, 'error');
1016+
if (statusEl) statusEl.textContent = '';
1017+
}
1018+
}
1019+
1020+
function updateCollectorStatuses() {
1021+
const configuredServices = ['honeygain', 'earnapp', 'iproyal', 'traffmonetizer', 'mysterium', 'storj'];
1022+
configuredServices.forEach(slug => {
1023+
const badge = document.getElementById(`status-${slug}`);
1024+
if (!badge) return;
1025+
const inputs = document.querySelectorAll(`.collector-input[data-config^="${slug}_"]`);
1026+
let hasValue = false;
1027+
inputs.forEach(input => {
1028+
if (input.value.trim() && input.value !== '********') hasValue = true;
1029+
});
1030+
if (hasValue) {
1031+
badge.textContent = 'Configured';
1032+
badge.className = 'badge badge-deployed';
1033+
}
1034+
});
1035+
}
1036+
9671037
// -----------------------------------------------------------
9681038
// Utility
9691039
// -----------------------------------------------------------
@@ -1054,6 +1124,8 @@ const CP = (() => {
10541124
openServiceDetail,
10551125
loadDetailLogs,
10561126
saveSettings,
1127+
saveCollectorCredentials,
1128+
testCollectors,
10571129
editCredentials,
10581130
filterCatalog,
10591131
};

app/templates/settings.html

Lines changed: 117 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,28 +32,133 @@ <h3 class="settings-section-title">General</h3>
3232
</div>
3333
</div>
3434

35-
<!-- Referral Codes -->
35+
<!-- Earnings Collection Credentials -->
3636
<div class="card settings-section">
37-
<h3 class="settings-section-title">Referral Codes</h3>
38-
<p class="settings-section-desc">Your referral codes for each service. New users who sign up through your links earn you bonuses.</p>
37+
<h3 class="settings-section-title">Earnings Collection</h3>
38+
<p class="settings-section-desc">
39+
Enter credentials for services you want to track earnings from.
40+
You don't need to deploy containers through CashPilot &mdash; just add your credentials and earnings will be collected automatically.
41+
</p>
3942

40-
<div id="settings-referrals">
41-
<p class="form-hint">No services configured yet. Deploy a service first.</p>
43+
<!-- Honeygain -->
44+
<details class="collector-section">
45+
<summary class="collector-header">
46+
<span class="collector-name">Honeygain</span>
47+
<span class="badge badge-category" id="status-honeygain">Not configured</span>
48+
</summary>
49+
<div class="collector-body">
50+
<div class="form-group">
51+
<label class="form-label">Email</label>
52+
<input class="form-input collector-input" type="text" data-config="honeygain_email" placeholder="Your Honeygain email">
53+
</div>
54+
<div class="form-group">
55+
<label class="form-label">Password</label>
56+
<input class="form-input collector-input" type="password" data-config="honeygain_password" placeholder="Your Honeygain password">
57+
</div>
58+
</div>
59+
</details>
60+
61+
<!-- EarnApp -->
62+
<details class="collector-section">
63+
<summary class="collector-header">
64+
<span class="collector-name">EarnApp</span>
65+
<span class="badge badge-category" id="status-earnapp">Not configured</span>
66+
</summary>
67+
<div class="collector-body">
68+
<div class="form-group">
69+
<label class="form-label">OAuth Token</label>
70+
<input class="form-input collector-input" type="password" data-config="earnapp_oauth_token"
71+
placeholder="From browser: F12 > Application > Cookies > oauth-refresh-token">
72+
<div class="form-hint">Open earnapp.com, press F12, go to Application > Cookies, and copy the <code>oauth-refresh-token</code> value.</div>
73+
</div>
74+
</div>
75+
</details>
76+
77+
<!-- IPRoyal Pawns -->
78+
<details class="collector-section">
79+
<summary class="collector-header">
80+
<span class="collector-name">IPRoyal Pawns</span>
81+
<span class="badge badge-category" id="status-iproyal">Not configured</span>
82+
</summary>
83+
<div class="collector-body">
84+
<div class="form-group">
85+
<label class="form-label">Email</label>
86+
<input class="form-input collector-input" type="text" data-config="iproyal_email" placeholder="Your Pawns email">
87+
</div>
88+
<div class="form-group">
89+
<label class="form-label">Password</label>
90+
<input class="form-input collector-input" type="password" data-config="iproyal_password" placeholder="Your Pawns password">
91+
</div>
92+
</div>
93+
</details>
94+
95+
<!-- Traffmonetizer -->
96+
<details class="collector-section">
97+
<summary class="collector-header">
98+
<span class="collector-name">Traffmonetizer</span>
99+
<span class="badge badge-category" id="status-traffmonetizer">Not configured</span>
100+
</summary>
101+
<div class="collector-body">
102+
<div class="form-group">
103+
<label class="form-label">API Token</label>
104+
<input class="form-input collector-input" type="password" data-config="traffmonetizer_token"
105+
placeholder="From browser: F12 > Local Storage > token">
106+
<div class="form-hint">Open app.traffmonetizer.com, press F12, go to Application > Local Storage, and copy the <code>token</code> value.</div>
107+
</div>
108+
</div>
109+
</details>
110+
111+
<!-- MystNodes -->
112+
<details class="collector-section">
113+
<summary class="collector-header">
114+
<span class="collector-name">MystNodes (Mysterium)</span>
115+
<span class="badge badge-category" id="status-mysterium">Not configured</span>
116+
</summary>
117+
<div class="collector-body">
118+
<div class="form-group">
119+
<label class="form-label">Tequila API URL</label>
120+
<input class="form-input collector-input" type="text" data-config="mysterium_api_url"
121+
value="http://localhost:4449" placeholder="http://localhost:4449">
122+
<div class="form-hint">The Mysterium node's local API. Default: <code>http://localhost:4449</code>. Change if your node runs on another host.</div>
123+
</div>
124+
</div>
125+
</details>
126+
127+
<!-- Storj -->
128+
<details class="collector-section">
129+
<summary class="collector-header">
130+
<span class="collector-name">Storj</span>
131+
<span class="badge badge-category" id="status-storj">Not configured</span>
132+
</summary>
133+
<div class="collector-body">
134+
<div class="form-group">
135+
<label class="form-label">Storagenode API URL</label>
136+
<input class="form-input collector-input" type="text" data-config="storj_api_url"
137+
value="http://localhost:14002" placeholder="http://localhost:14002">
138+
<div class="form-hint">Your storagenode's local dashboard API. Default: <code>http://localhost:14002</code>.</div>
139+
</div>
140+
</div>
141+
</details>
142+
143+
<div style="margin-top: 16px; display: flex; gap: 8px; align-items: center;">
144+
<button class="btn btn-primary" onclick="CP.saveCollectorCredentials()">Save Credentials</button>
145+
<button class="btn btn-secondary" onclick="CP.testCollectors()">Test Collection Now</button>
146+
<span id="collector-save-status" style="font-size: 0.85rem; color: var(--text-muted);"></span>
42147
</div>
43148
</div>
44149

45-
<!-- Credentials -->
150+
<!-- Referral Codes -->
46151
<div class="card settings-section">
47-
<h3 class="settings-section-title">Saved Credentials</h3>
48-
<p class="settings-section-desc">Credentials for deployed services. Passwords are stored encrypted.</p>
152+
<h3 class="settings-section-title">Referral Codes</h3>
153+
<p class="settings-section-desc">Your referral codes for each service. New users who sign up through your links earn you bonuses.</p>
49154

50-
<div id="settings-credentials">
51-
<p class="form-hint">No saved credentials yet. Deploy a service to add credentials.</p>
155+
<div id="settings-referrals">
156+
<p class="form-hint">No services configured yet. Deploy a service first.</p>
52157
</div>
53158
</div>
54159

55-
<!-- Save -->
160+
<!-- Save General -->
56161
<div style="display: flex; justify-content: flex-end; margin-top: 8px;">
57-
<button class="btn btn-primary btn-lg" onclick="CP.saveSettings()">Save Settings</button>
162+
<button class="btn btn-primary btn-lg" onclick="CP.saveSettings()">Save General Settings</button>
58163
</div>
59164
{% endblock %}

0 commit comments

Comments
 (0)