• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

marscoin / martianrepublic / 23825068715

31 Mar 2026 11:59PM UTC coverage: 11.001% (+0.6%) from 10.419%
23825068715

push

github

Martian Congress
feat: A2 service layer — IpfsService + ProposalService with tests

New services extracted from controllers:

IpfsService (app/Services/IpfsService.php):
  - pinFile(), pinContent(), pinFolder() — local IPFS node API
  - get() — retrieve via gateway
  - isValidCID(), gatewayUrl() — validation + URL generation
  - Used by ContentApiController (replaces AppHelper::upload)

ProposalService (app/Services/ProposalService.php):
  - syncPhases() — screening→voting→sunset transitions
  - tallyVotes() — count YES/NO with pass/fail threshold
  - getStats() — dashboard counts
  - Used by CongressController (replaces inline logic)

Tests (10 new, total 146):
  - CID validation, gateway URLs, pinFile null safety
  - Phase transitions, vote tallying (pass + fail), stats
  - BlockchainRpc config reading
  - All SQLite-compatible (no MySQL-only syntax in tests)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

42 of 112 new or added lines in 3 files covered. (37.5%)

1 existing line in 1 file now uncovered.

643 of 5845 relevant lines covered (11.0%)

1.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

28.46
/app/Http/Controllers/StatusController.php
1
<?php
2

3
namespace App\Http\Controllers;
4

5
use App\Includes\AppHelper;
6
use App\Includes\jsonRPCClient;
7
use Carbon\Carbon;
8
use Exception;
9
use Illuminate\Http\Response;
10
use Illuminate\Support\Facades\Cache;
11
use Illuminate\Support\Facades\DB;
12
use Illuminate\Support\Facades\Log;
13
use Illuminate\Support\Facades\View;
14

15
class StatusController extends Controller
16
{
17
    /**
18
     * Setup the layout used by the controller.
19
     *
20
     * @return void
21
     */
22
    public function __construct() {}
1✔
23

24
    protected function showStatus()
1✔
25
    {
26
        // Cache status results for 60 seconds to avoid slow RPC calls on every page load
27
        $cached = Cache::remember('status_page_data', 60, function () {
1✔
28
            return $this->collectStatusData();
1✔
29
        });
1✔
30

31
        $view = View::make('status');
×
32
        $view->web_status = $cached['web_status'];
×
33
        $view->mysql_status = $cached['mysql_status'];
×
34
        $view->marscoind_status = $cached['marscoind_status'];
×
35
        $view->network = $cached['network'];
×
36
        $view->blockexplorer = $cached['blockexplorer'];
×
37
        $view->pebas_status = $cached['pebas_status'];
×
38
        $view->ipfs_status = $cached['ipfs_status'];
×
39
        $view->blockchain_tracker_status = $cached['blockchain_tracker_status'];
×
40
        $view->ballot_server_status = $cached['ballot_server_status'];
×
41

42
        return $view;
×
43
    }
44

45
    protected function collectStatusData()
1✔
46
    {
47
        $web_status = 'danger';
1✔
48
        $mysql_status = 'danger';
1✔
49
        $marscoind_status = 'danger';
1✔
50

51
        $blockexplorer = 'danger';
1✔
52
        $pebas_status = 'danger';
1✔
53
        $ipfs_status = 'danger';
1✔
54

55
        // apache webserver check
56
        try {
57
            $a = AppHelper::file_get_contents_curl('http://127.0.0.1');
1✔
58
            if ($a) {
1✔
59
                $web_status = 'success';
×
60
            } else {
61
                $web_status = 'danger';
1✔
62
            }
63
        } catch (Exception $e) {
×
64
            $web_status = 'danger';
×
65
        }
66

67
        // Test database connection
68
        try {
69
            DB::connection()->getPdo();
1✔
70
            $mysql_status = 'success';
1✔
71
        } catch (Exception $e) {
×
72
            $mysql_status = 'danger';
×
73
        }
74

75
        try {
76
            $data = json_decode(file_get_contents('/home/mars/constitution/marswallet.json'), true);
1✔
77
            $RPC_Host = $data['rpc_host'];
×
78
            $RPC_Port = $data['rpc_port'];
×
79
            $RPC_User = $data['rpc_user'];
×
80
            $RPC_Pass = $data['rpc_pass'];
×
81

82
            $nu92u5p9u2np8uj5wr = 'http://'.$RPC_User.':'.$RPC_Pass.'@'.$RPC_Host.':'.$RPC_Port.'/';
×
83
            $Marscoind = new jsonRPCClient($nu92u5p9u2np8uj5wr);
×
84
            $network = $Marscoind->getNetworkInfo();
×
85

86
            // Also fetch blockchain info for blocks/difficulty (separate RPC call in v28+)
87
            try {
88
                $blockchain = $Marscoind->getBlockchainInfo();
×
89
                $network['blocks'] = $blockchain['blocks'] ?? 0;
×
90
                $network['difficulty'] = $blockchain['difficulty'] ?? 0;
×
91
            } catch (Exception $e) {
×
92
                $network['blocks'] = 0;
×
93
                $network['difficulty'] = 0;
×
94
            }
95

96
            // Check specific fields in the response
97
            $marscoind_status = (isset($network['version']) && isset($network['protocolversion'])) ? 'success' : 'danger';
×
98

99
        } catch (Exception $e) {
1✔
100
            Log::debug('Exception caught: '.$e->getMessage());
1✔
101
            $marscoind_status = 'danger';
1✔
102
            $network = [];
1✔
103
        }
104

105
        // blockexplorer check
106
        try {
107
            $json = AppHelper::file_get_contents_curl(config('blockchain.explorer.primary_url').'/api/status?q=getInfo');
1✔
108
            $a = json_decode($json, true);
1✔
109
            if ($a) {
1✔
110
                $blockexplorer = 'success';
1✔
111
            } else {
112
                $blockexplorer = 'danger';
1✔
113
            }
114
        } catch (Exception $e) {
×
115
            $blockexplorer = 'danger';
×
116
        }
117

118
        // pebas api check
119
        try {
120
            $json = AppHelper::file_get_contents_curl(config('blockchain.pebas.public_url').'/api/mars/utxo?sender_address=MRKAuE7k9UhANQ8JjoU5A9KACic5Rt2Diz&receiver_address=MRKAuE7k9UhANQ8JjoU5A9KACic5Rt2Diz&amount=0.1');
1✔
121
            $a = json_decode($json, true);
1✔
122
            // Log::debug($a);
123
            if ($a) {
1✔
UNCOV
124
                $pebas_status = 'success';
×
125
            } else {
126
                $pebas_status = 'danger';
1✔
127
            }
128
        } catch (Exception $e) {
×
129
            $pebas_status = 'danger';
×
130
        }
131

132
        // ipfs node check
133
        try {
134
            $a = AppHelper::file_get_contents_curl(config('blockchain.ipfs.api_url').'/api/v0/swarm/peers');
1✔
135
            if ($a) {
1✔
136
                $ipfs_status = 'success';
×
137
            } else {
138
                $ipfs_status = 'danger';
1✔
139
            }
140
        } catch (Exception $e) {
×
141
            $ipfs_status = 'danger';
×
142
        }
143

144
        // Check the blockchain tracker status
145
        // In your check method
146
        $lastProcessed = $this->getLastProcessedTimestamp();
1✔
147
        $now = Carbon::now(); // Use same timezone as database
×
148

149
        Log::debug('Last Processed: '.$lastProcessed);
×
150
        Log::debug('Now: '.$now);
×
151
        Log::debug('Diff in minutes: '.$lastProcessed->diffInMinutes($now));
×
152

153
        if ($lastProcessed->diffInMinutes($now) <= 15) {
×
154
            Log::debug('Success - diff is under 15 mins');
×
155
            $blockchain_tracker_status = 'success';
×
156
        } else {
157
            Log::debug('Danger - diff is over 15 mins');
×
158
            $blockchain_tracker_status = 'danger';
×
159
        }
160

161
        // Check the ballot shuffle server status
162
        $ballot_server_status = $this->checkBallotServer();
×
163

164
        return [
×
165
            'web_status' => $web_status,
×
166
            'mysql_status' => $mysql_status,
×
167
            'marscoind_status' => $marscoind_status,
×
168
            'network' => $network,
×
169
            'blockexplorer' => $blockexplorer,
×
170
            'pebas_status' => $pebas_status,
×
171
            'ipfs_status' => $ipfs_status,
×
172
            'blockchain_tracker_status' => $blockchain_tracker_status,
×
173
            'ballot_server_status' => $ballot_server_status,
×
174
        ];
×
175
    }
176

177
    public function getSystemStatus()
×
178
    {
179
        $response = [
×
180
            'ipfs_status' => 'offline',
×
181
            'blockchain_tracker_status' => 'offline',
×
182
            'ballot_server_status' => 'offline',
×
183
        ];
×
184

185
        // IPFS node check
186
        try {
187
            $a = AppHelper::file_get_contents_curl(config('blockchain.ipfs.api_url').'/api/v0/swarm/peers');
×
188
            $response['ipfs_status'] = $a ? 'online' : 'offline';
×
189
        } catch (Exception $e) {
×
190
            $response['ipfs_status'] = 'offline';
×
191
        }
192

193
        // Blockchain tracker status
194
        try {
195
            $lastProcessed = $this->getLastProcessedTimestamp();
×
196
            $now = Carbon::now();
×
197
            $response['blockchain_tracker_status'] = $lastProcessed->diffInMinutes($now) <= 15 ? 'online' : 'offline';
×
198
        } catch (Exception $e) {
×
199
            $response['blockchain_tracker_status'] = 'offline';
×
200
        }
201

202
        // Ballot server status
203
        $response['ballot_server_status'] = $this->checkBallotServer();
×
204

205
        return response()->json($response);
×
206
    }
207

208
    private function checkBallotServer($host = null, $port = null)
×
209
    {
210
        $host = $host ?? config('blockchain.ballot.host', '127.0.0.1');
×
211
        $port = $port ?? config('blockchain.ballot.port', 3678);
×
212
        $context = stream_context_create([
×
213
            'ssl' => [
×
214
                'verify_peer' => false,
×
215
                'verify_peer_name' => false,
×
216
                'allow_self_signed' => true,
×
217
            ],
×
218
        ]);
×
219
        $socket = @stream_socket_client('ssl://'.$host.':'.$port, $errno, $errstr, 5, STREAM_CLIENT_CONNECT, $context);
×
220
        if ($socket) {
×
221
            fclose($socket);
×
222

223
            return 'success';
×
224
        }
225

226
        return 'danger';
×
227
    }
228

229
    private function getLastProcessedTimestamp()
1✔
230
    {
231
        $lastLog = DB::table('feed_log')->latest('processed_at')->first();
1✔
232

233
        return Carbon::createFromFormat('Y-m-d H:i:s', $lastLog->processed_at, 'America/New_York')
×
234
            ->setTimezone('UTC');
×
235
    }
236
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc