diff options
| author | vin <git@vineetk.net> | 2023-11-16 13:44:11 -0500 |
|---|---|---|
| committer | vin <git@vineetk.net> | 2023-11-20 10:08:58 -0500 |
| commit | 23226c46a16bd1037016c1578b608eb6d23f7546 (patch) | |
| tree | 04cad20e31b2d76b5e76bebed151503c89c43f03 | |
| parent | b966951c47e2ba886d7a99541072c586b64bb17a (diff) | |
use the Canvas API to get A+ tool ID and URL
Was previously hardcoded.
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | aplus.go | 7 | ||||
| -rw-r--r-- | canvas.go | 32 | ||||
| -rw-r--r-- | main.go | 2 | ||||
| -rw-r--r-- | structs.go | 6 |
5 files changed, 43 insertions, 6 deletions
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | This is an cli utility initially created for students at Florida Polytechnic University to submit their aplus codes. | 3 | This is an cli utility initially created for students at Florida Polytechnic University to submit their aplus codes. |
| 4 | In time, we intend to generalize this utility to all universities. | 4 | In time, we intend to generalize this utility to all universities. |
| 5 | In the meantime however, any students from other universities wishing to use the utility may change the base_link and external_tools_code (you see this in the URL when you navigate to Aplus attendance within your course) variables. | 5 | In the meantime however, any students from other universities wishing to use the utility may change the instance_url (the main URL you see before the / when you use Canvas) variables. |
| 6 | 6 | ||
| 7 | ## Usage | 7 | ## Usage |
| 8 | 8 | ||
| @@ -7,6 +7,7 @@ import ( | |||
| 7 | "io" | 7 | "io" |
| 8 | "net/http" | 8 | "net/http" |
| 9 | "net/url" | 9 | "net/url" |
| 10 | "os" | ||
| 10 | "strings" | 11 | "strings" |
| 11 | ) | 12 | ) |
| 12 | 13 | ||
| @@ -60,6 +61,12 @@ func submit_code(course_code int, attendance_code string) { | |||
| 60 | } | 61 | } |
| 61 | 62 | ||
| 62 | func launch_aplus(course_code int) string { | 63 | func launch_aplus(course_code int) string { |
| 64 | err := init_aplus_toolid(course_code) | ||
| 65 | if err != nil { | ||
| 66 | fmt.Println("Failed to get A+ base URL and tool ID") | ||
| 67 | os.Exit(1) | ||
| 68 | } | ||
| 69 | |||
| 63 | aplus_link := fmt.Sprintf("%s/courses/%d/external_tools/sessionless_launch?id=%d&access_token=%s", | 70 | aplus_link := fmt.Sprintf("%s/courses/%d/external_tools/sessionless_launch?id=%d&access_token=%s", |
| 64 | base_link, course_code, external_tools_code, token) | 71 | base_link, course_code, external_tools_code, token) |
| 65 | aplus := get_aplus(token, aplus_link, client) | 72 | aplus := get_aplus(token, aplus_link, client) |
| @@ -2,20 +2,21 @@ package main | |||
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "encoding/json" | 4 | "encoding/json" |
| 5 | "errors" | ||
| 5 | "fmt" | 6 | "fmt" |
| 6 | "io" | 7 | "io" |
| 7 | "net/http" | 8 | "net/http" |
| 8 | "net/http/cookiejar" | 9 | "net/http/cookiejar" |
| 9 | "os" | 10 | "os" |
| 11 | "strings" | ||
| 10 | 12 | ||
| 11 | "golang.org/x/net/publicsuffix" | 13 | "golang.org/x/net/publicsuffix" |
| 12 | ) | 14 | ) |
| 13 | 15 | ||
| 14 | func initialize() { | 16 | func initialize() { |
| 15 | base_link = "https://floridapolytechnic.instructure.com/api/v1" | 17 | instance_url := "https://floridapolytechnic.instructure.com" |
| 16 | base_aplus_link = "https://floridapoly.aplusattendance.com/canvas" | 18 | base_link = instance_url + "/api/v1" |
| 17 | token = os.Getenv("CANVAS_API_KEY") | 19 | token = os.Getenv("CANVAS_API_KEY") |
| 18 | external_tools_code = 913 | ||
| 19 | jar, _ := cookiejar.New(&cookiejar.Options{ | 20 | jar, _ := cookiejar.New(&cookiejar.Options{ |
| 20 | PublicSuffixList: publicsuffix.List, | 21 | PublicSuffixList: publicsuffix.List, |
| 21 | }) | 22 | }) |
| @@ -49,6 +50,31 @@ func get_courses(token string, link string, client http.Client) []CanvasCourse { | |||
| 49 | return canvas_courses | 50 | return canvas_courses |
| 50 | } | 51 | } |
| 51 | 52 | ||
| 53 | func init_aplus_toolid(course_id int) error { | ||
| 54 | link := fmt.Sprintf("%s/courses/%d/external_tools?access_token=%s&search_term=aplus&include_parents=true", base_link, course_id, token) | ||
| 55 | resp, err := client.Get(link) | ||
| 56 | if err != nil { | ||
| 57 | return err | ||
| 58 | } | ||
| 59 | defer resp.Body.Close() | ||
| 60 | body, _ := io.ReadAll(resp.Body) | ||
| 61 | |||
| 62 | var external_tools []ExternalTool | ||
| 63 | err = json.Unmarshal(body, &external_tools) | ||
| 64 | if err != nil && !strings.Contains(string(body), "\"unauthorized\"") { | ||
| 65 | return err | ||
| 66 | } | ||
| 67 | |||
| 68 | for _, tool := range external_tools { | ||
| 69 | if strings.Contains(tool.URL, ".aplusattendance.com/") && base_aplus_link == "" { | ||
| 70 | base_aplus_link = tool.URL | ||
| 71 | external_tools_code = tool.ID | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | return errors.New("Could not find A+ link and tool ID") | ||
| 76 | } | ||
| 77 | |||
| 52 | func list_all_courses() { | 78 | func list_all_courses() { |
| 53 | all_courses := fmt.Sprintf("%s/courses?access_token=%s&per_page=100", base_link, token) | 79 | all_courses := fmt.Sprintf("%s/courses?access_token=%s&per_page=100", base_link, token) |
| 54 | 80 | ||
| @@ -9,9 +9,7 @@ import ( | |||
| 9 | ) | 9 | ) |
| 10 | 10 | ||
| 11 | var base_link string | 11 | var base_link string |
| 12 | var base_aplus_link string | ||
| 13 | var token string | 12 | var token string |
| 14 | var external_tools_code int | ||
| 15 | var client http.Client | 13 | var client http.Client |
| 16 | 14 | ||
| 17 | func main() { | 15 | func main() { |
| @@ -54,3 +54,9 @@ type Enrollment struct { | |||
| 54 | EnrollmentState string `json:"enrollment_state"` | 54 | EnrollmentState string `json:"enrollment_state"` |
| 55 | LimitPrivilegesToCourseSection bool `json:"limit_privileges_to_course_section"` | 55 | LimitPrivilegesToCourseSection bool `json:"limit_privileges_to_course_section"` |
| 56 | } | 56 | } |
| 57 | |||
| 58 | type ExternalTool struct { | ||
| 59 | ID int `json:"id"` | ||
| 60 | URL string `json:"url"` | ||
| 61 | Status string `json:"status"` | ||
| 62 | } | ||
