| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  | <?php namespace BookStack\Repos; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | use BookStack\Book; | 
					
						
							|  |  |  | use BookStack\Chapter; | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  | use BookStack\Entity; | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  | use BookStack\Page; | 
					
						
							| 
									
										
										
										
											2016-05-02 04:20:50 +08:00
										 |  |  | use BookStack\Services\PermissionService; | 
					
						
							| 
									
										
										
										
											2016-03-13 20:04:08 +08:00
										 |  |  | use BookStack\User; | 
					
						
							| 
									
										
										
										
											2016-08-27 03:20:58 +08:00
										 |  |  | use Illuminate\Support\Collection; | 
					
						
							| 
									
										
										
										
											2016-05-15 20:41:18 +08:00
										 |  |  | use Illuminate\Support\Facades\Log; | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class EntityRepo | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @var Book $book | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  |     public $book; | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @var Chapter | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  |     public $chapter; | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @var Page | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  |     public $page; | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2016-05-02 04:20:50 +08:00
										 |  |  |      * @var PermissionService | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-05-02 04:20:50 +08:00
										 |  |  |     protected $permissionService; | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-15 20:41:18 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Acceptable operators to be used in a query | 
					
						
							|  |  |  |      * @var array | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected $queryOperators = ['<=', '>=', '=', '<', '>', 'like', '!=']; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * EntityService constructor. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  |     public function __construct() | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  |         $this->book = app(Book::class); | 
					
						
							|  |  |  |         $this->chapter = app(Chapter::class); | 
					
						
							|  |  |  |         $this->page = app(Page::class); | 
					
						
							| 
									
										
										
										
											2016-05-02 04:20:50 +08:00
										 |  |  |         $this->permissionService = app(PermissionService::class); | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get the latest books added to the system. | 
					
						
							| 
									
										
										
										
											2016-03-06 21:17:46 +08:00
										 |  |  |      * @param int $count | 
					
						
							|  |  |  |      * @param int $page | 
					
						
							|  |  |  |      * @param bool $additionalQuery | 
					
						
							|  |  |  |      * @return | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-03-06 21:17:46 +08:00
										 |  |  |     public function getRecentlyCreatedBooks($count = 20, $page = 0, $additionalQuery = false) | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-05-02 04:20:50 +08:00
										 |  |  |         $query = $this->permissionService->enforceBookRestrictions($this->book) | 
					
						
							| 
									
										
										
										
											2016-03-06 21:17:46 +08:00
										 |  |  |             ->orderBy('created_at', 'desc'); | 
					
						
							|  |  |  |         if ($additionalQuery !== false && is_callable($additionalQuery)) { | 
					
						
							|  |  |  |             $additionalQuery($query); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return $query->skip($page * $count)->take($count)->get(); | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get the most recently updated books. | 
					
						
							|  |  |  |      * @param $count | 
					
						
							|  |  |  |      * @param int $page | 
					
						
							|  |  |  |      * @return mixed | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getRecentlyUpdatedBooks($count = 20, $page = 0) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-05-02 04:20:50 +08:00
										 |  |  |         return $this->permissionService->enforceBookRestrictions($this->book) | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  |             ->orderBy('updated_at', 'desc')->skip($page * $count)->take($count)->get(); | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get the latest pages added to the system. | 
					
						
							| 
									
										
										
										
											2016-03-06 21:17:46 +08:00
										 |  |  |      * @param int $count | 
					
						
							|  |  |  |      * @param int $page | 
					
						
							|  |  |  |      * @param bool $additionalQuery | 
					
						
							|  |  |  |      * @return | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-03-06 21:17:46 +08:00
										 |  |  |     public function getRecentlyCreatedPages($count = 20, $page = 0, $additionalQuery = false) | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-05-02 04:20:50 +08:00
										 |  |  |         $query = $this->permissionService->enforcePageRestrictions($this->page) | 
					
						
							| 
									
										
										
										
											2016-03-13 20:04:08 +08:00
										 |  |  |             ->orderBy('created_at', 'desc')->where('draft', '=', false); | 
					
						
							| 
									
										
										
										
											2016-03-06 21:17:46 +08:00
										 |  |  |         if ($additionalQuery !== false && is_callable($additionalQuery)) { | 
					
						
							|  |  |  |             $additionalQuery($query); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-04-09 21:26:42 +08:00
										 |  |  |         return $query->with('book')->skip($page * $count)->take($count)->get(); | 
					
						
							| 
									
										
										
										
											2016-03-06 21:17:46 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get the latest chapters added to the system. | 
					
						
							|  |  |  |      * @param int $count | 
					
						
							|  |  |  |      * @param int $page | 
					
						
							|  |  |  |      * @param bool $additionalQuery | 
					
						
							|  |  |  |      * @return | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getRecentlyCreatedChapters($count = 20, $page = 0, $additionalQuery = false) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-05-02 04:20:50 +08:00
										 |  |  |         $query = $this->permissionService->enforceChapterRestrictions($this->chapter) | 
					
						
							| 
									
										
										
										
											2016-03-06 21:17:46 +08:00
										 |  |  |             ->orderBy('created_at', 'desc'); | 
					
						
							|  |  |  |         if ($additionalQuery !== false && is_callable($additionalQuery)) { | 
					
						
							|  |  |  |             $additionalQuery($query); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return $query->skip($page * $count)->take($count)->get(); | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get the most recently updated pages. | 
					
						
							|  |  |  |      * @param $count | 
					
						
							|  |  |  |      * @param int $page | 
					
						
							|  |  |  |      * @return mixed | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getRecentlyUpdatedPages($count = 20, $page = 0) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-05-02 04:20:50 +08:00
										 |  |  |         return $this->permissionService->enforcePageRestrictions($this->page) | 
					
						
							| 
									
										
										
										
											2016-03-13 20:04:08 +08:00
										 |  |  |             ->where('draft', '=', false) | 
					
						
							| 
									
										
										
										
											2016-04-09 21:26:42 +08:00
										 |  |  |             ->orderBy('updated_at', 'desc')->with('book')->skip($page * $count)->take($count)->get(); | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-13 20:04:08 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Get draft pages owned by the current user. | 
					
						
							|  |  |  |      * @param int $count | 
					
						
							|  |  |  |      * @param int $page | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getUserDraftPages($count = 20, $page = 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $user = auth()->user(); | 
					
						
							|  |  |  |         return $this->page->where('draft', '=', true) | 
					
						
							|  |  |  |             ->where('created_by', '=', $user->id) | 
					
						
							|  |  |  |             ->orderBy('updated_at', 'desc') | 
					
						
							|  |  |  |             ->skip($count * $page)->take($count)->get(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Updates entity restrictions from a request | 
					
						
							|  |  |  |      * @param $request | 
					
						
							|  |  |  |      * @param Entity $entity | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-05-02 04:20:50 +08:00
										 |  |  |     public function updateEntityPermissionsFromRequest($request, Entity $entity) | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  |     { | 
					
						
							|  |  |  |         $entity->restricted = $request->has('restricted') && $request->get('restricted') === 'true'; | 
					
						
							| 
									
										
										
										
											2016-05-02 04:20:50 +08:00
										 |  |  |         $entity->permissions()->delete(); | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  |         if ($request->has('restrictions')) { | 
					
						
							|  |  |  |             foreach ($request->get('restrictions') as $roleId => $restrictions) { | 
					
						
							|  |  |  |                 foreach ($restrictions as $action => $value) { | 
					
						
							| 
									
										
										
										
											2016-05-02 04:20:50 +08:00
										 |  |  |                     $entity->permissions()->create([ | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  |                         'role_id' => $roleId, | 
					
						
							| 
									
										
										
										
											2016-03-06 21:17:46 +08:00
										 |  |  |                         'action'  => strtolower($action) | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  |                     ]); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         $entity->save(); | 
					
						
							| 
									
										
										
										
											2016-05-02 04:20:50 +08:00
										 |  |  |         $this->permissionService->buildJointPermissionsForEntity($entity); | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Prepare a string of search terms by turning | 
					
						
							|  |  |  |      * it into an array of terms. | 
					
						
							|  |  |  |      * Keeps quoted terms together. | 
					
						
							|  |  |  |      * @param $termString | 
					
						
							|  |  |  |      * @return array | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-08-26 00:17:26 +08:00
										 |  |  |     public function prepareSearchTerms($termString) | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-05-15 20:41:18 +08:00
										 |  |  |         $termString = $this->cleanSearchTermString($termString); | 
					
						
							| 
									
										
										
										
											2016-08-26 00:17:26 +08:00
										 |  |  |         preg_match_all('/(".*?")/', $termString, $matches); | 
					
						
							|  |  |  |         $terms = []; | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  |         if (count($matches[1]) > 0) { | 
					
						
							| 
									
										
										
										
											2016-08-26 00:17:26 +08:00
										 |  |  |             foreach ($matches[1] as $match) { | 
					
						
							|  |  |  |                 $terms[] = $match; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2016-03-06 03:00:26 +08:00
										 |  |  |             $termString = trim(preg_replace('/"(.*?)"/', '', $termString)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!empty($termString)) $terms = array_merge($terms, explode(' ', $termString)); | 
					
						
							|  |  |  |         return $terms; | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-15 20:41:18 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Removes any special search notation that should not | 
					
						
							|  |  |  |      * be used in a full-text search. | 
					
						
							|  |  |  |      * @param $termString | 
					
						
							|  |  |  |      * @return mixed | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function cleanSearchTermString($termString) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Strip tag searches
 | 
					
						
							|  |  |  |         $termString = preg_replace('/\[.*?\]/', '', $termString); | 
					
						
							|  |  |  |         // Reduced multiple spacing into single spacing
 | 
					
						
							|  |  |  |         $termString = preg_replace("/\s{2,}/", " ", $termString); | 
					
						
							|  |  |  |         return $termString; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get the available query operators as a regex escaped list. | 
					
						
							|  |  |  |      * @return mixed | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function getRegexEscapedOperators() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $escapedOperators = []; | 
					
						
							|  |  |  |         foreach ($this->queryOperators as $operator) { | 
					
						
							|  |  |  |             $escapedOperators[] = preg_quote($operator); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return join('|', $escapedOperators); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Parses advanced search notations and adds them to the db query. | 
					
						
							|  |  |  |      * @param $query | 
					
						
							|  |  |  |      * @param $termString | 
					
						
							|  |  |  |      * @return mixed | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function addAdvancedSearchQueries($query, $termString) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $escapedOperators = $this->getRegexEscapedOperators(); | 
					
						
							|  |  |  |         // Look for tag searches
 | 
					
						
							|  |  |  |         preg_match_all("/\[(.*?)((${escapedOperators})(.*?))?\]/", $termString, $tags); | 
					
						
							|  |  |  |         if (count($tags[0]) > 0) { | 
					
						
							|  |  |  |             $this->applyTagSearches($query, $tags); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $query; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Apply extracted tag search terms onto a entity query. | 
					
						
							|  |  |  |      * @param $query | 
					
						
							|  |  |  |      * @param $tags | 
					
						
							|  |  |  |      * @return mixed | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function applyTagSearches($query, $tags) { | 
					
						
							|  |  |  |         $query->where(function($query) use ($tags) { | 
					
						
							|  |  |  |             foreach ($tags[1] as $index => $tagName) { | 
					
						
							|  |  |  |                 $query->whereHas('tags', function($query) use ($tags, $index, $tagName) { | 
					
						
							|  |  |  |                     $tagOperator = $tags[3][$index]; | 
					
						
							|  |  |  |                     $tagValue = $tags[4][$index]; | 
					
						
							|  |  |  |                     if (!empty($tagOperator) && !empty($tagValue) && in_array($tagOperator, $this->queryOperators)) { | 
					
						
							|  |  |  |                         if (is_numeric($tagValue) && $tagOperator !== 'like') { | 
					
						
							|  |  |  |                             // We have to do a raw sql query for this since otherwise PDO will quote the value and MySQL will
 | 
					
						
							|  |  |  |                             // search the value as a string which prevents being able to do number-based operations
 | 
					
						
							|  |  |  |                             // on the tag values. We ensure it has a numeric value and then cast it just to be sure.
 | 
					
						
							|  |  |  |                             $tagValue = (float) trim($query->getConnection()->getPdo()->quote($tagValue), "'"); | 
					
						
							|  |  |  |                             $query->where('name', '=', $tagName)->whereRaw("value ${tagOperator} ${tagValue}"); | 
					
						
							|  |  |  |                         } else { | 
					
						
							|  |  |  |                             $query->where('name', '=', $tagName)->where('value', $tagOperator, $tagValue); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } else { | 
					
						
							|  |  |  |                         $query->where('name', '=', $tagName); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         return $query; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-27 03:20:58 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Alias method to update the book jointPermissions in the PermissionService. | 
					
						
							|  |  |  |      * @param Collection $collection collection on entities | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function buildJointPermissions(Collection $collection) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->permissionService->buildJointPermissionsForEntities($collection); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-15 20:41:18 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-20 20:37:06 +08:00
										 |  |  | 
 |