Skip to content

Commit f2389ea

Browse files
authored
Merge pull request #19 from cmu-sei/lp-test
Lp test
2 parents 9eea65c + 903787b commit f2389ea

23 files changed

+2704
-736
lines changed

block_crucible.php

Lines changed: 445 additions & 316 deletions
Large diffs are not rendered by default.

classes/competencies.php

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
<?php
2+
namespace block_crucible;
3+
4+
defined('MOODLE_INTERNAL') || die();
5+
6+
use moodle_url;
7+
8+
class competencies {
9+
10+
public function list_mapped_via_api(int $limit = 20): array {
11+
$all = \core_competency\competency::get_records([], 'shortname', 'ASC');
12+
$out = [];
13+
$ctx = \context_system::instance();
14+
15+
foreach ($all as $cobj) {
16+
if (count($out) >= $limit) {
17+
break;
18+
}
19+
20+
$cid = (int)$cobj->get('id');
21+
$shortname = (string)$cobj->get('shortname');
22+
$idnumber = (string)$cobj->get('idnumber');
23+
24+
$frameworkshort = '';
25+
if ($fwid = $cobj->get('competencyframeworkid')) {
26+
if ($fw = \core_competency\competency_framework::get_record(['id' => $fwid])) {
27+
$frameworkshort = (string)$fw->get('shortname');
28+
}
29+
}
30+
31+
// Courses using this competency
32+
$courses = \core_competency\api::list_courses_using_competency($cid);
33+
$coursecount = is_array($courses) ? count($courses) : 0;
34+
35+
if ($coursecount === 0) {
36+
continue;
37+
}
38+
39+
// Count activities across those courses
40+
$activitycount = 0;
41+
if (!empty($courses)) {
42+
foreach ($courses as $cs) {
43+
$cmids = \core_competency\api::list_course_modules_using_competency($cid, (int)$cs->id);
44+
if (is_array($cmids)) {
45+
$activitycount += count($cmids);
46+
if ($activitycount > 0) {
47+
break;
48+
}
49+
}
50+
}
51+
}
52+
53+
if ($activitycount === 0) {
54+
continue;
55+
}
56+
57+
$out[] = (object)[
58+
'id' => $cid,
59+
'name' => format_string($shortname, true, ['context' => $ctx]),
60+
'framework' => s($frameworkshort),
61+
'idnumber' => s($idnumber),
62+
'coursecount' => $coursecount,
63+
'activitycount' => $activitycount,
64+
'url' => (new \moodle_url('/blocks/crucible/competency.php', ['idnumber' => $idnumber]))->out(false),
65+
];
66+
}
67+
68+
return $out;
69+
}
70+
71+
public function get_view_data(int $limit = 20): \stdClass {
72+
$rows = $this->list_mapped_via_api($limit);
73+
74+
// --- mapped grouping (unchanged) ---
75+
$unknown = get_string('framework_unknown', 'block_crucible');
76+
$buckets = [];
77+
foreach ($rows as $r) {
78+
$fname = trim((string)$r->framework) !== '' ? (string)$r->framework : $unknown;
79+
$buckets[$fname][] = $r;
80+
}
81+
ksort($buckets, SORT_NATURAL | SORT_FLAG_CASE);
82+
$groups = [];
83+
foreach ($buckets as $fname => $items) {
84+
$groups[] = (object)[
85+
'framework' => $fname,
86+
'count' => count($items),
87+
'competencies' => $items,
88+
];
89+
}
90+
91+
// --- NEW: unmapped summary per framework, linking to competency.php?fwid=... ---
92+
$unmappedbuckets = []; // key: framework label
93+
$all = \core_competency\competency::get_records([], 'shortname', 'ASC');
94+
$ctx = \context_system::instance();
95+
96+
foreach ($all as $cobj) {
97+
$cid = (int)$cobj->get('id');
98+
$shortname = (string)$cobj->get('shortname');
99+
$idnumber = (string)$cobj->get('idnumber');
100+
101+
// Resolve framework label + id
102+
$fwlabel = $unknown;
103+
$fwidval = 0;
104+
if ($fwid = $cobj->get('competencyframeworkid')) {
105+
if ($fw = \core_competency\competency_framework::get_record(['id' => $fwid])) {
106+
$fwlabel = (string)$fw->get('shortname') ?: $unknown;
107+
$fwidval = (int)$fw->get('id');
108+
}
109+
}
110+
111+
// Counts
112+
$courses = \core_competency\api::list_courses_using_competency($cid);
113+
$coursecount = is_array($courses) ? count($courses) : 0;
114+
115+
$activitycount = 0;
116+
if (!empty($courses)) {
117+
foreach ($courses as $cs) {
118+
$cmids = \core_competency\api::list_course_modules_using_competency($cid, (int)$cs->id);
119+
if (is_array($cmids)) {
120+
$activitycount += count($cmids);
121+
}
122+
}
123+
}
124+
125+
// Unmapped = 0 courses OR 0 activities
126+
if ($coursecount === 0 || $activitycount === 0) {
127+
if (!isset($unmappedbuckets[$fwlabel])) {
128+
$unmappedbuckets[$fwlabel] = (object)[
129+
'framework' => $fwlabel,
130+
'fwid' => $fwidval,
131+
'count' => 0,
132+
];
133+
}
134+
$unmappedbuckets[$fwlabel]->count++;
135+
}
136+
}
137+
138+
ksort($unmappedbuckets, SORT_NATURAL | SORT_FLAG_CASE);
139+
$unmapped = [];
140+
foreach ($unmappedbuckets as $g) {
141+
$unmapped[] = (object)[
142+
'framework' => $g->framework,
143+
'fwid' => $g->fwid,
144+
'count' => $g->count,
145+
// prebuild the link to reuse competency.php with fwid
146+
'url' => (new \moodle_url('/blocks/crucible/competency.php', ['fwid' => $g->fwid]))->out(false),
147+
];
148+
}
149+
150+
return (object)[
151+
'hascomps' => !empty($rows),
152+
'competencies' => $rows, // kept for compatibility
153+
'hasgroups' => !empty($groups),
154+
'groups' => $groups, // mapped per framework
155+
156+
// New summary rows at the bottom:
157+
'hasunmapped' => !empty($unmapped),
158+
'unmapped' => $unmapped,
159+
];
160+
}
161+
162+
public function get_competency_detail_data(string $idnumber): \stdClass {
163+
global $CFG;
164+
require_once($CFG->dirroot.'/course/lib.php');
165+
166+
$ctxsys = \context_system::instance();
167+
168+
// Load competencies
169+
$c = \core_competency\competency::get_record(['idnumber' => $idnumber]);
170+
if (!$c) {
171+
throw new \moodle_exception('invalidrecord', 'error');
172+
}
173+
174+
$cid = (int)$c->get('id');
175+
$name = (string)$c->get('shortname');
176+
$idnumber = (string)$c->get('idnumber');
177+
$fwshort = '';
178+
if ($fwid = $c->get('competencyframeworkid')) {
179+
if ($fw = \core_competency\competency_framework::get_record(['id' => $fwid])) {
180+
$fwshort = (string)$fw->get('shortname');
181+
}
182+
}
183+
184+
// Courses using this competency.
185+
$courses = \core_competency\api::list_courses_using_competency($cid);
186+
187+
$coursecards = [];
188+
$activitysets = [];
189+
190+
if (!empty($courses)) {
191+
foreach ($courses as $cs) {
192+
$courseid = (int)$cs->id;
193+
$course = get_course($courseid);
194+
$cctx = \context_course::instance($courseid);
195+
196+
$catname = '';
197+
if (!empty($course->category)) {
198+
try {
199+
$cat = \core_course_category::get($course->category, IGNORE_MISSING);
200+
if ($cat) $catname = $cat->get_formatted_name();
201+
} catch (\Throwable $e) {}
202+
}
203+
204+
// Activities mapped to this competency in this course.
205+
$cmids = \core_competency\api::list_course_modules_using_competency($cid, $courseid);
206+
$modinfo = get_fast_modinfo($courseid);
207+
$acts = [];
208+
209+
if (!empty($cmids)) {
210+
foreach ($cmids as $cmid) {
211+
$cm = $modinfo->get_cm($cmid, IGNORE_MISSING);
212+
if (!$cm) continue;
213+
$acts[] = (object)[
214+
'name' => $cm->get_formatted_name(),
215+
'url' => $cm->url ? $cm->url->out(false)
216+
: (new \moodle_url('/course/view.php', ['id' => $courseid]))->out(false),
217+
'modname' => $cm->modname,
218+
];
219+
}
220+
}
221+
222+
$coursecards[] = (object)[
223+
'id' => $courseid,
224+
'fullname' => format_string($course->fullname, true, ['context' => $cctx]),
225+
'url' => (new \moodle_url('/course/view.php', ['id' => $courseid]))->out(false),
226+
'category' => $catname,
227+
'actcount' => count($acts),
228+
];
229+
230+
if ($acts) {
231+
$activitysets[] = (object)[
232+
'courseid' => $courseid,
233+
'courseurl' => (new \moodle_url('/course/view.php', ['id' => $courseid]))->out(false),
234+
'coursename' => format_string($course->fullname, true, ['context' => $cctx]),
235+
'activities' => $acts,
236+
];
237+
}
238+
}
239+
}
240+
241+
return (object)[
242+
'id' => $cid,
243+
'name' => format_string($name, true, ['context' => $ctxsys]),
244+
'idnumber' => s($idnumber),
245+
'framework' => s($fwshort),
246+
'hascourses' => !empty($coursecards),
247+
'courses' => $coursecards,
248+
'hasactivities'=> !empty($activitysets),
249+
'bycourse' => $activitysets,
250+
];
251+
}
252+
253+
public function get_unmapped_for_framework(int $fwid): \stdClass {
254+
$unknown = get_string('framework_unknown', 'block_crucible');
255+
$ctx = \context_system::instance();
256+
257+
$fwrec = \core_competency\competency_framework::get_record(['id' => $fwid]);
258+
$fwname = $fwrec ? (string)$fwrec->get('shortname') : $unknown;
259+
260+
// All comps in this framework
261+
$comps = \core_competency\competency::get_records(['competencyframeworkid' => $fwid], 'shortname', 'ASC');
262+
263+
$items = [];
264+
foreach ($comps as $cobj) {
265+
$cid = (int)$cobj->get('id');
266+
$shortname = (string)$cobj->get('shortname');
267+
$idnumber = (string)$cobj->get('idnumber');
268+
269+
// counts (same logic you already use)
270+
$courses = \core_competency\api::list_courses_using_competency($cid);
271+
$coursecount = is_array($courses) ? count($courses) : 0;
272+
273+
$activitycount = 0;
274+
if (!empty($courses)) {
275+
foreach ($courses as $cs) {
276+
$cmids = \core_competency\api::list_course_modules_using_competency($cid, (int)$cs->id);
277+
if (is_array($cmids)) {
278+
$activitycount += count($cmids);
279+
}
280+
}
281+
}
282+
283+
// unmapped = zero courses OR zero activities
284+
if ($coursecount === 0 || $activitycount === 0) {
285+
$items[] = (object)[
286+
'id' => $cid,
287+
'name' => format_string($shortname, true, ['context' => $ctx]),
288+
'idnumber' => s($idnumber),
289+
'url' => (new \moodle_url('/blocks/crucible/competency.php', ['idnumber' => $idnumber]))->out(false),
290+
];
291+
}
292+
}
293+
294+
return (object)[
295+
'framework' => s($fwname),
296+
'count' => count($items),
297+
'hasitems' => !empty($items),
298+
'items' => $items,
299+
];
300+
}
301+
}

classes/crucible.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,14 +1181,14 @@ public function get_keycloak_groups() {
11811181
if (is_array($groups) && !empty($groups)) {
11821182
// Initialize an array to store group names.
11831183
$groupNames = [];
1184-
1184+
11851185
// Loop through each group and collect the 'name' value.
11861186
foreach ($groups as $group) {
11871187
if (isset($group['name'])) {
11881188
$groupNames[] = $group['name'];
11891189
}
11901190
}
1191-
1191+
11921192
// Output or return the array of group names.
11931193
return $groupNames;
11941194
} else {

0 commit comments

Comments
 (0)