Add complex component editing (close #5), improve editor, add more theme functions, add URL options (close #6)
This commit is contained in:
parent
e018a09b50
commit
6b2189eed2
15
action.php
15
action.php
@ -41,10 +41,19 @@ switch ($VARS['action']) {
|
|||||||
die(json_encode(["status" => "ERROR", "msg" => "Invalid page or site"]));
|
die(json_encode(["status" => "ERROR", "msg" => "Invalid page or site"]));
|
||||||
}
|
}
|
||||||
foreach ($content as $name => $value) {
|
foreach ($content as $name => $value) {
|
||||||
if ($database->has("components", ["AND" => ["pageid" => $pageid, "name" => $name]])) {
|
if (is_array($value)) {
|
||||||
$database->update("components", ["content" => $value], ["AND" => ["pageid" => $pageid, "name" => $name]]);
|
$json = json_encode($value);
|
||||||
|
if ($database->has("complex_components", ["AND" => ["pageid" => $pageid, "name" => $name]])) {
|
||||||
|
$database->update("complex_components", ["content" => $json], ["AND" => ["pageid" => $pageid, "name" => $name]]);
|
||||||
|
} else {
|
||||||
|
$database->insert("complex_components", ["name" => $name, "content" => $json, "pageid" => $pageid]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$database->insert("components", ["name" => $name, "content" => $value, "pageid" => $pageid]);
|
if ($database->has("components", ["AND" => ["pageid" => $pageid, "name" => $name]])) {
|
||||||
|
$database->update("components", ["content" => $value], ["AND" => ["pageid" => $pageid, "name" => $name]]);
|
||||||
|
} else {
|
||||||
|
$database->insert("components", ["name" => $name, "content" => $value, "pageid" => $pageid]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit(json_encode(["status" => "OK"]));
|
exit(json_encode(["status" => "OK"]));
|
||||||
|
@ -30,10 +30,11 @@ define("STRINGS", [
|
|||||||
"captcha error" => "There was a problem with the CAPTCHA (robot test). Try again.",
|
"captcha error" => "There was a problem with the CAPTCHA (robot test). Try again.",
|
||||||
"actions" => "Actions",
|
"actions" => "Actions",
|
||||||
"home" => "Home",
|
"home" => "Home",
|
||||||
"more" => "More",
|
"editor" => "Editor",
|
||||||
"sites" => "Sites",
|
"sites" => "Sites",
|
||||||
"theme" => "Theme",
|
"theme" => "Theme",
|
||||||
"name" => "Name",
|
"name" => "Name",
|
||||||
|
"new site" => "New Site",
|
||||||
"site name" => "Site Name",
|
"site name" => "Site Name",
|
||||||
"url" => "URL",
|
"url" => "URL",
|
||||||
"editing site" => "Editing {site}",
|
"editing site" => "Editing {site}",
|
||||||
@ -41,5 +42,16 @@ define("STRINGS", [
|
|||||||
"single page" => "Single page",
|
"single page" => "Single page",
|
||||||
"multiple page" => "Multiple page",
|
"multiple page" => "Multiple page",
|
||||||
"templates" => "Templates",
|
"templates" => "Templates",
|
||||||
"color styles" => "Color styles"
|
"color styles" => "Color styles",
|
||||||
|
"save" => "Save",
|
||||||
|
"edit" => "Edit",
|
||||||
|
"view" => "View",
|
||||||
|
"cancel" => "Cancel",
|
||||||
|
"save needed" => "Press Save to see recent changes.",
|
||||||
|
"saved" => "Saved",
|
||||||
|
"icon" => "Icon",
|
||||||
|
"link" => "Link",
|
||||||
|
"text" => "Text",
|
||||||
|
"select page or enter url" => "Select a page or enter URL",
|
||||||
|
"edit component" => "Edit component"
|
||||||
]);
|
]);
|
@ -85,6 +85,12 @@ function getdatabase() {
|
|||||||
|
|
||||||
function getsiteid() {
|
function getsiteid() {
|
||||||
global $database;
|
global $database;
|
||||||
|
if (isset($_GET['siteid'])) {
|
||||||
|
$id = preg_replace("/[^0-9]/", '', $_GET['siteid']);
|
||||||
|
if ($database->has('sites', ["siteid" => $id])) {
|
||||||
|
return $id;
|
||||||
|
}
|
||||||
|
}
|
||||||
return $database->get("sites", "siteid");
|
return $database->get("sites", "siteid");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,6 +110,9 @@ function getpageslug() {
|
|||||||
function getpagetemplate() {
|
function getpagetemplate() {
|
||||||
global $database;
|
global $database;
|
||||||
$slug = getpageslug();
|
$slug = getpageslug();
|
||||||
|
if (isset($_GET['template'])) {
|
||||||
|
return preg_replace("/[^A-Za-z0-9]/", '', $_GET['template']);
|
||||||
|
}
|
||||||
if (!is_null($slug)) {
|
if (!is_null($slug)) {
|
||||||
return $database->get("pages", "template", ["AND" => ["slug" => $slug, "siteid" => getsiteid()]]);
|
return $database->get("pages", "template", ["AND" => ["slug" => $slug, "siteid" => getsiteid()]]);
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,19 @@ function get_page_url($echo = true, $slug = null) {
|
|||||||
if (isset($_GET['edit'])) {
|
if (isset($_GET['edit'])) {
|
||||||
$edit = "&edit";
|
$edit = "&edit";
|
||||||
}
|
}
|
||||||
$url = get_site_url(false) . "index.php?id=$slug$edit";
|
$theme = "";
|
||||||
|
if (isset($_GET['theme'])) {
|
||||||
|
$theme = "&theme=" . preg_replace("/[^A-Za-z0-9]/", '', $_GET['theme']);
|
||||||
|
}
|
||||||
|
$template = "";
|
||||||
|
if (isset($_GET['template'])) {
|
||||||
|
$template = "&template=" . preg_replace("/[^A-Za-z0-9]/", '', $_GET['template']);
|
||||||
|
}
|
||||||
|
$siteid = "";
|
||||||
|
if (isset($_GET['siteid'])) {
|
||||||
|
$siteid = "&siteid=" . preg_replace("/[^0-9]/", '', $_GET['siteid']);
|
||||||
|
}
|
||||||
|
$url = get_site_url(false) . "index.php?id=$slug$edit$theme$template$siteid";
|
||||||
if ($echo) {
|
if ($echo) {
|
||||||
echo $url;
|
echo $url;
|
||||||
} else {
|
} else {
|
||||||
@ -77,7 +89,10 @@ function get_component($name, $context = null, $echo = true) {
|
|||||||
$context = get_page_slug(false);
|
$context = get_page_slug(false);
|
||||||
}
|
}
|
||||||
$pageid = $db->get("pages", "pageid", ["AND" => ["slug" => $context, "siteid" => getsiteid()]]);
|
$pageid = $db->get("pages", "pageid", ["AND" => ["slug" => $context, "siteid" => getsiteid()]]);
|
||||||
$content = "Edit me";
|
$content = "";
|
||||||
|
if (isset($_GET['edit'])) {
|
||||||
|
$content = "Click here to edit me";
|
||||||
|
}
|
||||||
if ($db->has("components", ["AND" => ["pageid" => $pageid, "name" => $name]])) {
|
if ($db->has("components", ["AND" => ["pageid" => $pageid, "name" => $name]])) {
|
||||||
$content = $db->get("components", "content", ["AND" => ["pageid" => $pageid, "name" => $name]]);
|
$content = $db->get("components", "content", ["AND" => ["pageid" => $pageid, "name" => $name]]);
|
||||||
}
|
}
|
||||||
@ -111,13 +126,42 @@ function get_complex_component($name, $context = null) {
|
|||||||
$context = get_page_slug(false);
|
$context = get_page_slug(false);
|
||||||
}
|
}
|
||||||
$pageid = $db->get("pages", "pageid", ["AND" => ["slug" => $context, "siteid" => getsiteid()]]);
|
$pageid = $db->get("pages", "pageid", ["AND" => ["slug" => $context, "siteid" => getsiteid()]]);
|
||||||
$content = null;
|
$content = ["icon" => "", "link" => "", "text" => ""];
|
||||||
if ($db->has("complex_components", ["AND" => ["pageid" => $pageid, "name" => $name]])) {
|
if ($db->has("complex_components", ["AND" => ["pageid" => $pageid, "name" => $name]])) {
|
||||||
$content = json_decode($db->get("complex_components", "content", ["AND" => ["pageid" => $pageid, "name" => $name]]), true);
|
$content = json_decode($db->get("complex_components", "content", ["AND" => ["pageid" => $pageid, "name" => $name]]), true);
|
||||||
}
|
}
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function get_escaped_json($json, $echo = true) {
|
||||||
|
$text = htmlspecialchars(json_encode($json), ENT_QUOTES, 'UTF-8');
|
||||||
|
if ($echo) {
|
||||||
|
echo $text;
|
||||||
|
} else {
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects if a string is a URL or a page slug, and returns something usable for href
|
||||||
|
* @param string $str
|
||||||
|
* @param boolean $echo
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function get_url_or_slug($str, $echo = true) {
|
||||||
|
$url = $str;
|
||||||
|
if ($str == "") {
|
||||||
|
$url = "#";
|
||||||
|
} else if (strpos($str, "http") !== 0) {
|
||||||
|
$url = get_page_url(false, $str);
|
||||||
|
}
|
||||||
|
if ($echo) {
|
||||||
|
echo $url;
|
||||||
|
} else {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function get_page_content($slug = null) {
|
function get_page_content($slug = null) {
|
||||||
get_component("content", $slug);
|
get_component("content", $slug);
|
||||||
}
|
}
|
||||||
@ -143,10 +187,10 @@ function get_theme_color_url($echo = true) {
|
|||||||
if ($site["color"] == null) {
|
if ($site["color"] == null) {
|
||||||
$site["color"] = "default";
|
$site["color"] = "default";
|
||||||
}
|
}
|
||||||
if (!file_exists(__DIR__ . "/../public/themes/" . $site["theme"] . "/colors/" . $site['color'])) {
|
if (!file_exists(__DIR__ . "/../public/themes/" . SITE_THEME . "/colors/" . $site['color'])) {
|
||||||
$site['color'] = "default";
|
$site['color'] = "default";
|
||||||
}
|
}
|
||||||
$url = $site["url"] . "themes/" . $site["theme"] . "/colors/" . $site["color"];
|
$url = $site["url"] . "themes/" . SITE_THEME . "/colors/" . $site["color"];
|
||||||
if ($echo) {
|
if ($echo) {
|
||||||
echo $url;
|
echo $url;
|
||||||
} else {
|
} else {
|
||||||
|
@ -40,10 +40,60 @@ if (!is_empty($VARS['siteid'])) {
|
|||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<div class="row mb-2">
|
|
||||||
|
<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="editLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="editLabel"><?php lang("edit component"); ?></h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body" id="editModalBody">
|
||||||
|
<div class="form-group d-none" id="iconEdit">
|
||||||
|
<label><i class="fas fa-paint-brush"></i> <?php lang("icon"); ?></label>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="form-group" id="linkEdit">
|
||||||
|
<label><i class="fas fa-link"></i> <?php lang("link"); ?></label>
|
||||||
|
<select id="linkPage" class="form-control">
|
||||||
|
<option value=""><?php lang("select page or enter url"); ?></option>
|
||||||
|
<?php
|
||||||
|
foreach ($pagedata as $p) {
|
||||||
|
echo "<option value=\"" . $p['slug'] . "\">" . $p['title'] . ' (' . $p['slug'] . ')' . "</option>\n";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</select>
|
||||||
|
<input type="text" id="linkBox" class="form-control" placeholder="http://example.com" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group" id="textEdit">
|
||||||
|
<label><i class="fas fa-font"></i> <?php lang("text"); ?></label>
|
||||||
|
<input type="text" id="textBox" class="form-control" placeholder="Edit me" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php lang("cancel"); ?></button>
|
||||||
|
<button type="button" class="btn btn-success" id="editModalSave"><i class="fas fa-save"></i> <?php lang("save"); ?></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-2 justify-content-between">
|
||||||
<div class="col-12 col-sm-6 col-md-4">
|
<div class="col-12 col-sm-6 col-md-4">
|
||||||
<div class="btn btn-success" id="savebtn">
|
<div class="btn-group">
|
||||||
<i class="fas fa-save"></i> <?php lang("save"); ?>
|
<div class="btn btn-success" id="savebtn">
|
||||||
|
<i class="fas fa-save"></i> <?php lang("save"); ?>
|
||||||
|
</div>
|
||||||
|
<a class="btn btn-info" id="viewbtn" target="_BLANK" href="public/index.php?id=<?php echo $slug; ?>&siteid=<?php echo $VARS['siteid']; ?>">
|
||||||
|
<i class="fas fa-eye"></i> <?php lang("view"); ?>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<span class="badge badge-success d-none" id="savedBadge"><i class="fas fa-check"></i> <?php lang("saved"); ?></span>
|
||||||
|
<div id="reloadprompt" class="badge badge-info d-none">
|
||||||
|
<i class="fas fa-sync-alt"></i>
|
||||||
|
<?php lang("save needed"); ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form method="GET" action="app.php" class="col-12 col-sm-6 col-md-4">
|
<form method="GET" action="app.php" class="col-12 col-sm-6 col-md-4">
|
||||||
@ -68,4 +118,4 @@ if (!is_empty($VARS['siteid'])) {
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<iframe id="editorframe" src="public/index.php?id=<?php echo $slug; ?>&edit"></iframe>
|
<iframe id="editorframe" src="public/index.php?id=<?php echo $slug; ?>&edit&siteid=<?php echo $VARS['siteid']; ?>"></iframe>
|
@ -12,7 +12,13 @@ if (!getsiteid()) {
|
|||||||
sendError("No website has been created yet. Please open " . SITE_TITLE . " and make one.");
|
sendError("No website has been created yet. Please open " . SITE_TITLE . " and make one.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$theme = $database->get("sites", "theme", ["siteid" => getsiteid()]);
|
if (isset($_GET['theme']) && file_exists(__DIR__ . "/themes/" . preg_replace("/[^A-Za-z0-9]/", '', $_GET['theme']) . "/theme.json")) {
|
||||||
|
$theme = preg_replace("/[^A-Za-z0-9]/", '', $_GET['theme']);
|
||||||
|
} else {
|
||||||
|
$theme = $database->get("sites", "theme", ["siteid" => getsiteid()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
define("SITE_THEME", $theme);
|
||||||
|
|
||||||
$template = getpagetemplate();
|
$template = getpagetemplate();
|
||||||
if (file_exists(__DIR__ . "/themes/$theme/$template.php")) {
|
if (file_exists(__DIR__ . "/themes/$theme/$template.php")) {
|
||||||
|
@ -32,4 +32,11 @@ button.note-btn, .note-modal button {
|
|||||||
-moz-appearance: checkbox;
|
-moz-appearance: checkbox;
|
||||||
-webkit-appearance: checkbox;
|
-webkit-appearance: checkbox;
|
||||||
-ms-appearance: checkbox;
|
-ms-appearance: checkbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sw-editbtn {
|
||||||
|
border: 2px dashed red !important;
|
||||||
|
color: black !important;
|
||||||
|
background: white !important;
|
||||||
|
border-radius: 0px;
|
||||||
}
|
}
|
@ -12,6 +12,13 @@ function saveEdits() {
|
|||||||
$(".sw-text-input").each(function (e) {
|
$(".sw-text-input").each(function (e) {
|
||||||
components[$(this).data("component")] = $(this).val();
|
components[$(this).data("component")] = $(this).val();
|
||||||
});
|
});
|
||||||
|
$(".sw-complex").each(function (e) {
|
||||||
|
if (typeof $(this).data("json") === "string") {
|
||||||
|
components[$(this).data("component")] = JSON.parse($(this).data("json"));
|
||||||
|
} else {
|
||||||
|
components[$(this).data("component")] = $(this).data("json");
|
||||||
|
}
|
||||||
|
});
|
||||||
var output = {
|
var output = {
|
||||||
slug: page_slug,
|
slug: page_slug,
|
||||||
site: site_id,
|
site: site_id,
|
||||||
@ -19,6 +26,7 @@ function saveEdits() {
|
|||||||
};
|
};
|
||||||
//console.log(output);
|
//console.log(output);
|
||||||
var json = JSON.stringify(output);
|
var json = JSON.stringify(output);
|
||||||
|
console.log(output);
|
||||||
console.log("editor: sent page content");
|
console.log("editor: sent page content");
|
||||||
parent.postMessage('save ' + json, "*");
|
parent.postMessage('save ' + json, "*");
|
||||||
}
|
}
|
||||||
@ -50,10 +58,27 @@ $(document).ready(function () {
|
|||||||
$(this).html("<input type=\"text\" data-component=\"" + component + "\" class=\"sw-text-input\" value=\"" + text + "\" placeholder=\"Click to edit\">");
|
$(this).html("<input type=\"text\" data-component=\"" + component + "\" class=\"sw-text-input\" value=\"" + text + "\" placeholder=\"Click to edit\">");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(".sw-complex").each(function () {
|
||||||
|
$(this).append("<div class=\"sw-editbtn\">Click to edit</div>");
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".sw-editbtn").on("click", function () {
|
||||||
|
var data = $(this).parent().data("json");
|
||||||
|
var send = {"component": $(this).parent().data("component"), "content": data};
|
||||||
|
//console.log(send);
|
||||||
|
parent.postMessage('editcomplex ' + JSON.stringify(send), "*");
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
window.addEventListener('message', function (event) {
|
window.addEventListener('message', function (event) {
|
||||||
console.log("editor: received message: " + event.data);
|
console.log("editor: received message: " + event.data);
|
||||||
if (event.data == "save") {
|
if (event.data == "save") {
|
||||||
saveEdits();
|
saveEdits();
|
||||||
|
} else if (event.data.startsWith("complex ")) {
|
||||||
|
var json = JSON.parse(event.data.slice(8));
|
||||||
|
var comp = json["component"];
|
||||||
|
var data = json["content"];
|
||||||
|
$(".sw-complex[data-component='" + comp + "']").data("json", JSON.stringify(data));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
@ -15,17 +15,78 @@ function save(json) {
|
|||||||
content: output["content"]
|
content: output["content"]
|
||||||
}, function (data) {
|
}, function (data) {
|
||||||
if (data.status == "OK") {
|
if (data.status == "OK") {
|
||||||
alert("Saved");
|
$("#reloadprompt").addClass("d-none");
|
||||||
|
document.getElementById("editorframe").contentDocument.location.reload(true);
|
||||||
|
$("#savedBadge").removeClass("d-none");
|
||||||
|
$("#savedBadge").show();
|
||||||
|
setTimeout(function () {
|
||||||
|
$("#savedBadge").fadeOut("slow");
|
||||||
|
}, 1500);
|
||||||
} else {
|
} else {
|
||||||
alert(data.msg);
|
alert(data.msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function editComplex(json) {
|
||||||
|
var data = JSON.parse(json);
|
||||||
|
console.log(data);
|
||||||
|
if (typeof data.content === "string") {
|
||||||
|
var content = JSON.parse(data.content);
|
||||||
|
} else {
|
||||||
|
var content = data.content;
|
||||||
|
}
|
||||||
|
$("#iconEdit").removeClass("d-none");
|
||||||
|
$("#linkEdit").removeClass("d-none");
|
||||||
|
$("#textEdit").removeClass("d-none");
|
||||||
|
$("#linkPage").val("");
|
||||||
|
$("#linkBox").val("");
|
||||||
|
$("#textBox").val("");
|
||||||
|
if (typeof content.icon === 'undefined') {
|
||||||
|
$("#iconEdit").addClass("d-none");
|
||||||
|
}
|
||||||
|
if (typeof content.link === 'undefined') {
|
||||||
|
$("#linkEdit").addClass("d-none");
|
||||||
|
} else {
|
||||||
|
if (content.link.startsWith("http")) {
|
||||||
|
$("#linkBox").val(content.link);
|
||||||
|
} else {
|
||||||
|
$("#linkPage").val(content.link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeof content.text === 'undefined') {
|
||||||
|
$("#textEdit").addClass("d-none");
|
||||||
|
} else {
|
||||||
|
$("#textBox").val(content.text);
|
||||||
|
}
|
||||||
|
$("#editModal").data("component", data.component);
|
||||||
|
$("#editModal").modal();
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#editModalSave").on("click", function () {
|
||||||
|
var data = {};
|
||||||
|
data["component"] = $("#editModal").data("component");
|
||||||
|
var content = {};
|
||||||
|
content["icon"] = "";
|
||||||
|
if ($("#linkBox").val() != "") {
|
||||||
|
content["link"] = $("#linkBox").val();
|
||||||
|
} else {
|
||||||
|
content["link"] = $("#linkPage").val();
|
||||||
|
}
|
||||||
|
content["text"] = $("#textBox").val();
|
||||||
|
data["content"] = content;
|
||||||
|
var json = JSON.stringify(data);
|
||||||
|
document.getElementById("editorframe").contentWindow.postMessage("complex " + json, "*");
|
||||||
|
$("#reloadprompt").removeClass("d-none");
|
||||||
|
$('#editModal').modal('hide');
|
||||||
|
});
|
||||||
|
|
||||||
window.addEventListener('message', function (event) {
|
window.addEventListener('message', function (event) {
|
||||||
//console.log("parent: received message: " + event.data);
|
//console.log("parent: received message: " + event.data);
|
||||||
if (event.data.startsWith("save ")) {
|
if (event.data.startsWith("save ")) {
|
||||||
save(event.data.slice(5));
|
save(event.data.slice(5));
|
||||||
|
} else if (event.data.startsWith("editcomplex ")) {
|
||||||
|
editComplex(event.data.slice(12));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user