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 +120 -17 1.23 → 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,22 +32,24 @@
32 32 'created_by',
33 33 'archived_at',
34 34 ];
35 35
36 - protected $appends = ['meta'];
36 + protected $appends = ['meta', 'isUserOnlyViewer'];
37 37
38 + /**
39 + * Boot board defaults while preserving empty backgrounds for newly created boards.
40 + */
38 41 public static function boot()
39 42 {
40 43 static::creating(function ($model) {
41 44 $model->created_by = $model->created_by ?: get_current_user_id();
42 45 $model->type = $model->type ?: 'to-do'; // default board type is to-do
43 - $model->background = $model->background ?: $model->randomBackground();
46 + $model->background = $model->background ?: '';
44 47 });
45 48 /* global scope for board type which means only type = to-do will be fetched from everywhere */
46 49 parent::boot();
47 50 static::addGlobalScope('type', function (Builder $builder) {
48 - $builder = $builder->whereNull('archived_at');
49 - $builder->where('type', '=', 'to-do')
51 + $builder = $builder->where('type', '=', 'to-do')
50 52 ->orWhere('type', '=', 'roadmap');
51 53 });
52 54 }
53 55
@@ -81,11 +83,34 @@
81 83 }
82 84
83 85 public function getMetaAttribute()
84 86 {
85 - return $this->getMeta();
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;
86 96 }
87 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 +
88 113 public function setBackgroundAttribute($background)
89 114 {
90 115 $this->attributes['background'] = \maybe_serialize($background);
91 116 }
@@ -219,21 +244,49 @@
219 244 }
220 245
221 246 return $query->whereIn('id', $boardIds);
222 247 }
223 - 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)
224 255 {
225 - $solids = Constant::BOARD_BACKGROUND_DEFAULT_SOLID_COLORS;
226 - $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 + }
227 264
228 - return [
229 - 'id' => $solid['id'],
230 - 'is_image' => false,
231 - 'image_url' => null,
232 - 'color' => $solid['value']
233 - ];
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;
234 275 }
235 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 +
236 289 public function getUsers()
237 290 {
238 291 return (new UserService())->allFluentBoardsUsers($this->id);
239 292 }
@@ -259,10 +312,23 @@
259 312
260 313 return $formattedMeta;
261 314 }
262 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 +
263 328 public function updateMeta($key, $value)
264 329 {
330 + $this->unsetRelation('boardMeta');
265 331 $meta = Meta::where('object_id', $this->id)
266 332 ->where('object_type', Constant::OBJECT_TYPE_BOARD)
267 333 ->where('key', $key)
268 334 ->first();
@@ -282,6 +348,43 @@
282 348 return $meta;
283 349
284 350 }
285 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 +
388 + }
286 389
287 390 }