From bb3602073c2da9dee66ec1ce0ef99fbabc08cd34 Mon Sep 17 00:00:00 2001
From: Lee <42119604+Leesneaks@users.noreply.github.com>
Date: Mon, 4 Jan 2021 12:23:36 +0000
Subject: [PATCH] AdminPanel updates - changelog

-Admin menu updates
-Moved getchangelogtype/where to functions file and added to twig
-Added changelog editor to admin panel and updated changelog page
-Renamed the changelog md reader to clmd and edited the version file.
---
 admin/template/menus.php                      |  21 ++-
 system/functions.php                          |  27 ++++
 system/libs/changelog.php                     | 125 ++++++++++++++++
 system/pages/admin/changelog.php              | 134 ++++++++++++++++--
 system/pages/admin/clmd.php                   |  27 ++++
 system/pages/admin/version.php                |   4 +-
 system/pages/changelog.php                    |  33 +----
 .../templates/admin.changelog.form.html.twig  |  59 ++++++++
 system/templates/admin.changelog.html.twig    |  55 +++++++
 system/templates/changelog.html.twig          |  28 +++-
 system/twig.php                               |  14 ++
 11 files changed, 477 insertions(+), 50 deletions(-)
 create mode 100644 system/libs/changelog.php
 create mode 100644 system/pages/admin/clmd.php
 create mode 100644 system/templates/admin.changelog.form.html.twig
 create mode 100644 system/templates/admin.changelog.html.twig

diff --git a/admin/template/menus.php b/admin/template/menus.php
index 37a1c2df..12ffb85c 100644
--- a/admin/template/menus.php
+++ b/admin/template/menus.php
@@ -2,12 +2,25 @@
 
 return [
 	['name' => 'Dashboard', 'icon' => 'tachometer-alt', 'link' => 'dashboard'],
-	['name' => 'News', 'icon' => 'newspaper', 'link' => 'news'],
+	['name' => 'News', 'icon' => 'newspaper',  'link' =>
+		[
+			['name' => 'View', 'link' => 'news'],
+			['name' => 'Add news', 'link' => 'news&action=new&type=1'],
+			['name' => 'Add ticker', 'link' => 'news&action=new&type=2'],
+			['name' => 'Add article', 'link' => 'news&action=new&type=3'],
+		],
+	],
+	['name' => 'Changelogs', 'icon' => 'newspaper',  'link' =>
+		[
+			['name' => 'View', 'link' => 'changelog'],
+			['name' => 'Add', 'link' => 'changelog&action=new'],
+		],
+	],
 	['name' => 'Mailer', 'icon' => 'envelope', 'link' => 'mailer', 'disabled' => !config('mail_enabled')],
 	['name' => 'Pages', 'icon' => 'book', 'link' =>
 		[
-			['name' => 'All Pages', 'link' => 'pages'],
-			['name' => 'Add new', 'link' => 'pages&action=new'],
+			['name' => 'View', 'link' => 'pages'],
+			['name' => 'Add', 'link' => 'pages&action=new'],
 		],
 	],
 	['name' => 'Menus', 'icon' => 'list', 'link' => 'menus'],
@@ -32,4 +45,4 @@ return [
 			['name' => 'Visitors', 'icon' => 'user', 'link' => 'visitors'],
 		],
 	],
-];
\ No newline at end of file
+];
diff --git a/system/functions.php b/system/functions.php
index 2a37536f..04aa2584 100644
--- a/system/functions.php
+++ b/system/functions.php
@@ -1299,6 +1299,33 @@ function getBanType($typeId)
 	return "Unknown Type";
 }
 
+function getChangelogType($v)
+{
+	switch($v) {
+		case 1:
+			return 'added';
+		case 2:
+			return 'removed';
+		case 3:
+			return 'changed';
+		case 4:
+			return 'fixed';
+	}
+
+	return 'unknown';
+}
+
+function getChangelogWhere($v)
+{
+	switch($v) {
+		case 1:
+			return 'server';
+		case 2:
+			return 'website';
+	}
+
+	return 'unknown';
+}
 function getPlayerNameByAccount($id)
 {
 	global $vowels, $ots, $db;
diff --git a/system/libs/changelog.php b/system/libs/changelog.php
new file mode 100644
index 00000000..89f78bfc
--- /dev/null
+++ b/system/libs/changelog.php
@@ -0,0 +1,125 @@
+<?php
+
+class Changelog
+{
+	static public function verify($body,$date, &$errors)
+	{
+		if(!isset($date) || !isset($body[0])) {
+			$errors[] = 'Please fill all inputs.';
+			return false;
+		}
+
+		if(strlen($body) > CL_LIMIT) {
+			$errors[] = 'Changelog content cannot be longer than ' . CL_LIMIT . ' characters.';
+			return false;
+		}
+
+		return true;
+	}
+
+	static public function add($body, $type, $where, $player_id, $cdate, &$errors)
+	{
+		global $db;
+		if(!self::verify($body,$cdate, $errors))
+			return false;
+
+		$db->insert(TABLE_PREFIX . 'changelog', array('body' => $body, 'type' => $type, 'date' => $cdate, 'where' => $where, 'player_id' => isset($player_id) ? $player_id : 0));
+		self::clearCache();
+		return true;
+	}
+
+	static public function get($id) {
+		global $db;
+		return $db->select(TABLE_PREFIX . 'changelog', array('id' => $id));
+	}
+
+	static public function update($id, $body, $type, $where, $player_id, $date,  &$errors)
+	{
+		global $db;
+		if(!self::verify($body,$date, $errors))
+			return false;
+
+		$db->update(TABLE_PREFIX . 'changelog', array('body' => $body, 'type' => $type, 'where' => $where, 'player_id' => isset($player_id) ? $player_id : 0, 'date' => $date), array('id' => $id));
+		self::clearCache();
+		return true;
+	}
+
+	static public function delete($id, &$errors)
+	{
+		global $db;
+		if(isset($id))
+		{
+			if($db->select(TABLE_PREFIX . 'changelog', array('id' => $id)) !== false)
+				$db->delete(TABLE_PREFIX . 'changelog', array('id' => $id));
+			else
+				$errors[] = 'Changelog with id ' . $id . ' does not exist.';
+		}
+		else
+			$errors[] = 'Changelog id not set.';
+
+		if(count($errors)) {
+			return false;
+		}
+
+		self::clearCache();
+		return true;
+	}
+
+	static public function toggleHidden($id, &$errors, &$status)
+	{
+		global $db;
+		if(isset($id))
+		{
+			$query = $db->select(TABLE_PREFIX . 'changelog', array('id' => $id));
+			if($query !== false)
+			{
+				$db->update(TABLE_PREFIX . 'changelog', array('hidden' => ($query['hidden'] == 1 ? 0 : 1)), array('id' => $id));
+				$status = $query['hidden'];
+			}
+			else
+				$errors[] = 'Changelog with id ' . $id . ' does not exists.';
+		}
+		else
+			$errors[] = 'Changelog id not set.';
+
+		if(count($errors)) {
+			return false;
+		}
+
+		self::clearCache();
+		return true;
+	}
+
+	static public function getCached($type)
+	{
+		global $template_name;
+
+		$cache = Cache::getInstance();
+		if ($cache->enabled())
+		{
+			$tmp = '';
+			if ($cache->fetch('changelog_' . $template_name, $tmp) && isset($tmp[0])) {
+				return $tmp;
+			}
+		}
+
+		return false;
+	}
+
+	static public function clearCache()
+	{
+		global $template_name;
+		$cache = Cache::getInstance();
+		if (!$cache->enabled()) {
+			return;
+		}
+
+		$tmp = '';
+		foreach (get_templates() as $template) {
+			if ($cache->fetch('changelog_' . $template_name, $tmp)) {
+				$cache->delete('changelog_' . $template_name);
+			}
+
+		}
+	}
+}
diff --git a/system/pages/admin/changelog.php b/system/pages/admin/changelog.php
index 0c58c6bc..a6e7d01c 100644
--- a/system/pages/admin/changelog.php
+++ b/system/pages/admin/changelog.php
@@ -1,26 +1,140 @@
 <?php
 /**
- * CHANGELOG viewer
+ * CHANGELOG modifier
  *
  * @package   MyAAC
  * @author    Slawkens <slawkens@gmail.com>
- * @copyright 2019 MyAAC
+ * @author    Lee
+ * @copyright 2020 MyAAC
  * @link      https://my-aac.org
  */
 defined('MYAAC') or die('Direct access not allowed!');
-$title = 'MyAAC Changelog';
 
-if (!file_exists(BASE . 'CHANGELOG.md')) {
-	echo 'File CHANGELOG.md doesn\'t exist.';
+if (!hasFlag(FLAG_CONTENT_PAGES) && !superAdmin()) {
+	echo 'Access denied.';
 	return;
 }
 
-require LIBS . 'Parsedown.php';
+$title = 'Changelog';
+$use_datatable = true;
+define('CL_LIMIT', 600); // maximum changelog body length
+?>
 
-$changelog = file_get_contents(BASE . 'CHANGELOG.md');
+<link rel="stylesheet" type="text/css" href="<?php echo BASE_URL; ?>tools/css/jquery.datetimepicker.css"/ >
+<script src="<?php echo BASE_URL; ?>tools/js/jquery.datetimepicker.js"></script>
+<?php
+$id = isset($_GET['id']) ? $_GET['id'] : 0;
+require_once LIBS . 'changelog.php';
 
-$Parsedown = new Parsedown();
+if(!empty($action))
+{
+	$id = isset($_REQUEST['id']) ? $_REQUEST['id'] : null;
+	$body = isset($_REQUEST['body']) ? stripslashes($_REQUEST['body']) : null;
+	$create_date = isset($_REQUEST['createdate']) ? (int)strtotime($_REQUEST['createdate'] ): null;
+	$player_id = isset($_REQUEST['player_id']) ? (int)$_REQUEST['player_id'] : null;
+	$type = isset($_REQUEST['type']) ? (int)$_REQUEST['type'] : null;
+	$where = isset($_REQUEST['where']) ? (int)$_REQUEST['where'] : null;
 
-$changelog = $Parsedown->text($changelog); # prints: <p>Hello <em>Parsedown</em>!</p>
+	$errors = array();
 
-echo '<div>' . $changelog . '</div>';
+	if($action == 'add') {
+
+		if(Changelog::add($body, $type, $where, $player_id, $create_date, $errors)) {
+			$body = '';
+			$type = $where = $player_id = $create_date = 0;
+
+			success("Added successful.");
+		}
+	}
+	else if($action == 'delete') {
+		Changelog::delete($id, $errors);
+		success("Deleted successful.");
+	}
+	else if($action == 'edit')
+	{
+		if(isset($id) && !isset($body)) {
+			$cl = Changelog::get($id);
+			$body = $cl['body'];
+			$type = $cl['type'];
+			$where = $cl['where'];
+			$create_date = $cl['date'];
+			$player_id = $cl['player_id'];
+		}
+		else {
+			if(Changelog::update($id, $body, $type, $where, $player_id, $create_date,$errors)) {
+				$action = $body = '';
+				$type = $where = $player_id = $create_date = 0;
+
+				success("Updated successful.");
+			}
+		}
+	}
+	else if($action == 'hide') {
+		Changelog::toggleHidden($id, $errors, $status);
+		success(($status == 1 ? 'Show' : 'Hide') . " successful.");
+	}
+
+	if(!empty($errors))
+		error(implode(", ", $errors));
+}
+
+$changelogs = $db->query('SELECT * FROM `' . TABLE_PREFIX . 'changelog' . '` ORDER BY `id` DESC')->fetchAll();
+
+$i = 0;
+
+$log_type = [
+	['id' => 1, 'icon' => 'added'],
+	['id' => 2, 'icon' => 'removed'],
+	['id' => 3, 'icon' => 'changed'],
+	['id' => 4, 'icon' => 'fixed'],
+];
+
+$log_where = [
+	['id' => 1, 'icon' => 'server'],
+	['id' => 2, 'icon' => 'website'],
+];
+
+foreach($changelogs as $key => &$log)
+{
+	$log['type'] = getChangelogType($log['type']);
+	$log['where'] = getChangelogWhere($log['where']);
+}
+
+if($action == 'edit' || $action == 'new') {
+	if($action == 'edit') {
+		$player = new OTS_Player();
+		$player->load($player_id);
+	}
+
+	$account_players = $account_logged->getPlayersList();
+	$account_players->orderBy('group_id', POT::ORDER_DESC);
+	$twig->display('admin.changelog.form.html.twig', array(
+		'action' => $action,
+		'cl_link_form' => constant('ADMIN_URL').'?p=changelog&action=' . ($action == 'edit' ? 'edit' : 'add'),
+		'cl_id' => isset($id) ? $id : null,
+		'body' => isset($body) ? htmlentities($body, ENT_COMPAT, 'UTF-8') : '',
+		'create_date' => isset($create_date) ? $create_date : '',
+		'player' => isset($player) && $player->isLoaded() ? $player : null,
+		'player_id' => isset($player_id) ? $player_id : null,
+		'account_players' => $account_players,
+		'type' => isset($type) ? $type : 0,
+		'where' => isset($where) ? $where : 0,
+		'log_type' => $log_type,
+		'log_where' => $log_where,
+	));
+}
+$twig->display('admin.changelog.html.twig', array(
+	'changelogs' => $changelogs,
+));
+
+?>
+<script>
+	$(document).ready(function () {
+		$('#createdate').datetimepicker({format: "M d Y, H:i:s",});
+
+		$('.tb_datatable').DataTable({
+			"order": [[0, "desc"]],
+			"columnDefs": [{targets: [1, 2,4,5],orderable: false}]
+		});
+	});
+</script>
diff --git a/system/pages/admin/clmd.php b/system/pages/admin/clmd.php
new file mode 100644
index 00000000..9d27f170
--- /dev/null
+++ b/system/pages/admin/clmd.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * CHANGELOG viewer
+ *
+ * @package   MyAAC
+ * @author    Slawkens <slawkens@gmail.com>
+ * @author    Lee
+ * @copyright 2020 MyAAC
+ * @link      https://my-aac.org
+ */
+defined('MYAAC') or die('Direct access not allowed!');
+$title = 'MyAAC Changelog';
+
+if (!file_exists(BASE . 'CHANGELOG.md')) {
+	echo 'File CHANGELOG.md doesn\'t exist.';
+	return;
+}
+
+require LIBS . 'Parsedown.php';
+
+$changelog = file_get_contents(BASE . 'CHANGELOG.md');
+
+$Parsedown = new Parsedown();
+
+$changelog = $Parsedown->text($changelog); # prints: <p>Hello <em>Parsedown</em>!</p>
+
+echo '<div>' . $changelog . '</div>';
diff --git a/system/pages/admin/version.php b/system/pages/admin/version.php
index ec9f4f64..e643e728 100644
--- a/system/pages/admin/version.php
+++ b/system/pages/admin/version.php
@@ -24,10 +24,10 @@ if (!$myaac_version) {
 $version_compare = version_compare($myaac_version, MYAAC_VERSION);
 if ($version_compare == 0) {
 	success('MyAAC latest version is ' . $myaac_version . '. You\'re using the latest version.
-	<br/>View CHANGELOG ' . generateLink(ADMIN_URL . '?p=changelog', 'here'));
+	<br/>View CHANGELOG ' . generateLink(ADMIN_URL . '?p=clmd', 'here'));
 } else if ($version_compare < 0) {
 	success('Woah, seems you\'re using newer version as latest released one! MyAAC latest released version is ' . $myaac_version . ', and you\'re using version ' . MYAAC_VERSION . '.
-	<br/>View CHANGELOG ' . generateLink(ADMIN_URL . '?p=changelog', 'here'));
+	<br/>View CHANGELOG ' . generateLink(ADMIN_URL . '?p=clmd', 'here'));
 } else {
 	warning('You\'re using outdated version.<br/>
 		Your version: <b>' . MYAAC_VERSION . '</b><br/>
diff --git a/system/pages/changelog.php b/system/pages/changelog.php
index 6b2adb86..541f9088 100644
--- a/system/pages/changelog.php
+++ b/system/pages/changelog.php
@@ -16,7 +16,9 @@ $limit = 30;
 $offset = $_page * $limit;
 $next_page = false;
 
-$changelogs = $db->query('SELECT * FROM `' . TABLE_PREFIX . 'changelog' . '` WHERE `hidden` = 0 ORDER BY `id` DESC LIMIT ' . ($limit + 1) . ' OFFSET ' . $offset)->fetchAll();
+$canEdit = hasFlag(FLAG_CONTENT_NEWS) || superAdmin();
+
+$changelogs = $db->query('SELECT * FROM `' . TABLE_PREFIX . 'changelog` ' . ($canEdit ? '' : 'WHERE `hidden` = 0').' ORDER BY `id` DESC LIMIT ' . ($limit + 1) . ' OFFSET ' . $offset)->fetchAll();
 
 $i = 0;
 foreach($changelogs as $key => &$log)
@@ -39,33 +41,6 @@ $twig->display('changelog.html.twig', array(
 	'changelogs' => $changelogs,
 	'page' => $_page,
 	'next_page' => $next_page,
+	'canEdit' => $canEdit,
 ));
-
-function getChangelogType($v)
-{
-	switch($v) {
-		case 1:
-			return 'added';
-		case 2:
-			return 'removed';
-		case 3:
-			return 'changed';
-		case 4:
-			return 'fixed';
-	}
-
-	return 'unknown';
-}
-
-function getChangelogWhere($v)
-{
-	switch($v) {
-		case 1:
-			return 'server';
-		case 2:
-			return 'website';
-	}
-
-	return 'unknown';
-}
 ?>
diff --git a/system/templates/admin.changelog.form.html.twig b/system/templates/admin.changelog.form.html.twig
new file mode 100644
index 00000000..e3ca5dab
--- /dev/null
+++ b/system/templates/admin.changelog.form.html.twig
@@ -0,0 +1,59 @@
+{% if action %}
+	<div class="card card-info card-outline">
+		<div class="card-header">
+			<h5 class="m-0">{{ (action == 'edit') ? 'Edit' : 'Add' }}</h5>
+		</div>
+		<form role="form" method="post" action="{{ cl_link_form }}" id="cl-edit-form">
+			<div class="card-body">
+				{% if action == 'edit' %}
+					<input type="hidden" name="id" value="{{ cl_id }}"/>
+				{% endif %}
+
+				<div class="form-group row">
+					<label for="body">Content</label>
+					<textarea class="form-control" id="body" name="body" maxlength="600" cols="50" rows="5">{{ body|raw }}</textarea>
+				</div>
+				<div class="form-group row">
+					<div class="col-12 col-sm-12 col-lg-6">
+						<label for="createdate" class="control-label">Date:</label>
+						<input type="text" class="form-control" id="createdate" name="createdate" autocomplete="off"  maxlength="20" value="{{ create_date|date("M d Y, H:i:s") }}"/>
+					</div>
+					<div class="col-sm-6 pl-0">
+						<label for="player_id">Author</label>
+						<select class="form-control" name="player_id" id="player_id">
+							{% for player in account_players %}
+								<option value="{{ player.getId() }}"{% if player_id is defined and player.getId() == player_id %} selected="selected"{% endif %}>{{ player.getName() }}</option>
+							{% endfor %}
+						</select>
+					</div>
+				</div>
+				<div class="form-group row">
+					<div class="col-sm-6 pl-0">
+						<label for="select-where">Where</label>
+						<select class="form-control" name="where" id="select-where">
+							{% for id, cat in log_where %}
+								<option value="{{ cat.id }}"
+										{% if (where == 0 and id == 1) or (where == cat.id) %}selected="selected"{% endif %}>{{ cat.icon|capitalize }}</option>
+							{% endfor %}
+						</select>
+					</div>
+					<div class="col-sm-6 pl-0">
+						<label for="select-type">Type</label>
+						<select class="form-control" name="type" id="select-type">
+							{% for id, cat in log_type %}
+								<option value="{{ cat.id }}"
+										{% if (type == 0 and id == 1) or (type == cat.id) %}selected="selected"{% endif %}>{{ cat.icon|capitalize }}</option>
+							{% endfor %}
+						</select>
+					</div>
+				</div>
+			</div>
+			<div class="card-footer">
+				<button type="submit" class="btn btn-info"><i class="fas fa-update"></i> {{ (action == 'edit') ? 'Update' : 'Add' }}</button>
+				<button type="button" onclick="window.location = '{{ constant('ADMIN_URL') }}?p=changelog';"
+						class="btn btn-danger float-right"><i class="fas fa-cancel"></i> Cancel
+				</button>
+			</div>
+		</form>
+	</div>
+{% endif %}
diff --git a/system/templates/admin.changelog.html.twig b/system/templates/admin.changelog.html.twig
new file mode 100644
index 00000000..fe43982a
--- /dev/null
+++ b/system/templates/admin.changelog.html.twig
@@ -0,0 +1,55 @@
+<div class="card card-info card-outline">
+	<div class="card-header">
+		<h5 class="m-0">News:
+			<a href="{{ constant('ADMIN_URL') }}?p=changelog&action=new" class="float-right"><span
+					class="btn btn-sm btn-success">New</span></a>
+		</h5>
+	</div>
+
+	<div class="card-body">
+		<table class="tb_datatable table table-striped table-bordered">
+			<thead>
+			<tr>
+				<th width="5%">ID</th>
+				<th>Date</th>
+				<th>Description</th>
+				<th>Type</th>
+				<th>Where</th>
+				<th></th>
+			</tr>
+			</thead>
+			<tbody>
+			{% if changelogs|length > 0 %}
+				{% set i = 0 %}
+				{% for log in changelogs %}
+					<tr>
+						<td>{{ log.id }}</td>
+						<td>{{ log.date|date("j.m.Y") }}</td>
+						<td>{{ truncate(log.body|raw,20) }}</td>
+						<td><img src="{{ constant('BASE_URL') }}images/changelog/{{ log.type }}.png" title="{{ log.type|capitalize }}"/> {{ log.type|capitalize }}</td>
+						<td><img src="{{ constant('BASE_URL') }}images/changelog/{{ log.where }}.png" title="{{ log.where|capitalize }}"/> {{ log.where|capitalize }}</td>
+						<td>
+							<div class="btn-group">
+								<a href="{{ constant('ADMIN_URL') }}?p=changelog&action=edit&id={{ log.id }}" class="btn btn-success btn-sm" title="Edit">
+									<i class="fas fa-pencil-alt"></i>
+								</a>
+								<a href="{{ constant('ADMIN_URL') }}?p=changelog&action=delete&id={{ log.id }}" class="btn btn-danger btn-sm" onclick="return confirm('Are you sure?');" title="Delete">
+									<i class="fas fa-trash"></i>
+								</a>
+								<a href="{{ constant('ADMIN_URL') }}?p=changelog&action=hide&id={{ log.id }}" class="btn btn-{{ (log.hidden != 1) ? 'info' : 'default' }} btn-sm" title="{% if log.hidden != 1 %}Hide{% else %}Show{% endif %}">
+									<i class="fas fa-eye{{ (log.hidden != 1) ? '' : '-slash' }}"></i>
+								</a>
+							</div>
+						</td>
+					</tr>
+					{% set i = i + 1 %}
+				{% endfor %}
+			{% else %}
+				<tr>
+					<td colspan="6">There are no changelogs for the moment.</td>
+				</tr>
+			{% endif %}
+			</tbody>
+		</table>
+	</div>
+</div>
diff --git a/system/templates/changelog.html.twig b/system/templates/changelog.html.twig
index 8ba6c627..d63a6a2a 100644
--- a/system/templates/changelog.html.twig
+++ b/system/templates/changelog.html.twig
@@ -1,23 +1,41 @@
-<br/>
+{% if canEdit %}
+	<a href="{{ constant('ADMIN_URL') }}?p=changelog&action=new" class="btn btn-success btn-sm" title="Add New" target="_blank">Add New</a>
+{% endif %}
 <table border="0" cellspacing="1" cellpadding="4" width="100%">
 	<tr bgcolor="{{ config.vdarkborder }}">
 		<td width="22"><span class="white"><b>Type</b></span></td>
 		<td width="22"><span class="white"><b>Where</b></span></td>
 		<td width="50"><span class="white"><b>Date</b></span></td>
 		<td><span class="white"><b>Description</b></span></td>
+		{% if canEdit %}
+		<td></td>
+		{% endif %}
 	</tr>
 	{% if changelogs|length > 0%}
 		{% set i = 0 %}
 		{% for log in changelogs %}
 		<tr bgcolor="{{ getStyle(i) }}">
 			<td align="center">
-				<img src="images/changelog/{{ log.type }}.png" title="{{ log.type|capitalize }}"/>
+				<img src="{{ constant('BASE_URL') }}images/changelog/{{ log.type }}.png" title="{{ log.type|capitalize }}"/>
 			</td>
 			<td align="center">
-				<img src="images/changelog/{{ log.where }}.png" title="{{ log.where|capitalize }}"/>
+				<img src="{{ constant('BASE_URL') }}images/changelog/{{ log.where }}.png" title="{{ log.where|capitalize }}"/>
 			</td>
 			<td>{{ log.date|date("j.m.Y") }}</td>
-			<td>{{ log.body|raw }}</td>
+			<td>{{ log.body|nl2br}}</td>
+			{% if canEdit  %}
+				<td>
+					<a href="{{ constant('ADMIN_URL') }}?p=changelog&action=edit&id={{ log.id }}" title="Edit in Admin Panel" target="_blank">
+						<img src="images/edit.png"/>Edit
+					</a>
+					<a href="{{ constant('ADMIN_URL') }}?p=changelog&action=delete&id={{ log.id }}" onclick="return confirm('Are you sure?');" title="Delete in Admin Panel" target="_blank">
+						<img src="images/del.png"/>Delete
+					</a>
+					<a href="{{ constant('ADMIN_URL') }}?p=changelog&action=hide&id={{ log.id }}"  title="{% if log.hidden != 1 %}Hide{% else %}Show{% endif %} in Admin Panel" target="_blank">
+						<img src="images/{{ (log.hidden != 1 ? 'success' : 'error') }}.png"/>{{ (log.hidden != 1) ? 'Hide' : 'Show' }}
+					</a>
+				</td>
+			{% endif %}
 		</tr>
 		{% set i = i + 1 %}
 		{% endfor %}
@@ -35,4 +53,4 @@
 		<tr><td width="100%" align="right" valign="bottom"><a href="{{ getLink('changelog/' ~ (page + 1)) }}" class="size_xxs">Next Page</a></td></tr>
 	{% endif %}
 	</table>
-</table>
\ No newline at end of file
+</table>
diff --git a/system/twig.php b/system/twig.php
index 3a258843..e847f356 100644
--- a/system/twig.php
+++ b/system/twig.php
@@ -54,6 +54,20 @@ $function = new TwigFunction('getGuildLink', function ($s, $p) {
 });
 $twig->addFunction($function);
 
+$function = new TwigFunction('truncate', function ($s, $n) {
+    return truncate($s, $n);
+});
+$twig->addFunction($function);
+
+$function = new TwigFunction('getChangelogType', function ($n) {
+    return getChangelogType($n);
+});
+$twig->addFunction($function);
+
+$function = new TwigFunction('getChangelogWhere', function ($n) {
+	return getChangelogWhere($n);
+});
+$twig->addFunction($function);
 $function = new TwigFunction('hook', function ($hook) {
 	global $hooks;