PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 2.2.0
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v2.2.0
2.2.0 2.1.0 2.0.15 2.0.12 2.0.10 2.0.4 2.0.1 2.0.0 1.95.3 1.95.2 1.95 1.91.6 trunk 1.11 1.12 1.13 1.20 1.21 1.22 1.23 1.30 1.31 1.32 1.35 1.40 All 43 releases
← All changes | app/Models/Board.php +165 -21 1.20 → 2.2.0 View file →
@@ -1,15 +1,13 @@
1 1 <?php
2 2
3 3 namespace FluentBoards\App\Models;
4 4
5 -use FluentBoards\App\Services\BoardService;
6 5 use FluentBoards\App\Services\Constant;
7 6 use FluentBoards\App\Services\PermissionManager;
8 7 use FluentBoards\App\Services\UserService;
9 8 use FluentBoards\Framework\Database\Orm\Builder;
10 -use FluentBoards\Framework\Support\Arr;
11 -use FluentBoardsPro\App\Models\CustomField;
9 +use FluentBoards\App\Models\CustomField;
12 10
13 11 class Board extends Model
14 12 {
15 13 protected $table = 'fbs_boards';
@@ -18,8 +16,10 @@
18 16
19 17 protected $hidden = [
20 18 'created_at',
21 19 'updated_at',
20 + 'boardMeta',
21 + 'viewerMembership',
22 22 ];
23 23
24 24 protected $fillable = [
25 25 'parent_id',
@@ -32,20 +32,24 @@
32 32 'created_by',
33 33 'archived_at',
34 34 ];
35 35
36 + protected $appends = ['meta', 'isUserOnlyViewer'];
37 +
38 + /**
39 + * Boot board defaults while preserving empty backgrounds for newly created boards.
40 + */
36 41 public static function boot()
37 42 {
38 43 static::creating(function ($model) {
39 44 $model->created_by = $model->created_by ?: get_current_user_id();
40 45 $model->type = $model->type ?: 'to-do'; // default board type is to-do
41 - $model->background = $model->background ?: $model->randomBackground();
46 + $model->background = $model->background ?: '';
42 47 });
43 48 /* global scope for board type which means only type = to-do will be fetched from everywhere */
44 49 parent::boot();
45 50 static::addGlobalScope('type', function (Builder $builder) {
46 - $builder = $builder->whereNull('archived_at');
47 - $builder->where('type', '=', 'to-do')
51 + $builder = $builder->where('type', '=', 'to-do')
48 52 ->orWhere('type', '=', 'roadmap');
49 53 });
50 54 }
51 55
@@ -77,8 +81,36 @@
77 81 {
78 82 return \maybe_unserialize($settings);
79 83 }
80 84
85 + public function getMetaAttribute()
86 + {
87 + if (!$this->relationLoaded('boardMeta')) {
88 + return $this->getMeta();
89 + }
90 +
91 + $meta = [];
92 + foreach ($this->getRelation('boardMeta') as $item) {
93 + $meta[$item->key] = $item->value;
94 + }
95 + return $meta;
96 + }
97 +
98 + /** Internal eager-loaded metadata for board-list serialization. */
99 + public function boardMeta()
100 + {
101 + return $this->hasMany(Meta::class, 'object_id')
102 + ->where('object_type', Constant::OBJECT_TYPE_BOARD);
103 + }
104 +
105 + /** Internal membership snapshot for the current board-list reader. */
106 + public function viewerMembership()
107 + {
108 + return $this->hasOne(Relation::class, 'object_id')
109 + ->where('object_type', Constant::OBJECT_TYPE_BOARD_USER)
110 + ->where('foreign_id', get_current_user_id());
111 + }
112 +
81 113 public function setBackgroundAttribute($background)
82 114 {
83 115 $this->attributes['background'] = \maybe_serialize($background);
84 116 }
@@ -100,13 +132,8 @@
100 132 ->where('parent_id', null)
101 133 ->where('status', 'closed');
102 134 }
103 135
104 - public function boardTerm()
105 - {
106 - return $this->hasMany(BoardTerm::class, 'board_id');
107 - }
108 -
109 136 public function stages()
110 137 {
111 138 return $this->hasMany(Stage::class, 'board_id')
112 139 ->whereNull('archived_at')
@@ -126,9 +153,9 @@
126 153 User::class,
127 154 'fbs_relations',
128 155 'object_id',
129 156 'foreign_id'
130 - )->withPivot('settings')
157 + )->withPivot('settings','preferences')
131 158 ->wherePivot('object_type', Constant::OBJECT_TYPE_BOARD_USER)
132 159 ->withTimestamps();
133 160 }
134 161
@@ -217,21 +244,49 @@
217 244 }
218 245
219 246 return $query->whereIn('id', $boardIds);
220 247 }
221 - private function randomBackground()
248 +
249 + /**
250 + * Exclude template boards (settings['is_template'] === true).
251 + * The settings column is serialized text, so both the PHP-serialized
252 + * and JSON representations of the flag are matched.
253 + */
254 + public function scopeExcludeTemplates($query)
222 255 {
223 - $solids = Constant::BOARD_BACKGROUND_DEFAULT_SOLID_COLORS;
224 - $solid = $solids[wp_rand(0, count($solids) - 1)];
256 + return $query->where(function ($query) {
257 + $query->whereNull('settings')
258 + ->orWhere(function ($subQuery) {
259 + $subQuery->where('settings', 'NOT LIKE', '%"is_template";b:1%')
260 + ->where('settings', 'NOT LIKE', '%"is_template":true%');
261 + });
262 + });
263 + }
225 264
226 - return [
227 - 'id' => $solid['id'],
228 - 'is_image' => false,
229 - 'image_url' => null,
230 - 'color' => $solid['value']
231 - ];
265 + /**
266 + * Limit boards to types supported by the currently loaded plugins.
267 + */
268 + public function scopeAvailableInCurrentInstall($query)
269 + {
270 + if (!defined('FLUENT_ROADMAP')) {
271 + return $query->where('type', 'to-do');
272 + }
273 +
274 + return $query;
232 275 }
233 276
277 + /**
278 + * Only template boards (inverse of scopeExcludeTemplates).
279 + */
280 + public function scopeOnlyTemplates($query)
281 + {
282 + return $query->whereNotNull('settings')
283 + ->where(function ($subQuery) {
284 + $subQuery->where('settings', 'LIKE', '%"is_template";b:1%')
285 + ->orWhere('settings', 'LIKE', '%"is_template":true%');
286 + });
287 + }
288 +
234 289 public function getUsers()
235 290 {
236 291 return (new UserService())->allFluentBoardsUsers($this->id);
237 292 }
@@ -240,7 +295,96 @@
240 295 {
241 296 return $this->hasMany(CustomField::class, 'board_id')
242 297 ->whereNull('archived_at')
243 298 ->orderBy('position', 'asc');
299 + }
300 +
301 + public function getMeta() // get Board Meta only
302 + {
303 + $meta = Meta::where('object_id', $this->id)
304 + ->where('object_type', Constant::OBJECT_TYPE_BOARD)
305 + ->get();
306 +
307 + $formattedMeta = [];
308 +
309 + foreach ($meta as $m) {
310 + $formattedMeta[$m->key] = $m->value;
311 + }
312 +
313 + return $formattedMeta;
314 + }
315 +
316 +
317 +
318 + public function getMetaByKey($key) // get Board Meta only
319 + {
320 + $meta = Meta::where('object_id', $this->id)
321 + ->where('object_type', Constant::OBJECT_TYPE_BOARD)
322 + ->where('key', $key)
323 + ->first();
324 +
325 + return $meta->value ?? null;
326 + }
327 +
328 + public function updateMeta($key, $value)
329 + {
330 + $this->unsetRelation('boardMeta');
331 + $meta = Meta::where('object_id', $this->id)
332 + ->where('object_type', Constant::OBJECT_TYPE_BOARD)
333 + ->where('key', $key)
334 + ->first();
335 +
336 + if ($meta) {
337 + $meta->value = $value;
338 + $meta->save();
339 + } else {
340 + $meta = Meta::create([
341 + 'object_id' => $this->id,
342 + 'object_type' => Constant::OBJECT_TYPE_BOARD,
343 + 'key' => $key,
344 + 'value' => $value,
345 + ]);
346 + }
347 +
348 + return $meta;
349 +
350 + }
351 +
352 +
353 + public function activities()
354 + {
355 + return $this->hasMany(Activity::class, 'object_id')
356 + ->where('object_type', Constant::ACTIVITY_BOARD);
357 + }
358 +
359 + public function getisUserOnlyViewerAttribute()
360 + {
361 + $userId = get_current_user_id();
362 + if(PermissionManager::isAdmin()) {
363 + return false;
364 + }
365 + $boardPermissions = $this->relationLoaded('viewerMembership') ? $this->getRelation('viewerMembership') : null;
366 + // Never reuse another user's eagerly loaded membership.
367 + if (!$boardPermissions || (int) $boardPermissions->foreign_id !== (int) $userId) {
368 + $boardPermissions = Relation::where('object_id', $this->id)
369 + ->where('foreign_id', $userId)
370 + ->where('object_type', Constant::OBJECT_TYPE_BOARD_USER)
371 + ->first();
372 + }
373 +
374 + return $boardPermissions->settings['is_viewer_only'] ?? false;
375 + }
376 +
377 + public function removeBoardFromFolder()
378 + {
379 + $relation = Relation::where('object_type', Constant::OBJECT_TYPE_FOLDER_BOARD)
380 + ->where('foreign_id', $this->id)
381 + ->first();
382 +
383 + if (!$relation) {
384 + return;
385 + }
386 + $relation->delete();
387 +
244 388 }
245 389
246 390 }