Skip to content

Commit 823a5fe

Browse files
committed
Add a Final module for reference.
1 parent ac4e026 commit 823a5fe

File tree

10 files changed

+679
-3
lines changed

10 files changed

+679
-3
lines changed

composer.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
"Notes\\Module2\\": "module-2/server/",
2525
"Notes\\Module3\\": "module-3/server/",
2626
"Notes\\Module4\\": "module-4/server/",
27-
"Notes\\Module5\\": "module-5/server/"
27+
"Notes\\Module5\\": "module-5/server/",
28+
"Notes\\ModuleFinal\\": "module-final/server/"
2829
},
2930
"files": [
3031
"util/Database.php",
@@ -33,7 +34,8 @@
3334
"util/types/Note.php",
3435
"util/types/User.php",
3536
"module-1/config.php",
36-
"module-5/config.php"
37+
"module-5/config.php",
38+
"module-final/config.php"
3739
]
3840
}
3941
}

module-3/client/notes.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ protected function setup(Options $options)
5555
}
5656

5757
$this->client = new GuzzleHttp\Client(['base_uri' => 'http://localhost:8888']);
58-
$this->token = file_get_contents('.session');
58+
$this->token = @file_get_contents('.session');
5959
}
6060

6161
protected function createNote($contents)

module-final/client/notes.php

Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
#!/usr/bin/php
2+
<?php
3+
4+
include __DIR__ . '/../../vendor/autoload.php';
5+
6+
use splitbrain\phpcli\CLI;
7+
use splitbrain\phpcli\Colors;
8+
use splitbrain\phpcli\Options;
9+
use splitbrain\phpcli\TableFormatter;
10+
11+
class ModuleFinal extends CLI
12+
{
13+
/**
14+
* @var GuzzleHttp\Client
15+
*/
16+
private $client;
17+
private $token;
18+
19+
private $user;
20+
21+
private $pass;
22+
23+
const TABLE_WIDTH = ['9', '*'];
24+
const TABLE_STYLE = [Colors::C_CYAN, Colors::C_GREEN];
25+
26+
protected function setup(Options $options)
27+
{
28+
$options->setHelp('This client is built to operate against the server defined in Module 1 only.');
29+
30+
$options->registerCommand('create', 'Create a new note.');
31+
$options->registerCommand('get', 'Get a specific note.');
32+
$options->registerCommand('delete', 'Delete a specific note.');
33+
$options->registerCommand('all', 'Get all notes.');
34+
35+
$options->registerCommand('register', 'Create a user account.');
36+
$options->registerCommand('changePassword', 'Change your user password');
37+
$options->registerCommand('login', 'Create a persistent authentication session');
38+
39+
$options->registerArgument('note', 'Actual note to store.', true, 'create');
40+
$options->registerArgument('noteId', 'Identify the note to retrieve.', true, 'get');
41+
$options->registerArgument('noteId', 'Identify the note to delete.', true, 'delete');
42+
43+
$options->registerOption('email', 'Email address', 'e', true, 'register');
44+
$options->registerOption('password', 'Login password', 'p', true, 'register');
45+
$options->registerOption('repeat-password', 'Login password (again)', 'r', true, 'register');
46+
$options->registerOption('greeting', 'User name or greeting', 'g', true, 'register');
47+
$options->registerOption('email', 'Email address', 'e', true, 'changePassword');
48+
$options->registerOption('old-password', 'Old login password', 'o', true, 'changePassword');
49+
$options->registerOption('new-password', 'New login password', 'p', true, 'changePassword');
50+
$options->registerOption('repeat-password', 'New login password (again)', 'r', true, 'changePassword');
51+
52+
foreach (['create', 'get', 'delete', 'all', 'login'] as $command) {
53+
$options->registerOption('email', 'Email address', 'e', true, $command);
54+
$options->registerOption('password', 'Login password', 'p', true, $command);
55+
}
56+
57+
$this->client = new GuzzleHttp\Client(['base_uri' => 'http://localhost:8888']);
58+
$this->token = @file_get_contents('.session');
59+
}
60+
61+
protected function createNote($contents)
62+
{
63+
if (empty($this->token)) {
64+
$this->error('Please log in first!');
65+
return;
66+
}
67+
68+
if (empty($contents)) {
69+
$this->error('Invalid/Empty note. Cannot send to server!');
70+
return;
71+
}
72+
73+
$jsonBody = [
74+
'note' => $contents
75+
];
76+
77+
$response = $this->client->request(
78+
'POST',
79+
'notes', [
80+
'body' => json_encode($jsonBody),
81+
'headers' => ['Authorization' => sprintf('Bearer %s', $this->token)]
82+
]);
83+
84+
if ($response->getStatusCode() === 200) {
85+
$return = json_decode($response->getBody(), true);
86+
87+
$this->info(sprintf('Created note ID %s', $return['noteId']));
88+
}
89+
}
90+
91+
private function initTable(): TableFormatter
92+
{
93+
$tf = new TableFormatter($this->colors);
94+
$tf->setBorder(' | ');
95+
96+
echo $tf->format(
97+
self::TABLE_WIDTH,
98+
['Field', 'Value']
99+
);
100+
101+
echo str_pad('', $tf->getMaxWidth(), '-') . "\n";
102+
103+
return $tf;
104+
}
105+
106+
private function printNote(array $note, TableFormatter $tf)
107+
{
108+
echo $tf->format(
109+
self::TABLE_WIDTH,
110+
['Note ID', $note['noteId']],
111+
self::TABLE_STYLE
112+
);
113+
114+
echo $tf->format(
115+
self::TABLE_WIDTH,
116+
['Created', $note['created']],
117+
self::TABLE_STYLE
118+
);
119+
120+
echo $tf->format(
121+
self::TABLE_WIDTH,
122+
['Note', $note['note']],
123+
self::TABLE_STYLE
124+
);
125+
}
126+
127+
protected function getNote($noteId)
128+
{
129+
if (empty($this->token)) {
130+
$this->error('Please log in first!');
131+
return;
132+
}
133+
134+
$response = $this->client->request(
135+
'GET',
136+
sprintf('notes/%s', $noteId),
137+
['headers' => ['Authorization' => sprintf('Bearer %s', $this->token)]]
138+
);
139+
140+
if ($response->getStatusCode() === 200) {
141+
$return = json_decode($response->getBody(), true);
142+
143+
if ( ! empty($return)) {
144+
$tf = $this->initTable();
145+
$this->printNote($return, $tf);
146+
echo str_pad('', $tf->getMaxWidth(), '-') . "\n";
147+
} else {
148+
$this->error(sprintf('Note ID %s does not exist!', $noteId));
149+
}
150+
}
151+
}
152+
153+
protected function deleteNote($noteId)
154+
{
155+
if (empty($this->token)) {
156+
$this->error('Please log in first!');
157+
return;
158+
}
159+
160+
try {
161+
$this->client->request(
162+
'DELETE',
163+
sprintf('notes/%s', $noteId),
164+
['headers' => ['Authorization' => sprintf('Bearer %s', $this->token)]]
165+
);
166+
$this->info(sprintf('Note ID %s has been deleted.', $noteId));
167+
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
168+
$this->error(sprintf('Unable to delete note %s. It might not exist!', $noteId));
169+
}
170+
}
171+
172+
protected function getAllNotes()
173+
{
174+
if (empty($this->token)) {
175+
$this->error('Please log in first!');
176+
return;
177+
}
178+
179+
$response = $this->client->request(
180+
'GET',
181+
'notes',
182+
['headers' => ['Authorization' => sprintf('Bearer %s', $this->token)]]
183+
);
184+
185+
if ($response->getStatusCode() === 200) {
186+
$notes = json_decode($response->getBody(), true);
187+
188+
if (empty($notes)) {
189+
$this->warning('System contains no notes.');
190+
} else {
191+
$tf = $this->initTable();
192+
foreach ($notes as $note) {
193+
$this->printNote($note, $tf);
194+
echo str_pad('', $tf->getMaxWidth(), '-') . "\n";
195+
}
196+
}
197+
}
198+
}
199+
200+
protected function register(Options $options)
201+
{
202+
$email = $options->getOpt('email');
203+
$password = $options->getOpt('password');
204+
$repeat = $options->getOpt('repeat-password');
205+
$greeting = $options->getOpt('greeting');
206+
207+
$error = false;
208+
if (empty($email)) {
209+
$this->error('Email is required.');
210+
$error = true;
211+
}
212+
if (empty($password)) {
213+
$this->error('Password is required.');
214+
$error = true;
215+
}
216+
if (empty($repeat)) {
217+
$this->error('You must repeat your password.');
218+
$error = true;
219+
}
220+
if ($error) return;
221+
222+
$jsonBody = [
223+
'email' => $email,
224+
'greeting' => $greeting,
225+
'password' => $password,
226+
'repeat_password' => $repeat,
227+
];
228+
229+
try {
230+
$response = $this->client->request('POST', 'account', [
231+
'body' => json_encode($jsonBody)
232+
]);
233+
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
234+
$this->error('Unable to create user account.');
235+
return;
236+
}
237+
238+
if ($response->getStatusCode() === 200) {
239+
$return = json_decode($response->getBody(), true);
240+
241+
$this->info(sprintf('Registered user with ID %s', $return['userId']));
242+
}
243+
}
244+
245+
protected function changePassword(Options $options)
246+
{
247+
$email = $options->getOpt('email');
248+
$oldPassword = $options->getOpt('old-password');
249+
$newPassword = $options->getOpt('new-password');
250+
$repeat = $options->getOpt('repeat-password');
251+
252+
$error = false;
253+
if (empty($email)) {
254+
$this->error('Email is required.');
255+
$error = true;
256+
}
257+
if (empty($oldPassword)) {
258+
$this->error('Old password is required.');
259+
$error = true;
260+
}
261+
if (empty($newPassword)) {
262+
$this->error('New password is required.');
263+
$error = true;
264+
}
265+
if (empty($repeat)) {
266+
$this->error('You must repeat your new password.');
267+
$error = true;
268+
}
269+
if ($error) return;
270+
271+
$jsonBody = [
272+
'email' => $email,
273+
'old_password' => $oldPassword,
274+
'new_password' => $newPassword,
275+
'repeat_password' => $repeat,
276+
];
277+
278+
$response = $this->client->request('PUT', 'account', [
279+
'body' => json_encode($jsonBody)
280+
]);
281+
282+
if ($response->getStatusCode() === 204) {
283+
$this->info('Successfully updated your user password.');
284+
}
285+
}
286+
287+
protected function login(Options $options)
288+
{
289+
try {
290+
$response = $this->client->request('GET', 'login', ['auth' => [$this->user, $this->pass]]);
291+
292+
if ($response->getStatusCode() === 200) {
293+
$auth = json_decode($response->getBody(), true);
294+
295+
if (empty($auth)) {
296+
$this->error('Could not establish a session!');
297+
} else {
298+
$token = $auth['token'];
299+
300+
try {
301+
$fp = fopen('.session', 'w');
302+
fwrite($fp, $token);
303+
fclose($fp);
304+
305+
$this->info('Established a persistent session. Commence note taking!');
306+
} catch (\Exception $e) {
307+
$this->error('Could not establish a session!');
308+
}
309+
}
310+
}
311+
} catch(\GuzzleHttp\Exception\BadResponseException $e) {
312+
$this->error('Could not establish a session!');
313+
}
314+
}
315+
316+
protected function main(Options $options)
317+
{
318+
$args = $options->getArgs();
319+
$this->user = $options->getOpt('email');
320+
$this->pass = $options->getOpt('password');
321+
322+
switch ($options->getCmd()) {
323+
case 'create':
324+
$this->createNote($args[0]);
325+
break;
326+
case 'get':
327+
$this->getNote($args[0]);
328+
break;
329+
case 'delete':
330+
$this->deleteNote($args[0]);
331+
break;
332+
case 'all':
333+
$this->getAllNotes();
334+
break;
335+
case 'register':
336+
$this->register($options);
337+
break;
338+
case 'changePassword':
339+
$this->changePassword($options);
340+
break;
341+
case 'login':
342+
$this->login($options);
343+
break;
344+
default:
345+
$this->error('No known command was called, we show the default help instead:');
346+
echo $options->help();
347+
exit;
348+
}
349+
}
350+
}
351+
352+
$cli = new ModuleFinal();
353+
$cli->run();

module-final/config.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<?php
2+
define('ENCRYPTION_KEY', '737d8f1918d900b83f8438423433946fce3c72441557b2393ea6767a23ceae05');

0 commit comments

Comments
 (0)