• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daycry / auth / 22527658769

28 Feb 2026 07:41PM UTC coverage: 63.267% (-3.6%) from 66.864%
22527658769

push

github

web-flow
Merge pull request #36 from daycry/development

Implement TOTP 2FA, JWT auth, device session tracking, and docs overhaul

465 of 1168 new or added lines in 52 files covered. (39.81%)

129 existing lines in 46 files now uncovered.

3064 of 4843 relevant lines covered (63.27%)

41.53 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Controllers/Admin/GroupsController.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of Daycry Auth.
7
 *
8
 * (c) Daycry <daycry9@proton.me>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace Daycry\Auth\Controllers\Admin;
15

16
use CodeIgniter\HTTP\RedirectResponse;
17
use Daycry\Auth\Entities\Group;
18
use Daycry\Auth\Models\GroupModel;
19
use Daycry\Auth\Models\GroupUserModel;
20
use Daycry\Auth\Models\PermissionGroupModel;
21
use Daycry\Auth\Models\PermissionModel;
22

23
/**
24
 * Admin Groups Controller — CRUD for groups (roles).
25
 */
26
class GroupsController extends BaseAdminController
27
{
28
    /**
29
     * List all groups with member counts.
30
     */
NEW
31
    public function index(): string
×
32
    {
33
        /** @var GroupModel $groupModel */
NEW
34
        $groupModel = model(GroupModel::class);
×
35

36
        /** @var GroupUserModel $groupUserModel */
NEW
37
        $groupUserModel = model(GroupUserModel::class);
×
38

NEW
39
        $groups = $groupModel->orderBy('name')->findAll();
×
40

41
        // Attach member counts using group_id
NEW
42
        $counts = [];
×
43

NEW
44
        foreach ($groups as $group) {
×
NEW
45
            $counts[$group->id] = $groupUserModel->where('group_id', $group->id)->countAllResults();
×
46
        }
47

NEW
48
        return $this->view('Daycry\\Auth\\Views\\admin\\groups\\index', [
×
NEW
49
            'groups' => $groups,
×
NEW
50
            'counts' => $counts,
×
NEW
51
        ]);
×
52
    }
53

54
    /**
55
     * Show the create-group form.
56
     */
NEW
57
    public function create(): string
×
58
    {
59
        /** @var PermissionModel $permissionModel */
NEW
60
        $permissionModel = model(PermissionModel::class);
×
61

NEW
62
        return $this->view('Daycry\\Auth\\Views\\admin\\groups\\form', [
×
NEW
63
            'group'    => null,
×
NEW
64
            'allPerms' => $permissionModel->findAll(),
×
NEW
65
            'assigned' => [],
×
NEW
66
        ]);
×
67
    }
68

69
    /**
70
     * Persist a new group.
71
     */
NEW
72
    public function store(): RedirectResponse
×
73
    {
74
        /** @var GroupModel $groupModel */
NEW
75
        $groupModel = model(GroupModel::class);
×
76

NEW
77
        $name        = trim((string) $this->request->getPost('name'));
×
NEW
78
        $description = trim((string) $this->request->getPost('description'));
×
79

NEW
80
        if ($name === '') {
×
NEW
81
            return redirect()->route('admin-group-create')->with('error', 'Group name is required.');
×
82
        }
83

NEW
84
        $group              = new Group();
×
NEW
85
        $group->name        = $name;
×
NEW
86
        $group->description = $description !== '' ? $description : null;
×
87

NEW
88
        if (! $groupModel->save($group)) {
×
NEW
89
            return redirect()->route('admin-group-create')
×
NEW
90
                ->with('errors', $groupModel->errors());
×
91
        }
92

NEW
93
        return redirect()->route('admin-groups')
×
NEW
94
            ->with('message', "Group \"{$name}\" created.");
×
95
    }
96

97
    /**
98
     * Show the edit form for an existing group.
99
     *
100
     * @param int|string $id
101
     */
NEW
102
    public function edit($id): RedirectResponse|string
×
103
    {
NEW
104
        $group = $this->findGroupOr404((int) $id);
×
105

NEW
106
        if ($group instanceof RedirectResponse) {
×
NEW
107
            return $group;
×
108
        }
109

110
        /** @var PermissionModel $permissionModel */
NEW
111
        $permissionModel = model(PermissionModel::class);
×
112

113
        /** @var PermissionGroupModel $pgModel */
NEW
114
        $pgModel = model(PermissionGroupModel::class);
×
115

116
        // Collect IDs of permissions already assigned to this group
NEW
117
        $assigned = array_column(
×
NEW
118
            $pgModel->where('group_id', $group->id)->findAll(),
×
NEW
119
            'permission_id',
×
NEW
120
        );
×
121

NEW
122
        return $this->view('Daycry\\Auth\\Views\\admin\\groups\\form', [
×
NEW
123
            'group'    => $group,
×
NEW
124
            'allPerms' => $permissionModel->findAll(),
×
NEW
125
            'assigned' => $assigned,
×
NEW
126
        ]);
×
127
    }
128

129
    /**
130
     * Persist edits to an existing group.
131
     *
132
     * @param int|string $id
133
     */
NEW
134
    public function update($id): RedirectResponse
×
135
    {
NEW
136
        $group = $this->findGroupOr404((int) $id);
×
137

NEW
138
        if ($group instanceof RedirectResponse) {
×
NEW
139
            return $group;
×
140
        }
141

142
        /** @var GroupModel $groupModel */
NEW
143
        $groupModel = model(GroupModel::class);
×
144

NEW
145
        $description = trim((string) $this->request->getPost('description'));
×
146

NEW
147
        $group->description = $description !== '' ? $description : null;
×
NEW
148
        $groupModel->save($group);
×
149

150
        // Sync permissions for the group via PermissionGroupModel
151
        /** @var PermissionGroupModel $pgModel */
NEW
152
        $pgModel = model(PermissionGroupModel::class);
×
153

154
        // The form sends permission IDs (from the checkbox values)
NEW
155
        $newPermIds = array_filter(array_map('intval', (array) $this->request->getPost('permissions')));
×
156

NEW
157
        $pgModel->deleteAll($group->id);
×
158

NEW
159
        if ($newPermIds !== []) {
×
NEW
160
            $inserts = [];
×
161

NEW
162
            foreach ($newPermIds as $permId) {
×
NEW
163
                $inserts[] = ['group_id' => $group->id, 'permission_id' => $permId];
×
164
            }
165

NEW
166
            $pgModel->insertBatch($inserts);
×
167
        }
168

NEW
169
        return redirect()->route('admin-groups')
×
NEW
170
            ->with('message', "Group \"{$group->name}\" updated.");
×
171
    }
172

173
    /**
174
     * Delete a group.
175
     *
176
     * @param int|string $id
177
     */
NEW
178
    public function delete($id): RedirectResponse
×
179
    {
NEW
180
        $group = $this->findGroupOr404((int) $id);
×
181

NEW
182
        if ($group instanceof RedirectResponse) {
×
NEW
183
            return $group;
×
184
        }
185

186
        /** @var GroupModel $groupModel */
NEW
187
        $groupModel = model(GroupModel::class);
×
NEW
188
        $groupModel->delete($group->id, true);
×
189

NEW
190
        return redirect()->route('admin-groups')
×
NEW
191
            ->with('message', "Group \"{$group->name}\" deleted.");
×
192
    }
193

194
    // ── Private helpers ───────────────────────────────────────────
195

NEW
196
    private function findGroupOr404(int $id): Group|RedirectResponse
×
197
    {
198
        /** @var GroupModel $groupModel */
NEW
199
        $groupModel = model(GroupModel::class);
×
NEW
200
        $group      = $groupModel->find($id);
×
201

NEW
202
        if ($group === null) {
×
NEW
203
            return redirect()->route('admin-groups')->with('error', 'Group not found.');
×
204
        }
205

NEW
206
        return $group;
×
207
    }
208
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc