cachet icon indicating copy to clipboard operation
cachet copied to clipboard

Component groups sorted by status and order

Open billmn opened this issue 8 years ago • 23 comments

Related to https://github.com/CachetHQ/Cachet/issues/2100

Now groups are ordered by severity status and specified order.

billmn avatar Oct 04 '16 09:10 billmn

How does this affect the component group ordering?

jbrooksuk avatar Oct 04 '16 12:10 jbrooksuk

We should instead define the original relationship to be sorted perhapse rather than doing a client side sort.

GrahamCampbell avatar Oct 04 '16 13:10 GrahamCampbell

The client being the PHP server in this case.

GrahamCampbell avatar Oct 04 '16 13:10 GrahamCampbell

@GrahamCampbell there is no relationship that we originally fetch the groups from. We're ordering the groups, not the components in this PR.

jbrooksuk avatar Oct 04 '16 18:10 jbrooksuk

@GrahamCampbell @jbrooksuk This order must be the same on the API?

billmn avatar Oct 04 '16 18:10 billmn

Yeah, I'd say so. Consistency. Although that said, the API allows for sorting.

jbrooksuk avatar Oct 04 '16 18:10 jbrooksuk

@jbrooksuk @GrahamCampbell

What about this query scope for ComponentGroup model that extract the group severity?

public function scopeWithSeverity(Builder $query)
{
    $subquery = 'SELECT group_id, MAX(status) as severity FROM components GROUP BY group_id';

    return $query->join(DB::raw("($subquery) as sq"), 'group_id', '=', 'id');
}

After that in Api\ComponentGroupController we can do this:

public function getGroups()
{
    $groups = ComponentGroup::withSeverity();

    if (!$this->guard->check()) {
        $groups->visible();
    }

    $groups->search(Binput::except(['sort', 'order', 'per_page']));

    if ($sortBy = Binput::get('sort')) {
        $direction = Binput::get('order', 'asc');
        $groups->sort($sortBy, $direction);
    } else {
        $groups->orderBy('severity', 'desc')->orderBy('order');
    }

    $groups = $groups->paginate(Binput::get('per_page', 20));

    return $this->paginator($groups, Request::instance());
}

And this in ComponentsComposer:

public function compose(View $view)
{
    $componentGroups = $this->getVisibleGroupedComponents();
    $ungroupedComponents = Component::ungrouped()->get();

    $view->withComponentGroups($componentGroups)
        ->withUngroupedComponents($ungroupedComponents);
}

/**
 * Get visible grouped components.
 *
 * @return \Illuminate\Support\Collection
 */
protected function getVisibleGroupedComponents()
{
    $componentGroupsBuilder = ComponentGroup::withSeverity()
        ->orderBy('severity', 'desc')
        ->orderBy('order');

    if (!$this->guard->check()) {
        $componentGroupsBuilder->visible();
    }

    $usedComponentGroups = Component::grouped()->pluck('group_id');

    return $componentGroupsBuilder->used($usedComponentGroups)
        ->get();
}

billmn avatar Oct 05 '16 07:10 billmn

Not sure about anyone else but seeing DB::raw makes me want to rip my eyeballs out.

ConnorVG avatar Oct 05 '16 08:10 ConnorVG

@ConnorVG Is only an example to show you what I think to do.

We can try to get the same thing using the query builder, although I think it would become only more complicated to read.

billmn avatar Oct 05 '16 08:10 billmn

@jbrooksuk @GrahamCampbell Thoughts on this?

billmn avatar Oct 06 '16 12:10 billmn

Looks okay to me. @GrahamCampbell?

Like @ConnorVG said, that DB::raw is making me sad.

jbrooksuk avatar Oct 06 '16 13:10 jbrooksuk

@jbrooksuk @ConnorVG Agree, I'm trying to figure out how to execute this subquery without DB::raw ... any suggestions?

billmn avatar Oct 06 '16 14:10 billmn

Use Eloquent?

SELECT group_id, MAX(status) as severity FROM components GROUP BY group_id ->

$query->selectRaw('MAX(status) as severity')
    ->addSelect('group_id')
    ->groupBy('group_id');

idk about merging it into the scope though, I'm at work atm so I can't test anything.

ConnorVG avatar Oct 06 '16 14:10 ConnorVG

@ConnorVG Yes the problem is merging the scope, not create the query :)

billmn avatar Oct 06 '16 14:10 billmn

Assigned to @ConnorVG and @billmn to figure out :)

jbrooksuk avatar Oct 07 '16 06:10 jbrooksuk

@ConnorVG what about this? I think there aren't SQL injection points.

/**
 * Add status severity.
 *
 * @param \Illuminate\Database\Eloquent\Builder $query
 * @return \Illuminate\Database\Eloquent\Builder
 */
public function scopeWithSeverity(Builder $query)
{
    $subquery = Component::selectRaw('MAX(status) as severity')
        ->addSelect('group_id')
        ->groupBy('group_id');

    return $query->join(DB::raw("({$subquery->toSql()}) as sq"), 'group_id', '=', 'id');
}

billmn avatar Oct 07 '16 14:10 billmn

Ping @jbrooksuk

billmn avatar Oct 10 '16 07:10 billmn

@billmn that seems equally as bad to me :disappointed:

ConnorVG avatar Oct 10 '16 08:10 ConnorVG

@ConnorVG I don't know an other way to do this.

Does not seem that the query can cause security vulnerability. I don't see anything wrong to use DB::raw in this case.

billmn avatar Oct 10 '16 10:10 billmn

@ConnorVG what's the plan on this?

jbrooksuk avatar Oct 24 '16 17:10 jbrooksuk

Any movement?

jbrooksuk avatar Jan 04 '17 19:01 jbrooksuk

I don't see ecurity issues in my proposal ... If you agree I can PR

billmn avatar Jan 04 '17 20:01 billmn

@ConnorVG thoughts?

jbrooksuk avatar Feb 06 '17 19:02 jbrooksuk

Thank you for your input on Cachet 2.x. We are shifting our attention and resources to Cachet 3.x and will no longer be supporting the 2.x version. If your feedback or issue is relevant to the 3.x series, we encourage you to engage with the new branch.

For more information on the Cachet rebuild and our plans for 3.x, you can read the announcement here.

We appreciate your understanding and look forward to your contributions to the new version.

jbrooksuk avatar Aug 12 '23 19:08 jbrooksuk