From 5af9596dde162b1b9819869e3d5129f571a1c503 Mon Sep 17 00:00:00 2001
From: Michael Vogel <icarus@dabo.de>
Date: Thu, 19 Jul 2018 15:52:05 +0200
Subject: [PATCH] New item field "Post-type" and new table "permissionset"
 (#5408)

* "post-type" replaces "bookmark" and "type"

* Removed some more type

* Added index to permission set

* The permission set is now stored

* The permission set is now removed upon expiry

* Post update now stores the permission set

* New file

* Permissions are now sorted

* Changed documentation
---
 boot.php                              |  2 +-
 database.sql                          | 28 ++++++++++--
 include/api.php                       |  8 +---
 include/conversation.php              |  3 +-
 mod/editpost.php                      |  3 +-
 mod/item.php                          | 34 ++++----------
 mod/network.php                       |  4 +-
 mod/notes.php                         | 10 ++--
 mod/oexchange.php                     | 15 +++---
 mod/photos.php                        |  6 +--
 mod/poke.php                          |  1 -
 mod/subthread.php                     |  1 -
 mod/tagger.php                        |  1 -
 src/Database/DBStructure.php          | 32 ++++++++++---
 src/Database/PostUpdate.php           | 30 +++++++++---
 src/Model/Event.php                   |  2 +-
 src/Model/Item.php                    | 66 ++++++++++++---------------
 src/Model/PermissionSet.php           | 60 ++++++++++++++++++++++++
 src/Object/Post.php                   |  2 +-
 src/Protocol/DFRN.php                 |  7 +--
 src/Protocol/Diaspora.php             |  2 -
 src/Protocol/Feed.php                 |  1 -
 src/Protocol/OStatus.php              |  3 --
 src/Worker/Expire.php                 |  7 ++-
 update.php                            | 14 +++++-
 view/templates/jot.tpl                |  7 ++-
 view/theme/frio/templates/jot.tpl     |  4 +-
 view/theme/quattro/templates/jot.tpl  |  3 +-
 view/theme/smoothly/templates/jot.tpl | 11 ++---
 29 files changed, 222 insertions(+), 145 deletions(-)
 create mode 100644 src/Model/PermissionSet.php

diff --git a/boot.php b/boot.php
index 8f25c2b931..30d3c5748a 100644
--- a/boot.php
+++ b/boot.php
@@ -41,7 +41,7 @@ define('FRIENDICA_PLATFORM',     'Friendica');
 define('FRIENDICA_CODENAME',     'The Tazmans Flax-lily');
 define('FRIENDICA_VERSION',      '2018.08-dev');
 define('DFRN_PROTOCOL_VERSION',  '2.23');
-define('DB_UPDATE_VERSION',      1277);
+define('DB_UPDATE_VERSION',      1278);
 define('NEW_UPDATE_ROUTINE_VERSION', 1170);
 
 /**
diff --git a/database.sql b/database.sql
index 78632bbb6a..d745e83a7e 100644
--- a/database.sql
+++ b/database.sql
@@ -1,6 +1,6 @@
 -- ------------------------------------------
 -- Friendica 2018.08-dev (The Tazmans Flax-lily)
--- DB_UPDATE_VERSION 1277
+-- DB_UPDATE_VERSION 1278
 -- ------------------------------------------
 
 
@@ -471,9 +471,9 @@ CREATE TABLE IF NOT EXISTS `item` (
 	`icid` int unsigned COMMENT 'Id of the item-content table entry that contains the whole item content',
 	`iaid` int unsigned COMMENT 'Id of the item-activity table entry that contains the activity data',
 	`extid` varchar(255) NOT NULL DEFAULT '' COMMENT '',
+	`post-type` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'Post type (personal note, bookmark, ...)',
 	`global` boolean NOT NULL DEFAULT '0' COMMENT '',
 	`private` boolean NOT NULL DEFAULT '0' COMMENT 'distribution is restricted',
-	`bookmark` boolean NOT NULL DEFAULT '0' COMMENT 'item has been bookmarked',
 	`visible` boolean NOT NULL DEFAULT '0' COMMENT '',
 	`moderated` boolean NOT NULL DEFAULT '0' COMMENT '',
 	`deleted` boolean NOT NULL DEFAULT '0' COMMENT 'item has been deleted',
@@ -486,6 +486,7 @@ CREATE TABLE IF NOT EXISTS `item` (
 	`unseen` boolean NOT NULL DEFAULT '1' COMMENT 'item has not been seen',
 	`mention` boolean NOT NULL DEFAULT '0' COMMENT 'The owner of this item was mentioned in it',
 	`forum_mode` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '',
+	`psid` int unsigned COMMENT 'ID of the permission set of this post',
 	`allow_cid` mediumtext COMMENT 'Access Control - list of allowed contact.id \'<19><78>\'',
 	`allow_gid` mediumtext COMMENT 'Access Control - list of allowed groups',
 	`deny_cid` mediumtext COMMENT 'Access Control - list of denied contact.id',
@@ -495,7 +496,8 @@ CREATE TABLE IF NOT EXISTS `item` (
 	`resource-id` varchar(32) NOT NULL DEFAULT '' COMMENT 'Used to link other tables to items, it identifies the linked resource (e.g. photo) and if set must also set resource_type',
 	`event-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Used to link to the event.id',
 	`attach` mediumtext COMMENT 'JSON structure representing attachments to this item',
-	`type` varchar(20) NOT NULL DEFAULT '' COMMENT '',
+	`type` varchar(20) COMMENT 'Deprecated',
+	`bookmark` boolean COMMENT 'Deprecated',
 	`file` mediumtext COMMENT 'Deprecated',
 	`location` varchar(255) COMMENT 'Deprecated',
 	`coord` varchar(255) COMMENT 'Deprecated',
@@ -542,7 +544,8 @@ CREATE TABLE IF NOT EXISTS `item` (
 	 INDEX `uid_wall_changed` (`uid`,`wall`,`changed`),
 	 INDEX `uid_eventid` (`uid`,`event-id`),
 	 INDEX `icid` (`icid`),
-	 INDEX `iaid` (`iaid`)
+	 INDEX `iaid` (`iaid`),
+	 INDEX `psid` (`psid`)
 ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Structure for all posts';
 
 --
@@ -760,6 +763,20 @@ CREATE TABLE IF NOT EXISTS `pconfig` (
 	 UNIQUE INDEX `uid_cat_k` (`uid`,`cat`,`k`)
 ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='personal (per user) configuration storage';
 
+--
+-- TABLE permissionset
+--
+CREATE TABLE IF NOT EXISTS `permissionset` (
+	`id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID',
+	`uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner id of this permission set',
+	`allow_cid` mediumtext COMMENT 'Access Control - list of allowed contact.id \'<19><78>\'',
+	`allow_gid` mediumtext COMMENT 'Access Control - list of allowed groups',
+	`deny_cid` mediumtext COMMENT 'Access Control - list of denied contact.id',
+	`deny_gid` mediumtext COMMENT 'Access Control - list of denied groups',
+	 PRIMARY KEY(`id`),
+	 INDEX `uid_allow_cid_allow_gid_deny_cid_deny_gid` (`allow_cid`(50),`allow_gid`(30),`deny_cid`(50),`deny_gid`(30))
+) DEFAULT COLLATE utf8mb4_general_ci COMMENT='';
+
 --
 -- TABLE photo
 --
@@ -1031,13 +1048,14 @@ CREATE TABLE IF NOT EXISTS `thread` (
 	`visible` boolean NOT NULL DEFAULT '0' COMMENT '',
 	`starred` boolean NOT NULL DEFAULT '0' COMMENT '',
 	`ignored` boolean NOT NULL DEFAULT '0' COMMENT '',
-	`bookmark` boolean NOT NULL DEFAULT '0' COMMENT '',
+	`post-type` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'Post type (personal note, bookmark, ...)',
 	`unseen` boolean NOT NULL DEFAULT '1' COMMENT '',
 	`deleted` boolean NOT NULL DEFAULT '0' COMMENT '',
 	`origin` boolean NOT NULL DEFAULT '0' COMMENT '',
 	`forum_mode` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '',
 	`mention` boolean NOT NULL DEFAULT '0' COMMENT '',
 	`network` char(4) NOT NULL DEFAULT '' COMMENT '',
+	`bookmark` boolean COMMENT '',
 	 PRIMARY KEY(`iid`),
 	 INDEX `uid_network_commented` (`uid`,`network`,`commented`),
 	 INDEX `uid_network_created` (`uid`,`network`,`created`),
diff --git a/include/api.php b/include/api.php
index 58f086c012..b67c5a5650 100644
--- a/include/api.php
+++ b/include/api.php
@@ -1035,7 +1035,6 @@ function api_statuses_mediap($type)
 	}
 	$user_info = api_get_user($a);
 
-	$_REQUEST['type'] = 'wall';
 	$_REQUEST['profile_uid'] = api_user();
 	$_REQUEST['api_source'] = true;
 	$txt = requestdata('status');
@@ -1124,9 +1123,7 @@ function api_statuses_update($type)
 	}
 	$_REQUEST['profile_uid'] = api_user();
 
-	if ($parent) {
-		$_REQUEST['type'] = 'net-comment';
-	} else {
+	if (!$parent) {
 		// Check for throttling (maximum posts per day, week and month)
 		$throttle_day = Config::get('system', 'throttle_limit_day');
 		if ($throttle_day > 0) {
@@ -1169,8 +1166,6 @@ function api_statuses_update($type)
 				throw new TooManyRequestsException(L10n::t("Monthly posting limit of %d post reached. The post was rejected.", "Monthly posting limit of %d posts reached. The post was rejected.", $throttle_month));
 			}
 		}
-
-		$_REQUEST['type'] = 'wall';
 	}
 
 	if (x($_FILES, 'media')) {
@@ -1992,7 +1987,6 @@ function api_statuses_repeat($type)
 		}
 		$_REQUEST['body'] = $post;
 		$_REQUEST['profile_uid'] = api_user();
-		$_REQUEST['type'] = 'wall';
 		$_REQUEST['api_source'] = true;
 
 		if (!x($_REQUEST, "source")) {
diff --git a/include/conversation.php b/include/conversation.php
index 21b700f2fe..54716cd687 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -1149,7 +1149,8 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false)
 		'$wait'         => L10n::t('Please wait'),
 		'$permset'      => L10n::t('Permission settings'),
 		'$shortpermset' => L10n::t('permissions'),
-		'$ptyp'         => $notes_cid ? 'note' : 'wall',
+		'$wall'         => $notes_cid ? 0 : 1,
+		'$posttype'     => $notes_cid ? Item::PT_PERSONAL_NOTE : Item::PT_ARTICLE,
 		'$content'      => defaults($x, 'content', ''),
 		'$post_id'      => defaults($x, 'post_id', ''),
 		'$baseurl'      => System::baseUrl(true),
diff --git a/mod/editpost.php b/mod/editpost.php
index 04caaf0a20..7994e9e239 100644
--- a/mod/editpost.php
+++ b/mod/editpost.php
@@ -110,7 +110,8 @@ function editpost_content(App $a) {
 		'$shortnoloc' => L10n::t('clear location'),
 		'$wait' => L10n::t('Please wait'),
 		'$permset' => L10n::t('Permission settings'),
-		'$ptyp' => $item['type'],
+		'$wall' => $item['wall'],
+		'$posttype' => $item['post-type'],
 		'$content' => undo_post_tagging($item['body']),
 		'$post_id' => $post_id,
 		'$baseurl' => System::baseUrl(),
diff --git a/mod/item.php b/mod/item.php
index a7a9543d00..2359b79c58 100644
--- a/mod/item.php
+++ b/mod/item.php
@@ -90,6 +90,7 @@ function item_post(App $a) {
 
 	$objecttype = null;
 	$profile_uid = defaults($_REQUEST, 'profile_uid', local_user());
+	$posttype = defaults($_REQUEST, 'post_type', Item::PT_ARTICLE);
 
 	if ($thr_parent || $thr_parent_uri) {
 		if ($thr_parent) {
@@ -124,10 +125,6 @@ function item_post(App $a) {
 		$parent_contact = Contact::getDetailsByURL($parent_item["author-link"]);
 
 		$objecttype = ACTIVITY_OBJ_COMMENT;
-
-		if (!x($_REQUEST, 'type')) {
-			$_REQUEST['type'] = 'net-comment';
-		}
 	}
 
 	if ($parent) {
@@ -138,6 +135,7 @@ function item_post(App $a) {
 	$app         = strip_tags(defaults($_REQUEST, 'source', ''));
 	$extid       = strip_tags(defaults($_REQUEST, 'extid', ''));
 	$object      = defaults($_REQUEST, 'object', '');
+	$wall        = intval(defaults($_REQUEST, 'wall', 1));
 
 	// Ensure that the user id in a thread always stay the same
 	if (!is_null($parent_user) && in_array($parent_user, [local_user(), 0])) {
@@ -259,6 +257,8 @@ function item_post(App $a) {
 			$str_contact_deny  = $parent_item['deny_cid'];
 			$str_group_deny    = $parent_item['deny_gid'];
 			$private           = $parent_item['private'];
+
+			$wall              = $parent_item['wall'];
 		}
 
 		$pubmail_enabled = defaults($_REQUEST, 'pubmail_enable', false) && !$private;
@@ -329,16 +329,6 @@ function item_post(App $a) {
 		$contact_record = dba::selectFirst('contact', [], ['uid' => $profile_uid, 'self' => true]);
 	}
 
-	$post_type = notags(trim($_REQUEST['type']));
-
-	if ($post_type === 'net-comment' && $parent_item !== null) {
-		if ($parent_item['wall'] == 1) {
-			$post_type = 'wall-comment';
-		} else {
-			$post_type = 'remote-comment';
-		}
-	}
-
 	// Look for any tags and linkify them
 	$str_tags = '';
 	$inform   = '';
@@ -429,6 +419,7 @@ function item_post(App $a) {
 		$contact_id = $private_id;
 		$contact_record = $forum_contact;
 		$_REQUEST['origin'] = false;
+		$wall = 0;
 	}
 
 	/*
@@ -507,11 +498,11 @@ function item_post(App $a) {
 
 	// embedded bookmark or attachment in post? set bookmark flag
 
-	$bookmark = 0;
 	$data = BBCode::getAttachmentData($body);
-	if (preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", $body, $match, PREG_SET_ORDER) || isset($data["type"])) {
+	if ((preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", $body, $match, PREG_SET_ORDER) || isset($data["type"]))
+		&& ($posttype != Item::PT_PERSONAL_NOTE)) {
+		$posttype = Item::PT_PAGE;
 		$objecttype = ACTIVITY_OBJ_BOOKMARK;
-		$bookmark = 1;
 	}
 
 	$body = bb_translate_video($body);
@@ -556,12 +547,6 @@ function item_post(App $a) {
 		}
 	}
 
-	$wall = 0;
-
-	if (($post_type === 'wall' || $post_type === 'wall-comment') && !count($forum_contact)) {
-		$wall = 1;
-	}
-
 	if (!strlen($verb)) {
 		$verb = ACTIVITY_POST;
 	}
@@ -588,7 +573,6 @@ function item_post(App $a) {
 
 	$datarray = [];
 	$datarray['uid']           = $profile_uid;
-	$datarray['type']          = $post_type;
 	$datarray['wall']          = $wall;
 	$datarray['gravity']       = $gravity;
 	$datarray['network']       = $network;
@@ -618,6 +602,7 @@ function item_post(App $a) {
 	$datarray['file']          = $categories;
 	$datarray['inform']        = $inform;
 	$datarray['verb']          = $verb;
+	$datarray['post-type']     = $posttype;
 	$datarray['object-type']   = $objecttype;
 	$datarray['allow_cid']     = $str_contact_allow;
 	$datarray['allow_gid']     = $str_group_allow;
@@ -626,7 +611,6 @@ function item_post(App $a) {
 	$datarray['private']       = $private;
 	$datarray['pubmail']       = $pubmail_enabled;
 	$datarray['attach']        = $attachments;
-	$datarray['bookmark']      = intval($bookmark);
 
 	// This is not a bug. The item store function changes 'parent-uri' to 'thr-parent' and fetches 'parent-uri' new. (We should change this)
 	$datarray['parent-uri']    = $thr_parent_uri;
diff --git a/mod/network.php b/mod/network.php
index b2f6b7ba88..67dd651e22 100644
--- a/mod/network.php
+++ b/mod/network.php
@@ -589,8 +589,8 @@ function networkThreadedView(App $a, $update, $parent)
 	// desired.
 
 	$sql_post_table = '';
-	$sql_options = (($star) ? " AND `thread`.`starred` " : '');
-	$sql_options .= (($bmark) ? " AND `thread`.`bookmark` " : '');
+	$sql_options = ($star ? " AND `thread`.`starred` " : '');
+	$sql_options .= ($bmark ? sprintf(" AND `thread`.`post-type` = %d ", Item::PT_PAGE) : '');
 	$sql_extra = $sql_options;
 	$sql_extra2 = '';
 	$sql_extra3 = '';
diff --git a/mod/notes.php b/mod/notes.php
index 553656406e..69a5280f7e 100644
--- a/mod/notes.php
+++ b/mod/notes.php
@@ -57,13 +57,9 @@ function notes_content(App $a, $update = false)
 		$o .= status_editor($a, $x, $a->contact['id']);
 	}
 
-	$condition = ["`uid` = ? AND `type` = 'note' AND `gravity` = ? AND NOT `wall`
-		AND `allow_cid` = ? AND `contact-id` = ?",
-		local_user(), GRAVITY_PARENT, '<' . $a->contact['id'] . '>', $a->contact['id']];
+	$condition = ['uid' => local_user(), 'post-type' => Item::PT_PERSONAL_NOTE, 'gravity' => GRAVITY_PARENT,
+		'wall' => false, 'allow_cid' => '<' . $a->contact['id'] . '>', 'contact-id'=> $a->contact['id']];
 
-	$notes = dba::count('item', $condition);
-
-	$a->set_pager_total($notes);
 	$a->set_pager_itemspage(40);
 
 	$params = ['order' => ['created' => true],
@@ -86,6 +82,6 @@ function notes_content(App $a, $update = false)
 		}
 	}
 
-	$o .= paginate($a);
+	$o .= alt_pager($a, count($r));
 	return $o;
 }
diff --git a/mod/oexchange.php b/mod/oexchange.php
index 9f844e1db3..72577ab4ef 100644
--- a/mod/oexchange.php
+++ b/mod/oexchange.php
@@ -21,7 +21,7 @@ function oexchange_init(App $a) {
 
 function oexchange_content(App $a) {
 
-	if (! local_user()) {
+	if (!local_user()) {
 		$o = Login::form();
 		return $o;
 	}
@@ -31,27 +31,26 @@ function oexchange_content(App $a) {
 		return;
 	}
 
-	$url = (((x($_REQUEST,'url')) && strlen($_REQUEST['url']))
+	$url = ((x($_REQUEST,'url') && strlen($_REQUEST['url']))
 		? urlencode(notags(trim($_REQUEST['url']))) : '');
-	$title = (((x($_REQUEST,'title')) && strlen($_REQUEST['title']))
+	$title = ((x($_REQUEST,'title') && strlen($_REQUEST['title']))
 		? '&title=' . urlencode(notags(trim($_REQUEST['title']))) : '');
-	$description = (((x($_REQUEST,'description')) && strlen($_REQUEST['description']))
+	$description = ((x($_REQUEST,'description') && strlen($_REQUEST['description']))
 		? '&description=' . urlencode(notags(trim($_REQUEST['description']))) : '');
-	$tags = (((x($_REQUEST,'tags')) && strlen($_REQUEST['tags']))
+	$tags = ((x($_REQUEST,'tags') && strlen($_REQUEST['tags']))
 		? '&tags=' . urlencode(notags(trim($_REQUEST['tags']))) : '');
 
 	$s = Network::fetchUrl(System::baseUrl() . '/parse_url?f=&url=' . $url . $title . $description . $tags);
 
-	if (! strlen($s)) {
+	if (!strlen($s)) {
 		return;
 	}
 
 	$post = [];
 
 	$post['profile_uid'] = local_user();
-	$post['return'] = '/oexchange/done' ;
+	$post['return'] = '/oexchange/done';
 	$post['body'] = Friendica\Content\Text\HTML::toBBCode($s);
-	$post['type'] = 'wall';
 
 	$_REQUEST = $post;
 	require_once('mod/item.php');
diff --git a/mod/photos.php b/mod/photos.php
index 7c5f539d06..bd1de938c8 100644
--- a/mod/photos.php
+++ b/mod/photos.php
@@ -459,7 +459,7 @@ function photos_post(App $a)
 			$arr['uid']           = $page_owner_uid;
 			$arr['uri']           = $uri;
 			$arr['parent-uri']    = $uri;
-			$arr['type']          = 'photo';
+			$arr['post-type']     = Item::PT_IMAGE;
 			$arr['wall']          = 1;
 			$arr['resource-id']   = $p[0]['resource-id'];
 			$arr['contact-id']    = $owner_record['id'];
@@ -626,7 +626,6 @@ function photos_post(App $a)
 					$arr['uid']           = $page_owner_uid;
 					$arr['uri']           = $uri;
 					$arr['parent-uri']    = $uri;
-					$arr['type']          = 'activity';
 					$arr['wall']          = 1;
 					$arr['contact-id']    = $owner_record['id'];
 					$arr['owner-name']    = $owner_record['name'];
@@ -1446,7 +1445,6 @@ function photos_content(App $a)
 					$comments .= replace_macros($cmnt_tpl, [
 						'$return_path' => '',
 						'$jsreload' => $return_url,
-						'$type' => 'wall-comment',
 						'$id' => $link_item['id'],
 						'$parent' => $link_item['id'],
 						'$profile_uid' =>  $owner_uid,
@@ -1485,7 +1483,6 @@ function photos_content(App $a)
 					$comments .= replace_macros($cmnt_tpl,[
 						'$return_path' => '',
 						'$jsreload' => $return_url,
-						'$type' => 'wall-comment',
 						'$id' => $link_item['id'],
 						'$parent' => $link_item['id'],
 						'$profile_uid' =>  $owner_uid,
@@ -1546,7 +1543,6 @@ function photos_content(App $a)
 						$comments .= replace_macros($cmnt_tpl, [
 							'$return_path' => '',
 							'$jsreload' => $return_url,
-							'$type' => 'wall-comment',
 							'$id' => $item['item_id'],
 							'$parent' => $item['parent'],
 							'$profile_uid' =>  $owner_uid,
diff --git a/mod/poke.php b/mod/poke.php
index 2fd7068f78..561a5b7989 100644
--- a/mod/poke.php
+++ b/mod/poke.php
@@ -100,7 +100,6 @@ function poke_init(App $a) {
 	$arr['uid']           = $uid;
 	$arr['uri']           = $uri;
 	$arr['parent-uri']    = ($parent_uri ? $parent_uri : $uri);
-	$arr['type']          = 'activity';
 	$arr['wall']          = 1;
 	$arr['contact-id']    = $poster['id'];
 	$arr['owner-name']    = $poster['name'];
diff --git a/mod/subthread.php b/mod/subthread.php
index a624cd9a60..3cd089d63e 100644
--- a/mod/subthread.php
+++ b/mod/subthread.php
@@ -122,7 +122,6 @@ EOT;
 	$arr['uri'] = $uri;
 	$arr['uid'] = $owner_uid;
 	$arr['contact-id'] = $contact['id'];
-	$arr['type'] = 'activity';
 	$arr['wall'] = $item['wall'];
 	$arr['origin'] = 1;
 	$arr['gravity'] = GRAVITY_ACTIVITY;
diff --git a/mod/tagger.php b/mod/tagger.php
index 0df31ac9a3..0c515f9c8b 100644
--- a/mod/tagger.php
+++ b/mod/tagger.php
@@ -119,7 +119,6 @@ EOT;
 	$arr['uri'] = $uri;
 	$arr['uid'] = $owner_uid;
 	$arr['contact-id'] = $contact['id'];
-	$arr['type'] = 'activity';
 	$arr['wall'] = $item['wall'];
 	$arr['gravity'] = GRAVITY_COMMENT;
 	$arr['parent'] = $item['id'];
diff --git a/src/Database/DBStructure.php b/src/Database/DBStructure.php
index ee46c2b4cb..24d7fbaae5 100644
--- a/src/Database/DBStructure.php
+++ b/src/Database/DBStructure.php
@@ -1174,9 +1174,9 @@ class DBStructure
 						"icid" => ["type" => "int unsigned", "relation" => ["item-content" => "id"], "comment" => "Id of the item-content table entry that contains the whole item content"],
 						"iaid" => ["type" => "int unsigned", "relation" => ["item-activity" => "id"], "comment" => "Id of the item-activity table entry that contains the activity data"],
 						"extid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
+						"post-type" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "Post type (personal note, bookmark, ...)"],
 						"global" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
 						"private" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "distribution is restricted"],
-						"bookmark" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "item has been bookmarked"],
 						"visible" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
 						"moderated" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
 						"deleted" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "item has been deleted"],
@@ -1190,22 +1190,23 @@ class DBStructure
 						"unseen" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => "item has not been seen"],
 						"mention" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "The owner of this item was mentioned in it"],
 						"forum_mode" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
-						// User specific fields. Should possible be replaced with something different
+						"psid" => ["type" => "int unsigned", "relation" => ["permissionset" => "id"], "comment" => "ID of the permission set of this post"],
+						// These fields will be replaced by the "psid" from above
 						"allow_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed contact.id '<19><78>'"],
 						"allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed groups"],
 						"deny_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied contact.id"],
 						"deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied groups"],
+						// These fields will be moved into some item-delivery-information table
 						"postopts" => ["type" => "text", "comment" => "External post connectors add their network name to this comma-separated string to identify that they should be delivered to these networks during delivery"],
 						"inform" => ["type" => "mediumtext", "comment" => "Additional receivers of this post"],
 						// It is to be decided whether these fields belong to the user or the structure
 						"resource-id" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => "Used to link other tables to items, it identifies the linked resource (e.g. photo) and if set must also set resource_type"],
 						"event-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["event" => "id"], "comment" => "Used to link to the event.id"],
-						// Will be replaced by the "attach" table
+						// Could possibly be replaced by the "attach" table?
 						"attach" => ["type" => "mediumtext", "comment" => "JSON structure representing attachments to this item"],
-						// Seems to be only used for notes, but is filled at many places.
-						// Will be replaced with some general field that contain the values of "origin" and "wall" as well.
-						"type" => ["type" => "varchar(20)", "not null" => "1", "default" => "", "comment" => ""],
 						// Deprecated fields. Will be removed in upcoming versions
+						"type" => ["type" => "varchar(20)", "comment" => "Deprecated"],
+						"bookmark" => ["type" => "boolean", "comment" => "Deprecated"],
 						"file" => ["type" => "mediumtext", "comment" => "Deprecated"],
 						"location" => ["type" => "varchar(255)", "comment" => "Deprecated"],
 						"coord" => ["type" => "varchar(255)", "comment" => "Deprecated"],
@@ -1255,6 +1256,7 @@ class DBStructure
 						"uid_eventid" => ["uid","event-id"],
 						"icid" => ["icid"],
 						"iaid" => ["iaid"],
+						"psid" => ["psid"],
 						]
 				];
 		$database["item-activity"] = [
@@ -1485,6 +1487,21 @@ class DBStructure
 						"uid_cat_k" => ["UNIQUE", "uid", "cat", "k"],
 						]
 				];
+		$database["permissionset"] = [
+				"comment" => "",
+				"fields" => [
+						"id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
+						"uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "Owner id of this permission set"],
+						"allow_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed contact.id '<19><78>'"],
+						"allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed groups"],
+						"deny_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied contact.id"],
+						"deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied groups"],
+						],
+				"indexes" => [
+						"PRIMARY" => ["id"],
+						"uid_allow_cid_allow_gid_deny_cid_deny_gid" => ["allow_cid(50)", "allow_gid(30)", "deny_cid(50)", "deny_gid(30)"],
+						]
+				];
 		$database["photo"] = [
 				"comment" => "photo storage",
 				"fields" => [
@@ -1768,13 +1785,14 @@ class DBStructure
 						"visible" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
 						"starred" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
 						"ignored" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
-						"bookmark" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+						"post-type" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "Post type (personal note, bookmark, ...)"],
 						"unseen" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => ""],
 						"deleted" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
 						"origin" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
 						"forum_mode" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
 						"mention" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
 						"network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => ""],
+						"bookmark" => ["type" => "boolean", "comment" => ""],
 						],
 				"indexes" => [
 						"PRIMARY" => ["iid"],
diff --git a/src/Database/PostUpdate.php b/src/Database/PostUpdate.php
index d391d531d5..416dc92243 100644
--- a/src/Database/PostUpdate.php
+++ b/src/Database/PostUpdate.php
@@ -8,6 +8,7 @@ use Friendica\Core\Config;
 use Friendica\Database\DBM;
 use Friendica\Model\Contact;
 use Friendica\Model\Item;
+use Friendica\Model\PermissionSet;
 use dba;
 
 require_once 'include/dba.php';
@@ -31,7 +32,7 @@ class PostUpdate
 		if (!self::update1206()) {
 			return;
 		}
-		if (!self::update1276()) {
+		if (!self::update1278()) {
 			return;
 		}
 	}
@@ -227,19 +228,20 @@ class PostUpdate
 	 *
 	 * @return bool "true" when the job is done
 	 */
-	private static function update1276()
+	private static function update1278()
 	{
 		// Was the script completed?
-		if (Config::get("system", "post_update_version") >= 1276) {
+		if (Config::get("system", "post_update_version") >= 1278) {
 			return true;
 		}
 
-		$id = Config::get("system", "post_update_version_1276_id", 0);
+		$id = Config::get("system", "post_update_version_1278_id", 0);
 
 		logger("Start from item " . $id, LOGGER_DEBUG);
 
 		$fields = array_merge(Item::MIXED_CONTENT_FIELDLIST, ['network', 'author-id', 'owner-id', 'tag', 'file',
-			'author-name', 'author-avatar', 'author-link', 'owner-name', 'owner-avatar', 'owner-link', 'id']);
+			'author-name', 'author-avatar', 'author-link', 'owner-name', 'owner-avatar', 'owner-link', 'id',
+			'uid', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'psid', 'post-type', 'bookmark', 'type']);
 
 		$start_id = $id;
 		$rows = 0;
@@ -263,18 +265,32 @@ class PostUpdate
 				$item['owner-id'] = Contact::getIdForURL($item["owner-link"], 0, false, $default);
 			}
 
+			if (empty($item['psid'])) {
+				$item['psid'] = PermissionSet::fetchIDForPost($item);
+			}
+
+			if ($item['post-type'] == 0) {
+				if (!empty($item['type']) && ($item['type'] == 'note')) {
+					$item['post-type'] = Item::PT_PERSONAL_NOTE;
+				} elseif (!empty($item['type']) && ($item['type'] == 'photo')) {
+					$item['post-type'] = Item::PT_IMAGE;
+				} elseif (!empty($item['bookmark']) && $item['bookmark']) {
+					$item['post-type'] = Item::PT_PAGE;
+				}
+			}
+
 			Item::update($item, ['id' => $id]);
 
 			++$rows;
 		}
 		dba::close($items);
 
-		Config::set("system", "post_update_version_1276_id", $id);
+		Config::set("system", "post_update_version_1278_id", $id);
 
 		logger("Processed rows: " . $rows . " - last processed item:  " . $id, LOGGER_DEBUG);
 
 		if ($start_id == $id) {
-			Config::set("system", "post_update_version", 1276);
+			Config::set("system", "post_update_version", 1278);
 			logger("Done", LOGGER_DEBUG);
 			return true;
 		}
diff --git a/src/Model/Event.php b/src/Model/Event.php
index 66d5f389fe..47ec50aaa0 100644
--- a/src/Model/Event.php
+++ b/src/Model/Event.php
@@ -319,7 +319,7 @@ class Event extends BaseObject
 			$item_arr['uri']           = $event['uri'];
 			$item_arr['parent-uri']    = $event['uri'];
 			$item_arr['guid']          = $event['guid'];
-			$item_arr['type']          = 'activity';
+			$item_arr['post-type']     = Item::PT_EVENT;
 			$item_arr['wall']          = $event['cid'] ? 0 : 1;
 			$item_arr['contact-id']    = $contact['id'];
 			$item_arr['owner-name']    = $contact['name'];
diff --git a/src/Model/Item.php b/src/Model/Item.php
index d6635407dc..d6e30c926f 100644
--- a/src/Model/Item.php
+++ b/src/Model/Item.php
@@ -17,6 +17,7 @@ use Friendica\Core\PConfig;
 use Friendica\Core\System;
 use Friendica\Core\Worker;
 use Friendica\Database\DBM;
+use Friendica\Model\PermissionSet;
 use Friendica\Object\Image;
 use Friendica\Protocol\Diaspora;
 use Friendica\Protocol\OStatus;
@@ -30,6 +31,17 @@ require_once 'include/text.php';
 
 class Item extends BaseObject
 {
+	// Posting types, inspired by https://www.w3.org/TR/activitystreams-vocabulary/#object-types
+	const PT_ARTICLE = 0;
+	const PT_NOTE = 1;
+	const PT_PAGE = 2;
+	const PT_IMAGE = 16;
+	const PT_AUDIO = 17;
+	const PT_VIDEO = 18;
+	const PT_DOCUMENT = 19;
+	const PT_EVENT = 32;
+	const PT_PERSONAL_NOTE = 128;
+
 	// Field list that is used to display the items
 	const DISPLAY_FIELDLIST = ['uid', 'id', 'parent', 'uri', 'thr-parent', 'parent-uri', 'guid', 'network',
 			'commented', 'created', 'edited', 'received', 'verb', 'object-type', 'postopts', 'plink',
@@ -48,7 +60,7 @@ class Item extends BaseObject
 	const DELIVER_FIELDLIST = ['uid', 'id', 'parent', 'uri', 'thr-parent', 'parent-uri', 'guid',
 			'created', 'edited', 'verb', 'object-type', 'object', 'target',
 			'private', 'title', 'body', 'location', 'coord', 'app',
-			'attach', 'tag', 'bookmark', 'deleted', 'extid',
+			'attach', 'tag', 'deleted', 'extid', 'post-type',
 			'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid',
 			'author-id', 'author-link', 'owner-link', 'contact-uid',
 			'signed_text', 'signature', 'signer', 'network'];
@@ -63,10 +75,10 @@ class Item extends BaseObject
 
 	// All fields in the item table
 	const ITEM_FIELDLIST = ['id', 'uid', 'parent', 'uri', 'parent-uri', 'thr-parent', 'guid',
-			'contact-id', 'type', 'wall', 'gravity', 'extid', 'icid', 'iaid',
+			'contact-id', 'type', 'wall', 'gravity', 'extid', 'icid', 'iaid', 'psid',
 			'created', 'edited', 'commented', 'received', 'changed', 'verb',
 			'postopts', 'plink', 'resource-id', 'event-id', 'tag', 'attach', 'inform',
-			'file', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid',
+			'file', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'post-type',
 			'private', 'pubmail', 'moderated', 'visible', 'starred', 'bookmark',
 			'unseen', 'deleted', 'origin', 'forum_mode', 'mention', 'global', 'network',
 			'title', 'content-warning', 'body', 'location', 'coord', 'app',
@@ -464,7 +476,7 @@ class Item extends BaseObject
 
 		$threadfields = ['thread' => ['iid', 'uid', 'contact-id', 'owner-id', 'author-id',
 			'created', 'edited', 'commented', 'received', 'changed', 'wall', 'private',
-			'pubmail', 'moderated', 'visible', 'starred', 'ignored', 'bookmark',
+			'pubmail', 'moderated', 'visible', 'starred', 'ignored', 'post-type',
 			'unseen', 'deleted', 'origin', 'forum_mode', 'mention', 'network']];
 
 		$select_fields = self::constructSelectFields($fields, $selected);
@@ -501,8 +513,8 @@ class Item extends BaseObject
 		$fields['item'] = ['id', 'uid', 'parent', 'uri', 'parent-uri', 'thr-parent', 'guid',
 			'contact-id', 'owner-id', 'author-id', 'type', 'wall', 'gravity', 'extid',
 			'created', 'edited', 'commented', 'received', 'changed', 'postopts',
-			'resource-id', 'event-id', 'tag', 'attach', 'inform',
-			'file', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid',
+			'resource-id', 'event-id', 'tag', 'attach', 'inform', 'post-type',
+			'file', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'psid',
 			'private', 'pubmail', 'moderated', 'visible', 'starred', 'bookmark',
 			'unseen', 'deleted', 'origin', 'forum_mode', 'mention', 'global',
 			'id' => 'item_id', 'network', 'icid', 'iaid', 'id' => 'internal-iid',
@@ -750,8 +762,8 @@ class Item extends BaseObject
 			}
 		}
 
-		$author_owner_fields = ['author-name', 'author-avatar', 'author-link', 'owner-name', 'owner-avatar', 'owner-link'];
-		foreach ($author_owner_fields as $field) {
+		$clear_fields = ['bookmark', 'type', 'author-name', 'author-avatar', 'author-link', 'owner-name', 'owner-avatar', 'owner-link'];
+		foreach ($clear_fields as $field) {
 			if (array_key_exists($field, $fields)) {
 				$fields[$field] = null;
 			}
@@ -1179,7 +1191,6 @@ class Item extends BaseObject
 		// If it is a posting where users should get notifications, then define it as wall posting
 		if ($notify) {
 			$item['wall'] = 1;
-			$item['type'] = 'wall';
 			$item['origin'] = 1;
 			$item['network'] = NETWORK_DFRN;
 			$item['protocol'] = PROTOCOL_DFRN;
@@ -1232,19 +1243,15 @@ class Item extends BaseObject
 			$item['parent-uri'] = $item['thr-parent'];
 		}
 
-		$item['type'] = defaults($item, 'type', 'remote');
-
 		if (isset($item['gravity'])) {
 			$item['gravity'] = intval($item['gravity']);
 		} elseif ($item['parent-uri'] === $item['uri']) {
 			$item['gravity'] = GRAVITY_PARENT;
 		} elseif (activity_match($item['verb'], ACTIVITY_POST)) {
 			$item['gravity'] = GRAVITY_COMMENT;
-		} elseif ($item['type'] == 'activity') {
-			$item['gravity'] = GRAVITY_ACTIVITY;
 		} else {
 			$item['gravity'] = GRAVITY_UNKNOWN;   // Should not happen
-			logger('Unknown gravity for verb: ' . $item['verb'] . ' - type: ' . $item['type'], LOGGER_DEBUG);
+			logger('Unknown gravity for verb: ' . $item['verb'], LOGGER_DEBUG);
 		}
 
 		$uid = intval($item['uid']);
@@ -1314,6 +1321,7 @@ class Item extends BaseObject
 		$item['visible']       = ((x($item, 'visible') !== false) ? intval($item['visible'])         : 1);
 		$item['deleted']       = 0;
 		$item['parent-uri']    = trim(defaults($item, 'parent-uri', $item['uri']));
+		$item['post-type']     = defaults($item, 'post-type', self::PT_ARTICLE);
 		$item['verb']          = trim(defaults($item, 'verb', ''));
 		$item['object-type']   = trim(defaults($item, 'object-type', ''));
 		$item['object']        = trim(defaults($item, 'object', ''));
@@ -1325,7 +1333,6 @@ class Item extends BaseObject
 		$item['deny_cid']      = trim(defaults($item, 'deny_cid', ''));
 		$item['deny_gid']      = trim(defaults($item, 'deny_gid', ''));
 		$item['private']       = intval(defaults($item, 'private', 0));
-		$item['bookmark']      = intval(defaults($item, 'bookmark', 0));
 		$item['body']          = trim(defaults($item, 'body', ''));
 		$item['tag']           = trim(defaults($item, 'tag', ''));
 		$item['attach']        = trim(defaults($item, 'attach', ''));
@@ -1610,6 +1617,10 @@ class Item extends BaseObject
 			$files = '';
 		}
 
+		// Creates the permission set
+		// Currently we only store the data but don't using it
+		$item['psid'] = PermissionSet::fetchIDForPost($item);
+
 		// We are doing this outside of the transaction to avoid timing problems
 		if (!self::insertActivity($item)) {
 			self::insertContent($item);
@@ -1993,12 +2004,6 @@ class Item extends BaseObject
 			$item['contact-id'] = $self['id'];
 		}
 
-		if (in_array($item['type'], ["net-comment", "wall-comment"])) {
-			$item['type'] = 'remote-comment';
-		} elseif ($item['type'] == 'wall') {
-			$item['type'] = 'remote';
-		}
-
 		/// @todo Handling of "event-id"
 
 		$notify = false;
@@ -2073,12 +2078,6 @@ class Item extends BaseObject
 				$item['contact-id'] = $item['author-id'];
 			}
 
-			if (in_array($item['type'], ["net-comment", "wall-comment"])) {
-				$item['type'] = 'remote-comment';
-			} elseif ($item['type'] == 'wall') {
-				$item['type'] = 'remote';
-			}
-
 			$public_shadow = self::insert($item, false, false, true);
 
 			logger("Stored public shadow for thread ".$itemid." under id ".$public_shadow, LOGGER_DEBUG);
@@ -2134,12 +2133,6 @@ class Item extends BaseObject
 		unset($item['starred']);
 		$item['contact-id'] = Contact::getIdForURL($item['author-link']);
 
-		if (in_array($item['type'], ["net-comment", "wall-comment"])) {
-			$item['type'] = 'remote-comment';
-		} elseif ($item['type'] == 'wall') {
-			$item['type'] = 'remote';
-		}
-
 		$public_shadow = self::insert($item, false, false, true);
 
 		logger("Stored public shadow for comment ".$item['uri']." under id ".$public_shadow, LOGGER_DEBUG);
@@ -2972,7 +2965,6 @@ class Item extends BaseObject
 			'uri'           => self::newURI($item['uid']),
 			'uid'           => $item['uid'],
 			'contact-id'    => $item_contact_id,
-			'type'          => 'activity',
 			'wall'          => $item['wall'],
 			'origin'        => 1,
 			'network'       => NETWORK_DFRN,
@@ -3015,7 +3007,7 @@ class Item extends BaseObject
 	private static function addThread($itemid, $onlyshadow = false)
 	{
 		$fields = ['uid', 'created', 'edited', 'commented', 'received', 'changed', 'wall', 'private', 'pubmail',
-			'moderated', 'visible', 'starred', 'bookmark', 'contact-id',
+			'moderated', 'visible', 'starred', 'contact-id', 'post-type',
 			'deleted', 'origin', 'forum_mode', 'mention', 'network', 'author-id', 'owner-id'];
 		$condition = ["`id` = ? AND (`parent` = ? OR `parent` = 0)", $itemid, $itemid];
 		$item = self::selectFirst($fields, $condition);
@@ -3035,8 +3027,8 @@ class Item extends BaseObject
 
 	private static function updateThread($itemid, $setmention = false)
 	{
-		$fields = ['uid', 'guid', 'created', 'edited', 'commented', 'received', 'changed',
-			'wall', 'private', 'pubmail', 'moderated', 'visible', 'starred', 'bookmark', 'contact-id',
+		$fields = ['uid', 'guid', 'created', 'edited', 'commented', 'received', 'changed', 'post-type',
+			'wall', 'private', 'pubmail', 'moderated', 'visible', 'starred', 'contact-id',
 			'deleted', 'origin', 'forum_mode', 'network', 'author-id', 'owner-id'];
 		$condition = ["`id` = ? AND (`parent` = ? OR `parent` = 0)", $itemid, $itemid];
 
diff --git a/src/Model/PermissionSet.php b/src/Model/PermissionSet.php
new file mode 100644
index 0000000000..a5d5ed2b85
--- /dev/null
+++ b/src/Model/PermissionSet.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * @file src/Model/PermissionSet.php
+ */
+namespace Friendica\Model;
+
+use Friendica\BaseObject;
+use Friendica\Database\DBM;
+use dba;
+
+require_once 'include/dba.php';
+
+/**
+ * @brief functions for interacting with the permission set of an object (item, photo, event, ...)
+ */
+class PermissionSet extends BaseObject
+{
+	/**
+	 * Fetch the id of a given permission set. Generate a new one when needed
+	 *
+	 * @param array $postarray The array from an item, picture or event post
+	 * @return id
+	 */
+	public static function fetchIDForPost($postarray)
+	{
+		$condition = ['uid' => $postarray['uid'],
+			'allow_cid' => self::sortPermissions($postarray['allow_cid']),
+			'allow_gid' => self::sortPermissions($postarray['allow_gid']),
+			'deny_cid' => self::sortPermissions($postarray['deny_cid']),
+			'deny_gid' => self::sortPermissions($postarray['deny_gid'])];
+
+		$set = dba::selectFirst('permissionset', ['id'], $condition);
+
+		if (!DBM::is_result($set)) {
+			dba::insert('permissionset', $condition, true);
+
+			$set = dba::selectFirst('permissionset', ['id'], $condition);
+		}
+		return $set['id'];
+	}
+
+	private static function sortPermissions($permissionlist)
+	{
+		$cleaned_list = trim($permissionlist, '<>');
+
+		if (empty($cleaned_list)) {
+			return $permissionlist;
+		}
+
+		$elements = explode('><', $cleaned_list);
+
+		if (count($elements) <= 1) {
+			return $permissionlist;
+		}
+
+		asort($elements);
+
+		return '<' . implode('><', $elements) . '>';
+	}
+}
diff --git a/src/Object/Post.php b/src/Object/Post.php
index f9da142fec..8b05abc566 100644
--- a/src/Object/Post.php
+++ b/src/Object/Post.php
@@ -780,7 +780,7 @@ class Post extends BaseObject
 				'$return_path' => $a->query_string,
 				'$threaded'    => $this->isThreaded(),
 				'$jsreload'    => '',
-				'$type'        => $conv->getMode() === 'profile' ? 'wall-comment' : 'net-comment',
+				'$wall'        => ($conv->getMode() === 'profile'),
 				'$id'          => $this->getId(),
 				'$parent'      => $this->getId(),
 				'$qcomment'    => $qcomment,
diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php
index 79fa000f17..8cc148ff94 100644
--- a/src/Protocol/DFRN.php
+++ b/src/Protocol/DFRN.php
@@ -1017,7 +1017,7 @@ class DFRN
 			XML::addElement($doc, $entry, "dfrn:extid", $item['extid']);
 		}
 
-		if ($item['bookmark']) {
+		if ($item['post-type'] == Item::PT_PAGE) {
 			XML::addElement($doc, $entry, "dfrn:bookmark", "true");
 		}
 
@@ -2308,7 +2308,6 @@ class DFRN
 				|| ($item["verb"] == ACTIVITY_ATTENDMAYBE)
 			) {
 				$is_like = true;
-				$item["type"] = "activity";
 				$item["gravity"] = GRAVITY_ACTIVITY;
 				// only one like or dislike per person
 				// splitted into two queries for performance issues
@@ -2489,7 +2488,7 @@ class DFRN
 		$item["extid"] = XML::getFirstNodeValue($xpath, "dfrn:extid/text()", $entry);
 
 		if (XML::getFirstNodeValue($xpath, "dfrn:bookmark/text()", $entry) == "true") {
-			$item["bookmark"] = true;
+			$item["post-type"] = Item::PT_PAGE;
 		}
 
 		$notice_info = $xpath->query("statusnet:notice_info", $entry);
@@ -2621,7 +2620,6 @@ class DFRN
 		}
 
 		if ($entrytype == DFRN::REPLY_RC) {
-			$item["type"] = "remote-comment";
 			$item["wall"] = 1;
 		} elseif ($entrytype == DFRN::TOP_LEVEL) {
 			if (!isset($item["object-type"])) {
@@ -2829,7 +2827,6 @@ class DFRN
 		$header = [];
 		$header["uid"] = $importer["importer_uid"];
 		$header["network"] = NETWORK_DFRN;
-		$header["type"] = "remote";
 		$header["wall"] = 0;
 		$header["origin"] = 0;
 		$header["contact-id"] = $importer["id"];
diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php
index 181423a257..6b6e75cda4 100644
--- a/src/Protocol/Diaspora.php
+++ b/src/Protocol/Diaspora.php
@@ -1709,7 +1709,6 @@ class Diaspora
 		$datarray["guid"] = $guid;
 		$datarray["uri"] = self::getUriFromGuid($author, $guid);
 
-		$datarray["type"] = "remote-comment";
 		$datarray["verb"] = ACTIVITY_POST;
 		$datarray["gravity"] = GRAVITY_COMMENT;
 
@@ -1998,7 +1997,6 @@ class Diaspora
 		$datarray["guid"] = $guid;
 		$datarray["uri"] = self::getUriFromGuid($author, $guid);
 
-		$datarray["type"] = "activity";
 		$datarray["verb"] = $verb;
 		$datarray["gravity"] = GRAVITY_ACTIVITY;
 		$datarray["parent-uri"] = $parent_item["uri"];
diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php
index a68a2bd67e..d989b99622 100644
--- a/src/Protocol/Feed.php
+++ b/src/Protocol/Feed.php
@@ -190,7 +190,6 @@ class Feed {
 		$header = [];
 		$header["uid"] = $importer["uid"];
 		$header["network"] = NETWORK_FEED;
-		$header["type"] = "remote";
 		$header["wall"] = 0;
 		$header["origin"] = 0;
 		$header["gravity"] = GRAVITY_PARENT;
diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php
index f4b299761d..f0f4bed01a 100644
--- a/src/Protocol/OStatus.php
+++ b/src/Protocol/OStatus.php
@@ -345,7 +345,6 @@ class OStatus
 		$header = [];
 		$header["uid"] = $importer["uid"];
 		$header["network"] = NETWORK_OSTATUS;
-		$header["type"] = "remote-comment";
 		$header["wall"] = 0;
 		$header["origin"] = 0;
 		$header["gravity"] = GRAVITY_COMMENT;
@@ -457,7 +456,6 @@ class OStatus
 				$orig_uri = $xpath->query("activity:object/atom:id", $entry)->item(0)->nodeValue;
 				logger("Favorite ".$orig_uri." ".print_r($item, true));
 
-				$item["type"] = "activity";
 				$item["verb"] = ACTIVITY_LIKE;
 				$item["parent-uri"] = $orig_uri;
 				$item["gravity"] = GRAVITY_ACTIVITY;
@@ -696,7 +694,6 @@ class OStatus
 		} else {
 			$item["parent-uri"] = $item["uri"];
 			$item["gravity"] = GRAVITY_PARENT;
-			$item["type"] = "remote";
 		}
 
 		if (($item['author-link'] != '') && !empty($item['protocol'])) {
diff --git a/src/Worker/Expire.php b/src/Worker/Expire.php
index 685fad49e8..a4342722d5 100644
--- a/src/Worker/Expire.php
+++ b/src/Worker/Expire.php
@@ -29,7 +29,7 @@ class Expire
 			logger('Delete expired items', LOGGER_DEBUG);
 			// physically remove anything that has been deleted for more than two months
 			$condition = ["`deleted` AND `changed` < UTC_TIMESTAMP() - INTERVAL 60 DAY"];
-			$rows = dba::select('item', ['id', 'iaid', 'icid'],  $condition);
+			$rows = dba::select('item', ['id', 'iaid', 'icid', 'psid'],  $condition);
 			while ($row = dba::fetch($rows)) {
 				dba::delete('item', ['id' => $row['id']]);
 				if (!empty($row['iaid']) && !dba::exists('item', ['iaid' => $row['iaid']])) {
@@ -38,6 +38,11 @@ class Expire
 				if (!empty($row['icid']) && !dba::exists('item', ['icid' => $row['icid']])) {
 					dba::delete('item-content', ['id' => $row['icid']]);
 				}
+				// When the permission set will be used in photo and events as well.
+				// this query here needs to be extended.
+				if (!empty($row['psid']) && !dba::exists('item', ['psid' => $row['psid']])) {
+					dba::delete('permissionset', ['id' => $row['psid']]);
+				}
 			}
 			dba::close($rows);
 
diff --git a/update.php b/update.php
index c39212152f..ca427186d4 100644
--- a/update.php
+++ b/update.php
@@ -85,7 +85,6 @@ function update_1189() {
 }
 
 function update_1191() {
-
 	Config::set('system', 'maintenance', 1);
 
 	if (Addon::isEnabled('forumlist')) {
@@ -143,7 +142,6 @@ function update_1191() {
 	Config::set('system', 'maintenance', 0);
 
 	return UPDATE_SUCCESS;
-
 }
 
 function update_1203() {
@@ -233,3 +231,15 @@ function update_1261() {
 	dba::update('contact', ['blocked' => false, 'pending' => false], ['uid' => 0, 'blocked' => true, 'pending' => true]);
 	return UPDATE_SUCCESS;
 }
+
+function update_1278() {
+	Config::set('system', 'maintenance', 1);
+	Config::set('system', 'maintenance_reason', L10n::t('%s: Updating post-type.', DBM::date().' '.date('e')));
+
+	Item::update(['post-type' => Item::PT_PAGE], ['bookmark' => true]);
+	Item::update(['post-type' => Item::PT_PERSONAL_NOTE], ['type' => 'note']);
+
+	Config::set('system', 'maintenance', 0);
+
+	return UPDATE_SUCCESS;
+}
diff --git a/view/templates/jot.tpl b/view/templates/jot.tpl
index e4692a8bba..ca6d506ac6 100644
--- a/view/templates/jot.tpl
+++ b/view/templates/jot.tpl
@@ -1,5 +1,3 @@
-
-
 <div id="profile-jot-wrapper" >
 	<div id="profile-jot-banner-wrapper">
 		<div id="profile-jot-desc" >&nbsp;</div>
@@ -8,7 +6,8 @@
 	<div id="profile-jot-banner-end"></div>
 
 	<form id="profile-jot-form" action="{{$action}}" method="post" >
-		<input type="hidden" name="type" value="{{$ptyp}}" />
+		<input type="hidden" name="wall" value="{{$wall}}" />
+		<input type="hidden" name="post_type" value="{{$posttype}}" />
 		<input type="hidden" name="profile_uid" value="{{$profile_uid}}" />
 		<input type="hidden" name="return" value="{{$return_path|escape:'html'}}" />
 		<input type="hidden" name="location" id="jot-location" value="{{$defloc|escape:'html'}}" />
@@ -65,7 +64,7 @@
 
 
 	<div id="profile-jot-plugin-wrapper">
-  	{{$jotplugins}}
+	{{$jotplugins}}
 	</div>
 
 	<div id="profile-rotator-wrapper" style="display: {{$visitor}};" >
diff --git a/view/theme/frio/templates/jot.tpl b/view/theme/frio/templates/jot.tpl
index e1ef7110f4..260d4c18e4 100644
--- a/view/theme/frio/templates/jot.tpl
+++ b/view/theme/frio/templates/jot.tpl
@@ -1,4 +1,3 @@
-
 {{* The button to open the jot - in This theme we move the button with js to the second nav bar *}}
 <button class="btn btn-sm btn-main pull-right" id="jotOpen" aria-label="{{$new_post}}" title="{{$new_post}}" onclick="jotShow();"><i class="fa fa-pencil-square-o fa-2x"></i></button>
 
@@ -70,7 +69,8 @@
 					<div id="profile-jot-banner-end"></div>
 
 					{{* The hidden input fields which submit important values with the post *}}
-					<input type="hidden" name="type" value="{{$ptyp}}" />
+					<input type="hidden" name="jot" value="{{$jot}}" />
+					<input type="hidden" name="post_type" value="{{$posttype}}" />
 					<input type="hidden" name="profile_uid" value="{{$profile_uid}}" />
 					<input type="hidden" name="return" value="{{$return_path}}" />
 					<input type="hidden" name="location" id="jot-location" value="{{$defloc}}" />
diff --git a/view/theme/quattro/templates/jot.tpl b/view/theme/quattro/templates/jot.tpl
index 97fb0c24ff..48c084ca0a 100644
--- a/view/theme/quattro/templates/jot.tpl
+++ b/view/theme/quattro/templates/jot.tpl
@@ -9,7 +9,8 @@
 
 
 
-		<input type="hidden" name="type" value="{{$ptyp}}" />
+		<input type="hidden" name="wall" value="{{$wall}}" />
+		<input type="hidden" name="post_type" value="{{$posttype}}" />
 		<input type="hidden" name="profile_uid" value="{{$profile_uid}}" />
 		<input type="hidden" name="return" value="{{$return_path}}" />
 		<input type="hidden" name="location" id="jot-location" value="{{$defloc}}" />
diff --git a/view/theme/smoothly/templates/jot.tpl b/view/theme/smoothly/templates/jot.tpl
index 26578dafce..34c0b1a2bb 100644
--- a/view/theme/smoothly/templates/jot.tpl
+++ b/view/theme/smoothly/templates/jot.tpl
@@ -1,5 +1,3 @@
-
-
 <div id="profile-jot-wrapper" >
 	<div id="profile-jot-banner-wrapper">
 		<div id="profile-jot-desc" >&nbsp;</div>
@@ -8,7 +6,8 @@
 	<div id="profile-jot-banner-end"></div>
 
 	<form id="profile-jot-form" action="{{$action}}" method="post" >
-		<input type="hidden" name="type" value="{{$ptyp}}" />
+		<input type="hidden" name="wall" value="{{$wall}}" />
+		<input type="hidden" name="post_type" value="{{$posttype}}" />
 		<input type="hidden" name="profile_uid" value="{{$profile_uid}}" />
 		<input type="hidden" name="return" value="{{$return_path}}" />
 		<input type="hidden" name="location" id="jot-location" value="{{$defloc}}" />
@@ -25,8 +24,8 @@
 		</div>
 		{{/if}}
 		<div id="jot-text-wrap">
-                	<img id="profile-jot-text-loading" src="images/rotator.gif" alt="{{$wait}}" title="{{$wait}}" style="display: none;" /><br>
-                	<textarea rows="5" cols="80" class="profile-jot-text" id="profile-jot-text" name="body" placeholder="{{$share}}">
+			<img id="profile-jot-text-loading" src="images/rotator.gif" alt="{{$wait}}" title="{{$wait}}" style="display: none;" /><br>
+			<textarea rows="5" cols="80" class="profile-jot-text" id="profile-jot-text" name="body" placeholder="{{$share}}">
 			{{if $content}}{{$content}}{{/if}}
 			</textarea>
 		</div>
@@ -62,7 +61,7 @@
 	</div>
 
 	<div id="profile-jot-plugin-wrapper" style="display: none;">
-  	{{$jotplugins}}
+	{{$jotplugins}}
 	</div>
 	<div id="profile-jot-tools-end"></div>