Skip to content

Commit 0fdecb4

Browse files
authored
[Feature:System] Duplicate Enrollment of Class/Section(s) (#34)
This PR creates a tool for duplicating enrollment for specific class/section to another class/section with the intent to copy registration to optional practice courses.
1 parent 22d2d42 commit 0fdecb4

File tree

4 files changed

+313
-17
lines changed

4 files changed

+313
-17
lines changed

student_auto_feed/config.php

+5
Original file line numberDiff line numberDiff line change
@@ -193,5 +193,10 @@
193193
// 'tmp' or the current semester code.
194194
define('ADD_DROP_FILES_PATH', "path/to/reports/");
195195

196+
/* CRN Copymap ------------------------------------------------------------- */
197+
198+
// Where is the crn copymap CSV located. Set to NULL is this is not used.
199+
define('CRN_COPYMAP_FILE', "path/to/csv");
200+
196201
//EOF
197202
?>

student_auto_feed/crn_copymap.php

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#!/usr/bin/env php
2+
<?php
3+
require __DIR__ . "/config.php";
4+
5+
if (php_sapi_name() !== "cli") {
6+
die("This is a command line tool.\n");
7+
}
8+
9+
if (is_null(CRN_COPYMAP_FILE)) {
10+
die("CRN_COPYMAP_FILE is null. Check config.php.\n");
11+
}
12+
13+
$proc = new crn_copy();
14+
$proc->main();
15+
exit;
16+
17+
class crn_copy {
18+
public $err;
19+
20+
public function __construct() {
21+
$this->err = "";
22+
}
23+
24+
public function __destruct() {
25+
if ($this->err !== "") fprintf(STDERR, $this->err);
26+
}
27+
28+
public function main() {
29+
// Reminder: cli::parse_args() returns an array captured by regex,
30+
// so we need to always look at index [0] when reading $args data.
31+
$args = cli::parse_args();
32+
$args['source']['sections'][0] = $this->get_mappings($args['source']['sections'][0]);
33+
$args['dest']['sections'][0] = $this->get_mappings($args['dest']['sections'][0]);
34+
if (count($args['source']['sections'][0]) !== count($args['dest']['sections'][0])) {
35+
$this->err = "One course has more sections than the other. Sections need to map 1:1.\n";
36+
exit(1);
37+
}
38+
39+
$this->write_mappings($args);
40+
}
41+
42+
private function write_mappings($args) {
43+
$term = $args['term'][0];
44+
$source_course = $args['source']['course'][0];
45+
$source_sections = $args['source']['sections'][0];
46+
$dest_course = $args['dest']['course'][0];
47+
$dest_sections = $args['dest']['sections'][0];
48+
49+
// Insert "_{$term}" right before file extension.
50+
// e.g. "/path/to/crn_copymap.csv" for term f23 becomes "/path/to/crn_copymap_f23.csv"
51+
$filename = preg_replace("/([^\/]+?)(\.[^\/\.]*)?$/", "$1_{$term}$2", CRN_COPYMAP_FILE, 1);
52+
53+
$fh = fopen($filename, "a");
54+
if ($fh === false) {
55+
$this->err = "Could not open crn copymap file for writing.\n";
56+
exit(1);
57+
}
58+
59+
$len = count($source_sections);
60+
for ($i = 0; $i < $len; $i++) {
61+
$row = array($source_course, $source_sections[$i], $dest_course, $dest_sections[$i]);
62+
fputcsv($fh, $row, ",");
63+
}
64+
65+
fclose($fh);
66+
}
67+
68+
private function get_mappings($sections) {
69+
if ($sections === "" || $sections === "all") return array($sections);
70+
71+
$arr = explode(",", $sections);
72+
$expanded = array();
73+
foreach($arr as $val) {
74+
if (preg_match("/(\d+)\-(\d+)/", $val, $matches) === 1) {
75+
$expanded = array_merge($expanded, range((int) $matches[1], (int) $matches[2]));
76+
} else {
77+
$expanded[] = $val;
78+
}
79+
}
80+
81+
return $expanded;
82+
}
83+
}
84+
85+
/** class to parse command line arguments */
86+
class cli {
87+
/** @var string usage help message */
88+
private static $help_usage = "Usage: crn_copymap.php [-h | --help | help] (term) (course-a) (sections) (course-b) (sections)\n";
89+
/** @var string short description help message */
90+
private static $help_short_desc = "Create duplicate enrollment mapping of courses and semesters.\n";
91+
/** @var string long description help message */
92+
private static $help_long_desc = <<<LONG_DESC
93+
Create a mapping of CRNs (course and sections) that are to be duplicated.
94+
This is useful if a professor wishes to have a course enrollment,
95+
by section, duplicated to another course. Particularly when the
96+
duplicated course has no enrollment data provided by IT.\n
97+
LONG_DESC;
98+
/** @var string argument list help message */
99+
private static $help_args_list = <<<ARGS_LIST
100+
Arguments:
101+
-h, --help, help Show this help message.
102+
term Term code of courses and sections being mapped. Required.
103+
course-a Original course
104+
sections Section list, or "all" of preceding course
105+
course-b Course being copied to
106+
sections For course-b, this can be ommited when course-a sections is "all"
107+
ARGS_LIST;
108+
109+
/**
110+
* Parse command line arguments
111+
*
112+
* CLI arguments are captured from global $argv by regular expressions during validation.
113+
*
114+
* @return array cli arguments
115+
*/
116+
public static function parse_args() {
117+
global $argc, $argv;
118+
$matches = array();
119+
120+
switch(true) {
121+
// Check for request for help
122+
case $argc > 1 && ($argv[1] === "-h" || $argv[1] === "--help" || $argv[1] === "help"):
123+
self::print_help();
124+
exit;
125+
// Validate CLI arguments. Something is wrong (invalid) when a case condition is true.
126+
case $argc < 5 || $argc > 6:
127+
case $argv[3] === "all" && (array_key_exists(5, $argv) && $argv[5] !== "all"):
128+
case $argv[3] !== "all" && (!array_key_exists(5, $argv) || $argv[5] === "all"):
129+
case preg_match("/^[a-z][\d]{2}$/", $argv[1], $matches['term']) !== 1:
130+
case preg_match("/^[\w\d\-]+$/", $argv[2], $matches['source']['course']) !== 1:
131+
case preg_match("/^\d+(?:(?:,|\-)\d+)*$|^all$/", $argv[3], $matches['source']['sections']) !== 1:
132+
case preg_match("/^[\w\d\-]+$/", $argv[4], $matches['dest']['course']) !== 1:
133+
case preg_match("/^\d+(?:(?:,|\-)\d+)*$|^(?:all)?$/", $argv[5], $matches['dest']['sections']) !== 1:
134+
self::print_usage();
135+
exit;
136+
}
137+
138+
// $matches['dest']['sections'][0] must be "all" when ['source']['sections'][0] is "all".
139+
if ($matches['source']['sections'][0] === "all") $matches['dest']['sections'][0] = "all";
140+
return $matches;
141+
}
142+
143+
/** Print complete help */
144+
private static function print_help() {
145+
$msg = self::$help_usage . PHP_EOL;
146+
$msg .= self::$help_short_desc . PHP_EOL;
147+
$msg .= self::$help_long_desc . PHP_EOL;
148+
$msg .= self::$help_args_list . PHP_EOL;
149+
print $msg;
150+
}
151+
152+
/** Print CLI usage */
153+
private static function print_usage() {
154+
print self::$help_usage . PHP_EOL;
155+
}
156+
}
157+
// EOF
158+
?>

student_auto_feed/readme.md

+28-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Submitty Student Auto Feed Script
2-
Readme last updated Nov 17, 2021
2+
Readme last updated Sept 1, 2023
33

44
This is a code example for any University to use as a basis to have Submitty course's enrollment data added or updated on an automated schedule with a student enrollment CSV datasheet.
55

@@ -134,7 +134,7 @@ the first (prior to autofeed) or second (after auto feed) run.
134134

135135
Second cli parameter is the term code.
136136

137-
For example:
137+
For example:
138138
```
139139
$ ./add_drop_report.php 1 f21
140140
```
@@ -145,3 +145,29 @@ $ ./add_drop_report.php 2 f21
145145
```
146146
Will invoke the _second_ run to create the report of student enrollments for the
147147
Fall 2021 term.
148+
149+
## crn_copymap.php
150+
151+
Create a mapping of CRNs (course, term) that are to be duplicated. This is
152+
useful if a professor wishes to have a course enrollment, by section,
153+
duplicated to another course. Particularly when the duplicated course has
154+
no enrollment data provided by IT.
155+
156+
Sections can be a comma separated list, a range denoted by a hyphen, or the
157+
word "all" for all sections. Note that "all" sections will copy sections
158+
respectively. i.e. section 1 is copied as section 1, section 2 is copied as
159+
section 2, etc.
160+
161+
### Usage
162+
```bash
163+
$ crn_copymap.php (term) (original_course) (original_sections) (copied_course) (copied_sections)
164+
```
165+
For example:
166+
Copy enrollments of term "f23" (fall 2023) of course CSCI 1000,
167+
sections 1, 3, and 5 through 9 to course CSCI 2000 as sections 2, 4, and 6 through 10
168+
respectively.
169+
```bash
170+
$ crn_copymap.php f23 csci1000 1,3,5-9 csci2000 2,4,6-10
171+
```
172+
173+
EOF

0 commit comments

Comments
 (0)