Skip to content

Commit ca1b393

Browse files
committed
Implement document deletion
1 parent 3319c95 commit ca1b393

File tree

7 files changed

+248
-6
lines changed

7 files changed

+248
-6
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<?php
2+
3+
namespace BNETDocs\Controllers\Document;
4+
5+
use \BNETDocs\Libraries\CSRF;
6+
use \BNETDocs\Libraries\Common;
7+
use \BNETDocs\Libraries\Controller;
8+
use \BNETDocs\Libraries\Document;
9+
use \BNETDocs\Libraries\Exceptions\DocumentNotFoundException;
10+
use \BNETDocs\Libraries\Exceptions\UnspecifiedViewException;
11+
use \BNETDocs\Libraries\Logger;
12+
use \BNETDocs\Libraries\Router;
13+
use \BNETDocs\Libraries\UserSession;
14+
use \BNETDocs\Models\Document\Delete as DocumentDeleteModel;
15+
use \BNETDocs\Views\Document\DeleteHtml as DocumentDeleteHtmlView;
16+
use \InvalidArgumentException;
17+
18+
class Delete extends Controller {
19+
20+
public function run(Router &$router) {
21+
switch ($router->getRequestPathExtension()) {
22+
case "htm": case "html": case "":
23+
$view = new DocumentDeleteHtmlView();
24+
break;
25+
default:
26+
throw new UnspecifiedViewException();
27+
}
28+
29+
$data = $router->getRequestQueryArray();
30+
$model = new DocumentDeleteModel();
31+
$model->csrf_id = mt_rand();
32+
$model->csrf_token = CSRF::generate($model->csrf_id);
33+
$model->document = null;
34+
$model->error = null;
35+
$model->id = (isset($data["id"]) ? $data["id"] : null);
36+
$model->title = null;
37+
$model->user_session = UserSession::load($router);
38+
39+
try { $model->document = new Document($model->id); }
40+
catch (DocumentNotFoundException $e) { $model->document = null; }
41+
catch (InvalidArgumentException $e) { $model->document = null; }
42+
43+
if ($model->document === null) {
44+
$model->error = "NOT_FOUND";
45+
} else {
46+
$model->title = $model->document->getTitle();
47+
48+
if ($router->getRequestMethod() == "POST") {
49+
$this->tryDelete($router, $model);
50+
}
51+
}
52+
53+
ob_start();
54+
$view->render($model);
55+
$router->setResponseCode(200);
56+
$router->setResponseTTL(0);
57+
$router->setResponseHeader("Content-Type", $view->getMimeType());
58+
$router->setResponseContent(ob_get_contents());
59+
ob_end_clean();
60+
}
61+
62+
protected function tryDelete(Router &$router, DocumentDeleteModel &$model) {
63+
if (!isset($model->user_session)) {
64+
$model->error = "NOT_LOGGED_IN";
65+
return;
66+
}
67+
68+
$data = $router->getRequestBodyArray();
69+
$csrf_id = (isset($data["csrf_id" ]) ? $data["csrf_id" ] : null);
70+
$csrf_token = (isset($data["csrf_token"]) ? $data["csrf_token"] : null);
71+
$csrf_valid = CSRF::validate($csrf_id, $csrf_token);
72+
73+
if (!$csrf_valid) {
74+
$model->error = "INVALID_CSRF";
75+
return;
76+
}
77+
CSRF::invalidate($csrf_id);
78+
79+
$model->error = false;
80+
81+
$id = (int) $model->id;
82+
$user_id = $model->user_session->user_id;
83+
84+
try {
85+
86+
$success = Document::delete($id);
87+
88+
} catch (QueryException $e) {
89+
90+
// SQL error occurred. We can show a friendly message to the user while
91+
// also notifying this problem to staff.
92+
Logger::logException($e);
93+
94+
$success = false;
95+
96+
}
97+
98+
if (!$success) {
99+
$model->error = "INTERNAL_ERROR";
100+
} else {
101+
$model->error = false;
102+
}
103+
104+
Logger::logEvent(
105+
"document_deleted",
106+
$user_id,
107+
getenv("REMOTE_ADDR"),
108+
json_encode([
109+
"error" => $model->error,
110+
"document_id" => $id,
111+
])
112+
);
113+
}
114+
115+
}

src/controllers/News/Delete.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public function run(Router &$router) {
2525
default:
2626
throw new UnspecifiedViewException();
2727
}
28-
28+
2929
$data = $router->getRequestQueryArray();
3030
$model = new NewsDeleteModel();
3131
$model->csrf_id = mt_rand();
@@ -39,7 +39,7 @@ public function run(Router &$router) {
3939
try { $model->news_post = new NewsPost($model->id); }
4040
catch (NewsPostNotFoundException $e) { $model->news_post = null; }
4141
catch (InvalidArgumentException $e) { $model->news_post = null; }
42-
42+
4343
if ($model->news_post === null) {
4444
$model->error = "NOT_FOUND";
4545
} else {
@@ -64,7 +64,7 @@ protected function tryDelete(Router &$router, NewsDeleteModel &$model) {
6464
$model->error = "NOT_LOGGED_IN";
6565
return;
6666
}
67-
67+
6868
$data = $router->getRequestBodyArray();
6969
$csrf_id = (isset($data["csrf_id" ]) ? $data["csrf_id" ] : null);
7070
$csrf_token = (isset($data["csrf_token"]) ? $data["csrf_token"] : null);
@@ -78,15 +78,15 @@ protected function tryDelete(Router &$router, NewsDeleteModel &$model) {
7878

7979
$model->error = false;
8080

81-
$id = (int) $model->id;
81+
$id = (int) $model->id;
8282
$user_id = $model->user_session->user_id;
8383

8484
try {
8585

8686
$success = NewsPost::delete($id);
8787

8888
} catch (QueryException $e) {
89-
89+
9090
// SQL error occurred. We can show a friendly message to the user while
9191
// also notifying this problem to staff.
9292
Logger::logException($e);

src/libraries/Router.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use \BNETDocs\Controllers\Comment\Create as CommentCreateController;
77
use \BNETDocs\Controllers\Credits as CreditsController;
88
use \BNETDocs\Controllers\Document\Create as DocumentCreateController;
9+
use \BNETDocs\Controllers\Document\Delete as DocumentDeleteController;
910
use \BNETDocs\Controllers\Document\Edit as DocumentEditController;
1011
use \BNETDocs\Controllers\Document\Index as DocumentIndexController;
1112
use \BNETDocs\Controllers\Document\Popular as DocumentPopularController;
@@ -288,6 +289,9 @@ public function route(Pair &$redirect = null) {
288289
case "create":
289290
$controller = new DocumentCreateController();
290291
break;
292+
case "delete": case "delete.htm": case "delete.html":
293+
$controller = new DocumentDeleteController();
294+
break;
291295
case "edit": case "edit.htm": case "edit.html":
292296
$controller = new DocumentEditController();
293297
break;

src/models/Document/Delete.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace BNETDocs\Models\Document;
4+
5+
use \BNETDocs\Libraries\Model;
6+
7+
class Delete extends Model {
8+
9+
public $acl_allowed;
10+
public $csrf_id;
11+
public $csrf_token;
12+
public $document;
13+
public $error;
14+
public $id;
15+
public $title;
16+
public $user;
17+
public $user_session;
18+
19+
public function __construct() {
20+
parent::__construct();
21+
$this->acl_allowed = null;
22+
$this->csrf_id = null;
23+
$this->csrf_token = null;
24+
$this->document = null;
25+
$this->error = null;
26+
$this->id = null;
27+
$this->title = null;
28+
$this->user = null;
29+
$this->user_session = null;
30+
}
31+
32+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
namespace BNETDocs\Templates;
3+
4+
use \BNETDocs\Libraries\Pair;
5+
6+
$title = "Delete Document";
7+
$description = "This form allows an individual to delete a document.";
8+
9+
$this->opengraph->attach(new Pair("url", "/document/delete"));
10+
$this->opengraph->attach(new Pair("type", "article"));
11+
12+
switch ($this->getContext()->error) {
13+
case "ACL_NOT_SET":
14+
$message = "You do not have the privilege to delete documents.";
15+
break;
16+
case "NOT_FOUND":
17+
$message = "Cannot find document by that id.";
18+
break;
19+
case "NOT_LOGGED_IN":
20+
$message = "You must be logged in to delete documents.";
21+
break;
22+
case "INVALID_CSRF":
23+
$message = "The Cross-Site Request Forgery token was invalid. Either the "
24+
. "delete document form expired, or this may have been a malicious "
25+
. "attempt to delete a document.";
26+
break;
27+
case "INTERNAL_ERROR":
28+
$message = "An internal error occurred while processing your request. "
29+
. "Our staff has been notified of the issue. Try again later.";
30+
break;
31+
default:
32+
$message = $this->getContext()->error;
33+
}
34+
35+
$this->additional_css[] = "/a/forms.css";
36+
require("./header.inc.phtml");
37+
?>
38+
<article>
39+
<?php if (is_null($this->getContext()->error)) { ?>
40+
<header>Delete Document</header>
41+
<form method="POST" action="?id=<?php echo
42+
htmlspecialchars($this->getContext()->id, ENT_HTML5, "UTF-8"); ?>">
43+
<input type="hidden" name="csrf_id" value="<?php echo $this->getContext()->csrf_id; ?>"/>
44+
<input type="hidden" name="csrf_token" value="<?php echo $this->getContext()->csrf_token; ?>"/>
45+
<section>
46+
<p>Are you sure you wish to delete this document?</p>
47+
<p><input type="text" readonly="readonly" value="<?php echo filter_var($this->getContext()->title, FILTER_SANITIZE_STRING); ?>" tabindex="1"/></p>
48+
<p><input type="submit" value="Delete Document" tabindex="2" autofocus="autofocus"/></p>
49+
</section>
50+
</form>
51+
<?php } else if ($this->getContext()->error === false) { ?>
52+
<header class="green">Document Deleted</header>
53+
<section class="green">
54+
<p>You have successfully deleted the document!</p>
55+
<p>Use the navigation to the left to move to another page.</p>
56+
</section>
57+
<?php } else { ?>
58+
<header class="red">Delete Document</header>
59+
<section class="red">
60+
<p>An error occurred while attempting to delete the document.</p>
61+
<p><?php echo $message; ?></p>
62+
<p>Use the navigation to the left to move to another page.</p>
63+
</section>
64+
<?php } ?>
65+
</article>
66+
<?php require("./footer.inc.phtml"); ?>

src/templates/News/Delete.phtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ require("./header.inc.phtml");
4444
<input type="hidden" name="csrf_token" value="<?php echo $this->getContext()->csrf_token; ?>"/>
4545
<section>
4646
<p>Are you sure you wish to delete this news post?</p>
47-
<p><input type="text" readonly="readonly" value="<?php echo htmlspecialchars($this->getContext()->title, ENT_HTML5, "UTF-8"); ?>" tabindex="1"/></p>
47+
<p><input type="text" readonly="readonly" value="<?php echo filter_var($this->getContext()->title, FILTER_SANITIZE_STRING); ?>" tabindex="1"/></p>
4848
<p><input type="submit" value="Delete News Post" tabindex="2" autofocus="autofocus"/></p>
4949
</section>
5050
</form>

src/views/Document/DeleteHtml.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace BNETDocs\Views\Document;
4+
5+
use \BNETDocs\Libraries\Common;
6+
use \BNETDocs\Libraries\Exceptions\IncorrectModelException;
7+
use \BNETDocs\Libraries\Model;
8+
use \BNETDocs\Libraries\Template;
9+
use \BNETDocs\Libraries\View;
10+
use \BNETDocs\Models\Document\Delete as DocumentDeleteModel;
11+
12+
class DeleteHtml extends View {
13+
14+
public function getMimeType() {
15+
return "text/html;charset=utf-8";
16+
}
17+
18+
public function render(Model &$model) {
19+
if (!$model instanceof DocumentDeleteModel) {
20+
throw new IncorrectModelException();
21+
}
22+
(new Template($model, "Document/Delete"))->render();
23+
}
24+
25+
}

0 commit comments

Comments
 (0)