View difference between Paste ID: QE8uecEi and tcXaJ9bc
SHOW: | | - or go back to the newest paste.
1
<?php
2
3
/**
4
* ownCloud - User Conversations
5
*
6
* @author Simeon Ackermann
7
* @copyright 2014 Simeon Ackermann amseon@web.de
8
* 
9
* This library is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
11
* License as published by the Free Software Foundation; either 
12
* version 3 of the License, or any later version.
13
* 
14
* This library is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
18
*  
19
* You should have received a copy of the GNU Affero General Public 
20
* License along with this library.  If not, see <http://www.gnu.org/licenses/>.
21
* 
22
*/
23
24
class OC_Conversations
25
{
26
27
							// TODO: better arguments! 
28
	public static function getConversation($room=false, $offset=0, $limit=5, $from_id=null, $from_date=null)
29
	{	
30
		$userId = OC_User::getUser();			
31
		$room = ( $room ) ? $room : self::getRoom();
32
		$rtype = explode(":", $room);
33
34
		if ( $rtype[0] == "user" && UC_SINGLE_USER_MSG == true ) {			
35
			// get user rooms: msgs to user X from me OR to me from user X
36
			$and = array( "( ( room = ? AND author = ? ) OR ( room = ? AND author = ? ) )" );
37
			$args = array($room, $userId, 'user:' . $userId, $rtype[1]);
38
		} else {
39
			// for compatibility with UC <= 0.1.6: get room-msgs without "group:" prefix and default room in every room
40
			$and = array( "( room = ? OR room = ? OR room = ? )" );
41
			$args = array($room, $rtype[1], "default"); // rtype[1] and default for compatibilty
42
		} 
43
44
		if ( $from_id ) { // used in submit new comment, to get only the new comment; TODO: could be done with with $limit
45
			$and[] = "id > ?";
46
			$args[] = $from_id;
47
		}
48
49
		if ( $from_date ) { // used in polling, to get only newer posts than a date
50
			$and[] = "date > ?";
51
			$args[] = $from_date;
52
		}
53
54
		$sql = 	"SELECT * FROM *PREFIX*conversations " .
55
				"WHERE " . implode(" AND ", $and) . 
56
				" ORDER BY id DESC";
57
58
		$query = OCP\DB::prepare($sql, $limit, $offset);
59
		$conversation = $query->execute( $args )->fetchAll();
60
61
		if ( ! $offset && ! $from_date ) {
62
			// last id :http://www.php.net/manual/en/pdo.lastinsertid.php
63
			self::setUserRoomTime();
64
		}
65
66
		return $conversation;
67
	}
68
69
	public static function newComment( $comment, $attachment ) // TODO optional $room parameter
70
	{		
71
		$room = self::getRoom();
72
		$userId = OC_User::getUser();
73
74
		if ( USER_CONVERSATIONS_ATTACHMENTS &&  OCP\Share::isEnabled() && ! empty($attachment) ) {
75
			self::shareAttachment($attachment);
76
		}
77
78
		$query = OCP\DB::prepare('INSERT INTO *PREFIX*conversations (room,author,date,text,attachment) VALUES (?,?,?,?,?)');
79
		$query->execute( array(
80
							$room,
81
							$userId,
82
							date( 'Y-m-d H:i:s'),
83
							trim($comment),
84
							$attachment
85
		));	
86
		self::setRoomTime();	
87
		return true;
88
	}
89
90
	public static function deleteComment( $id ) {
91
		if ( ! USER_CONVERSATIONS_CAN_DELETE ) 
92
			return false;
93
94
		$query = OCP\DB::prepare('SELECT author FROM *PREFIX*conversations WHERE id = ?');
95
		$result = $query->execute( array($id) )->fetch();
96
97
		$uid = OC_User::getUser();
98
		if ( $result['author'] == $uid || OC_User::isAdminUser($uid) ) {
99
			$query = OCP\DB::prepare('DELETE FROM *PREFIX*conversations WHERE id = ?');
100
			$query->execute( array( $id ));
101
			return true;
102
		} else {
103
			return false;
104
		}
105
	}
106
107
	public static function getRooms() {
108
		$grooms = array();
109
		$urooms = array();
110
		$userId = OC_User::getUser();
111
		$ordering = array();
112
		// add groups the user contains if more than the user himself is in the room
113
		foreach (OC_Group::getUserGroups($userId) as $group) {
114
			if ( count(OC_Group::usersInGroup($group)) > 1 ) {
115
				$grooms["group:".$group] = array( "type" => "group", "name" => $group );
116
				/*if ( UC_ROOM_ONLY_MSGS ) { // TODO: option: maybe private msgs only to users in same rooms ?					
117
				} */
118
			}
119
		}
120
		// if no group exist create default; NEW in 0.2: no default room!
121
		//if ( empty($grooms) )
122
		//	$grooms["group:default"] = array( "type" => "group", "name" => "default" );
123
124
		// add all other users
125
		if ( UC_SINGLE_USER_MSG == true ) {
126
			foreach (OC_User::getUsers() as $user) {
127
				if ( $userId != $user ) {
128
					$urooms["user:".$user] = array( "type" => "user", "name" => $user );
129
				}
130
			}
131
		}
132
		$rooms = $grooms + $urooms; 
133
		return $rooms;
134
	}	
135
136
	// return active room from user value. If not exists return first room from rooms-list
137
	public static function getRoom()
138
	{		
139
		$room = OCP\Config::getUserValue(OC_User::getUser(), 'conversations', 'activeRoom', false);
140
		if ( $room == false ) {
141
			foreach (self::getRooms() as $key => $value) break; // get the first key of rooms
142
			$room = $key;
143
		}
144
		// TODO: return type and title array $room = array( "type" => "...", "label" => ... );
145
		return $room;
146
	}
147
148
	// write current time to user conf on reading a conversation or after a polling request
149
	public static function setUserRoomTime( $room=false ) {		
150
		$userId = OC_User::getUser();
151
		$room = ( $room ) ? $room : self::getRoom();
152
153
		$conf = OCP\Config::getUserValue( $userId, 'conversations', 'conf', false );
154
		$conf = ( ! $conf ) ? array() : unserialize( $conf );
155
		$conf['rooms'][$room]['rtime'] = time();
156
157
		OCP\Config::setUserValue( $userId, 'conversations', 'conf', serialize($conf));				
158
	}
159
160
	
161
	// write time and new message id on submit new comment 
162
	public static function setRoomTime( $room=false, $lastmsg=false ) {		
163
		$userId = OC_User::getUser();
164
		$room = ( $room ) ? $room : self::getRoom();
165
		$time = time();
166
167
		$rtype = explode(":", $room);
168
		$rtype = $rtype[0];		
169
170
		/*
171
		if ( ! $lastmsg ) {
172
			$query = OCP\DB::prepare("SELECT id FROM *PREFIX*conversations WHERE room = ? ORDER BY id DESC", 1, 0);
173
			$lastmsg = $query->execute( array($room) )->fetch();
174
			$lastmsg = ( !$lastmsg ) ? 0 : $lastmsg['id'];
175
		}		
176
		*/
177
178
		$conf = OCP\Config::getUserValue( $userId, 'conversations', 'conf', false );
179
		$conf = ( ! $conf ) ? array() : unserialize( $conf );
180
		//$conf['rooms'][$room]['lastmsg'] = $lastmsg;
181
		$conf['rooms'][$room]['wtime'] = $time;
182
183
		OCP\Config::setUserValue( $userId, 'conversations', 'conf', serialize($conf));	
184
185
		if ( $rtype == "group" ) {
186
			$gconf = OCP\Config::getAppValue( 'conversations', 'conf', false );
187
			$gconf = ( ! $gconf ) ? array() : unserialize( $gconf );
188
			//$gconf['rooms'][$room]['lastmsg'] = $lastmsg;
189
			$gconf['rooms'][$room]['wtime'] = $time;
190
			OCP\Config::setAppValue( 'conversations', 'conf', serialize($gconf) );
191
		}			
192
	}
193
194
	/*
195
	Test for new messages in all rooms */
196
	public static function updateCheck()
197
	{		
198
		$userId = OC_User::getUser();
199
		$result = array();		
200
201
		$uconf = OCP\Config::getUserValue( $userId, 'conversations', 'conf', false );
202
		$uconf = ( ! $uconf ) ? array() : unserialize( $uconf );
203
204
		foreach (self::getRooms() as $rkey => $room) {
205
			//$rtype = explode(":", $room);
206
			if ( $room['type'] == "group" ) {
207
				$conf = OCP\Config::getAppValue( 'conversations', 'conf', false );
208
				$conf = ( ! $conf ) ? array() : unserialize( $conf );
209
				$wtime = @$conf['rooms'][$rkey]['wtime'];
210
				//$lastmsg = $conf['rooms'][$rkey]['lastmsg'];
211
			} else {
212
				$u2conf = OCP\Config::getUserValue( $room['name'], 'conversations', 'conf', false );
213
				$u2conf = ( ! $u2conf ) ? array() : unserialize( $u2conf );
214
				$wtime = @$u2conf['rooms']['user:'.$userId]['wtime']; // @ if user didnt logged in yet -> key rooms not exist				
215
			}
216
			$urtime = @$uconf['rooms'][$rkey]['rtime'];
217
218
			//$ulastmsg = $uconf['rooms'][$rkey]['lastmsg'];
219
			if ( $wtime > $urtime ) {
220
				// get newer comments than last user room read time
221
				$new_comments = self::getConversation( $rkey, null, null, null, date( 'Y-m-d H:i:s', $urtime) );
222
				$result[$rkey] = array( 'newmsgs' => count($new_comments) );
223
			}
224
		}
225
        return $result;
226
	}
227
228
	/*
229
	Prepare post before display */
230
	public static function preparePost($post) {
231
		$dateTimeObj = new DateTime($post['date']);
232
		return array(
233
			"id"		=> $post['id'],
234
			"avatar"	=> self::getUserAvatar($post['author']),
235
			"author"	=> OC_User::getDisplayName($post['author']),
236
			"date"		=> array(
237
								'ISO8601' => $dateTimeObj->format(DateTime::ISO8601),
238
								'datetime'=>  date( 'Y-m-d H:i\h', strtotime($post['date']) )
239
				),
240
			"text"		=> (empty($post['text'])) ? "" : self::formatComment($post['text']),
241
			"attachment"=> (empty($post['attachment'])) ? "" : self::getAttachment($post['attachment']),
242
			"room"		=> $post['room'],
243
		);
244
	}
245
246
	/* 
247
	format plaintext of a comment */
248
	private static function formatComment($comment) {		
249
		$comment = htmlspecialchars($comment);
250
		$comment = nl2br($comment);	
251
		$comment = preg_replace ( 
252
    		"/(?<!a href=\")(?<!src=\")((http|ftp)+(s)?:\/\/[^<>\s]+)/i",
253
    		"<a href=\"\\0\" target=\"blank\">\\0</a>",
254
    		$comment
255
		);	
256
		return $comment;
257
	}
258
259
	/*
260
	get attachments for printing posts */
261
	private static function getAttachment($attachment) {		
262
		$attachment = json_decode($attachment, true);		
263
		switch ($attachment['type']) {
264
			case 'internal_file':
265
				return self::getInternalFileAttachment($attachment);
266
				break;
267
268
			case 'internal_image':
269
				return self::getInternalFileAttachment($attachment);
270
				break;
271
			
272
			default:
273
				return array();
274
				break;
275
		}
276
	}	
277
278
	/*
279
	Get internal file attachments for printing posts */
280
	private static function getInternalFileAttachment($attachment) {
281
		$path = urldecode($attachment['path']);
282
		$path = substr($path, strpos($path, "/")+1 ); //remove root folder
283
		
284
		if ( $attachment['owner'] == OC_User::getUser() ) {
285
			// file-owner can use own path
286
			$path = \OC\Files\Filesystem::getPath($attachment['fileid']);
287
		} else {			
288
			$item_shared = OCP\Share::getItemSharedWithBySource('file', $attachment['fileid']);			
289
			if ( $item_shared != false ) { // if item is direct shared use shared-file target
290-
				$path = "/Shared" . $item_shared['file_target'];
290+
				$path = "" . $item_shared['file_target'];
291
			} else {
292
				// else search shared parent folder
293-
				$path = "/Shared/" . self::getInheritedSharedPath( $attachment['owner'], urldecode($attachment['path']) );
293+
				$path = "/" . self::getInheritedSharedPath( $attachment['owner'], urldecode($attachment['path']) );
294
			}
295
		}
296
			
297
		$userId = OC_User::getUser();
298
		$view = new \OC\Files\View('/' . $userId . '/files');
299
		$fileinfo = $view->getFileInfo($path);
300
301
		$download_url = OCP\Util::linkToRoute('download', array('file' => $path));		
302
303
		// File not found		
304
		if ( \OC\Files\Filesystem::is_file( $path ) == false ) {
305
			$fileinfo['name'] = "File not found.";
306
			$download_url = "#";
307
		}
308
		
309
		$result = array(
310
			"type" => $attachment['type'],
311
			"mimetype"	=> $fileinfo['mimetype'],
312
			"name"		=> $fileinfo['name'],
313
			"path"		=> $path,
314
			"download_url"	=> $download_url
315
		);
316
		return $result;
317
	}
318
319
	/*
320
	Share item if not already done */
321
	private static function shareAttachment($attachment) {
322
		$attachment = json_decode($attachment, true);
323
		$room = self::getRoom();
324
		$room = explode(":", $room);
325
326
		$item_shared = self::isItemSharedWithGroup( true, 'file', $attachment['owner'], urldecode($attachment['path']) );
327
		if ( ! $item_shared ) {
328
			$share_type = ( $room[0] == "group" ) ? OCP\Share::SHARE_TYPE_GROUP : OCP\Share::SHARE_TYPE_USER;
329
			\OCP\Share::shareItem('file', $attachment['fileid'], $share_type, $room[1], 17);
330
		}
331
	}
332
333
	/*
334
	Test if item is shared with a group */
335
	private static function isItemSharedWithGroup($recursiv, $type, $owner, $path) {	
336
		if ( empty($path) || $path == "files" ) 
337
			return false;
338
		\OC_Util::setupFS($owner);
339
		\OC\Files\Filesystem::initMountPoints($owner);
340
		$view = new \OC\Files\View('/' . $owner . '/files');
341
		$fileinfo = $view->getFileInfo( substr($path, strpos($path, "/") ) ); //get fileinfo from path (remove root folder)
342
		
343
		$share_with = self::getRoom();
344
		$share_with = explode(":", $share_with);
345
346
		$share_type = ( $share_with[0] == "group" ) ? OCP\Share::SHARE_TYPE_GROUP : OCP\Share::SHARE_TYPE_USER;
347
348
		$query = \OC_DB::prepare( 'SELECT `file_target`, `permissions`, `expiration`
349
									FROM `*PREFIX*share`
350
									WHERE `share_type` = ? AND `item_source` = ? AND `item_type` = ? AND `share_with` = ?' );
351
352
		$result = $query->execute( array($share_type, $fileinfo['fileid'], $type, $share_with[1]) )->fetchAll();
353
354
		/*
355
		if ( count($result) == 0 ) { // item not shared, is parent folder shared?
356
			$parent_path = substr($fileinfo['path'], 0, strrpos($fileinfo['path'], "/") );					
357
			return self::isItemSharedWithGroup( 'folder', $owner, $parent_path );
358
		}
359
		return true;
360
		*/
361
		if ( count($result) == 0 ) { // item not shared, is parent folder shared?
362
			if ( $recursiv ) {
363
				$parent_path = substr($fileinfo['path'], 0, strrpos($fileinfo['path'], "/") );					
364
				return self::isItemSharedWithGroup(true, 'folder', $owner, $parent_path );
365
			} else {
366
				return false;
367
			}
368
		}
369
		return true;
370
	}
371
372
	/*
373
	Get shared path for inherited shared item */
374
	private static function getInheritedSharedPath($owner, $path) {
375
		$shared_path = substr($path, strrpos($path, "/")+1 ); // filename
376
		do {
377
			$path = substr($path, 0, strrpos($path, "/") ); // parent path
378
			$shared_path = substr($path, strrpos($path, "/")+1 ) . "/" . $shared_path; // shared path + parent folder
379
			if ( empty($path) || $path == "files" ) break;
380
		} while ( ! self::isItemSharedWithGroup(false, 'folder', $owner, $path) );
381
382
		return $shared_path;
383
	}
384
385
	/*
386
	Get user avatar from OC */
387
	public static $avatars = array();
388
	public static function getUserAvatar( $user )
389
	{
390
		if ( ! array_key_exists($user, self::$avatars) ) {
391
			$avatar = New OC_Avatar($user);
392
			$image = $avatar->get(32);
393
			if ($image instanceof OC_Image) {
394
				$imageUrl = OC_Helper::linkToRoute ( 'core_avatar_get', array ('user' => $user, 'size' => 32) ) . '?requesttoken='. OC::$session->get('requesttoken');
395
				self::$avatars[$user] = $imageUrl;
396
			} else {
397
				self::$avatars[$user] = '';
398
			}
399
		}
400
401
		if ( self::$avatars[$user] != '' )
402
			return self::$avatars[$user];
403
		return '';
404
	}
405
406
	/*
407
	Hook if a user is added or removed from group to change defualt room */
408
	public static function changeUserGroup( $args ) {
409
		$query = OCP\DB::prepare('DELETE FROM *PREFIX*preferences WHERE userid = ? AND appid = "conversations" AND configkey = "activeRoom"');
410
		$query->execute( array( $args['uid'] ));
411
	}
412
}