]> BookStack Code Mirror - bookstack/blob - app/helpers.php
Started refactor of URL system to better extend Laravel
[bookstack] / app / helpers.php
1 <?php
2
3 use BookStack\Auth\Permissions\PermissionService;
4 use BookStack\Entities\Entity;
5 use BookStack\Ownable;
6
7 /**
8  * Get the path to a versioned file.
9  *
10  * @param  string $file
11  * @return string
12  * @throws Exception
13  */
14 function versioned_asset($file = '')
15 {
16     static $version = null;
17
18     if (is_null($version)) {
19         $versionFile = base_path('version');
20         $version = trim(file_get_contents($versionFile));
21     }
22
23     $additional = '';
24     if (config('app.env') === 'development') {
25         $additional = sha1_file(public_path($file));
26     }
27
28     $path = $file . '?version=' . urlencode($version) . $additional;
29     return baseUrl($path);
30 }
31
32 /**
33  * Helper method to get the current User.
34  * Defaults to public 'Guest' user if not logged in.
35  * @return \BookStack\Auth\User
36  */
37 function user()
38 {
39     return auth()->user() ?: \BookStack\Auth\User::getDefault();
40 }
41
42 /**
43  * Check if current user is a signed in user.
44  * @return bool
45  */
46 function signedInUser() : bool
47 {
48     return auth()->user() && !auth()->user()->isDefault();
49 }
50
51 /**
52  * Check if the current user has general access.
53  * @return bool
54  */
55 function hasAppAccess() : bool
56 {
57     return !auth()->guest() || setting('app-public');
58 }
59
60 /**
61  * Check if the current user has a permission.
62  * If an ownable element is passed in the jointPermissions are checked against
63  * that particular item.
64  * @param string $permission
65  * @param Ownable $ownable
66  * @return mixed
67  */
68 function userCan(string $permission, Ownable $ownable = null)
69 {
70     if ($ownable === null) {
71         return user() && user()->can($permission);
72     }
73
74     // Check permission on ownable item
75     $permissionService = app(PermissionService::class);
76     return $permissionService->checkOwnableUserAccess($ownable, $permission);
77 }
78
79 /**
80  * Check if the current user has the given permission
81  * on any item in the system.
82  * @param string $permission
83  * @param string|null $entityClass
84  * @return bool
85  */
86 function userCanOnAny(string $permission, string $entityClass = null)
87 {
88     $permissionService = app(PermissionService::class);
89     return $permissionService->checkUserHasPermissionOnAnything($permission, $entityClass);
90 }
91
92 /**
93  * Helper to access system settings.
94  * @param $key
95  * @param bool $default
96  * @return bool|string|\BookStack\Settings\SettingService
97  */
98 function setting($key = null, $default = false)
99 {
100     $settingService = resolve(\BookStack\Settings\SettingService::class);
101     if (is_null($key)) {
102         return $settingService;
103     }
104     return $settingService->get($key, $default);
105 }
106
107 /**
108  * Helper to create url's relative to the applications root path.
109  * @param string $path
110  * @param bool $forceAppDomain
111  * @return string
112  */
113 function baseUrl($path, $forceAppDomain = false)
114 {
115     return url($path);
116     $isFullUrl = strpos($path, 'http') === 0;
117     if ($isFullUrl && !$forceAppDomain) {
118         return $path;
119     }
120
121     $path = trim($path, '/');
122     $base = rtrim(config('app.url'), '/');
123
124     // Remove non-specified domain if forced and we have a domain
125     if ($isFullUrl && $forceAppDomain) {
126         if (!empty($base) && strpos($path, $base) === 0) {
127             $path = mb_substr($path, mb_strlen($base));
128         } else {
129             $explodedPath = explode('/', $path);
130             $path = implode('/', array_splice($explodedPath, 3));
131         }
132     }
133
134     // Return normal url path if not specified in config
135     if (config('app.url') === '') {
136         return url($path);
137     }
138
139     return $base . '/' . ltrim($path, '/');
140 }
141
142 /**
143  * Get an instance of the redirector.
144  * Overrides the default laravel redirect helper.
145  * Ensures it redirects even when the app is in a subdirectory.
146  *
147  * @param  string|null  $to
148  * @param  int     $status
149  * @param  array   $headers
150  * @param  bool    $secure
151  * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
152  */
153 function redirect($to = null, $status = 302, $headers = [], $secure = null)
154 {
155     if (is_null($to)) {
156         return app('redirect');
157     }
158
159     $to = baseUrl($to);
160
161     return app('redirect')->to($to, $status, $headers, $secure);
162 }
163
164 /**
165  * Get a path to a theme resource.
166  * @param string $path
167  * @return string|boolean
168  */
169 function theme_path($path = '')
170 {
171     $theme = config('view.theme');
172     if (!$theme) {
173         return false;
174     }
175
176     return base_path('themes/' . $theme .($path ? DIRECTORY_SEPARATOR.$path : $path));
177 }
178
179 /**
180  * Get fetch an SVG icon as a string.
181  * Checks for icons defined within a custom theme before defaulting back
182  * to the 'resources/assets/icons' folder.
183  *
184  * Returns an empty string if icon file not found.
185  * @param $name
186  * @param array $attrs
187  * @return mixed
188  */
189 function icon($name, $attrs = [])
190 {
191     $attrs = array_merge([
192         'class' => 'svg-icon',
193         'data-icon' => $name
194     ], $attrs);
195     $attrString = ' ';
196     foreach ($attrs as $attrName => $attr) {
197         $attrString .=  $attrName . '="' . $attr . '" ';
198     }
199
200     $iconPath = resource_path('assets/icons/' . $name . '.svg');
201     $themeIconPath = theme_path('icons/' . $name . '.svg');
202     if ($themeIconPath && file_exists($themeIconPath)) {
203         $iconPath = $themeIconPath;
204     } else if (!file_exists($iconPath)) {
205         return '';
206     }
207
208     $fileContents = file_get_contents($iconPath);
209     return  str_replace('<svg', '<svg' . $attrString, $fileContents);
210 }
211
212 /**
213  * Generate a url with multiple parameters for sorting purposes.
214  * Works out the logic to set the correct sorting direction
215  * Discards empty parameters and allows overriding.
216  * @param $path
217  * @param array $data
218  * @param array $overrideData
219  * @return string
220  */
221 function sortUrl($path, $data, $overrideData = [])
222 {
223     $queryStringSections = [];
224     $queryData = array_merge($data, $overrideData);
225
226     // Change sorting direction is already sorted on current attribute
227     if (isset($overrideData['sort']) && $overrideData['sort'] === $data['sort']) {
228         $queryData['order'] = ($data['order'] === 'asc') ? 'desc' : 'asc';
229     } else {
230         $queryData['order'] = 'asc';
231     }
232
233     foreach ($queryData as $name => $value) {
234         $trimmedVal = trim($value);
235         if ($trimmedVal === '') {
236             continue;
237         }
238         $queryStringSections[] = urlencode($name) . '=' . urlencode($trimmedVal);
239     }
240
241     if (count($queryStringSections) === 0) {
242         return $path;
243     }
244
245     return baseUrl($path . '?' . implode('&', $queryStringSections));
246 }