This commit is contained in:
Tyler Beckman 2024-10-14 00:18:50 -06:00
commit 604979ec12
Signed by: Ty
GPG key ID: 2813440C772555A4
11 changed files with 43131 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

243
Cargo.lock generated Normal file
View file

@ -0,0 +1,243 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "ascii"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "canvas-autouploader"
version = "0.1.0"
dependencies = [
"graphql_client",
"serde",
]
[[package]]
name = "combine"
version = "3.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680"
dependencies = [
"ascii",
"byteorder",
"either",
"memchr",
"unreachable",
]
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "graphql-introspection-query"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2a4732cf5140bd6c082434494f785a19cfb566ab07d1382c3671f5812fed6d"
dependencies = [
"serde",
]
[[package]]
name = "graphql-parser"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2ebc8013b4426d5b81a4364c419a95ed0b404af2b82e2457de52d9348f0e474"
dependencies = [
"combine",
"thiserror",
]
[[package]]
name = "graphql_client"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a50cfdc7f34b7f01909d55c2dcb71d4c13cbcbb4a1605d6c8bd760d654c1144b"
dependencies = [
"graphql_query_derive",
"serde",
"serde_json",
]
[[package]]
name = "graphql_client_codegen"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e27ed0c2cf0c0cc52c6bcf3b45c907f433015e580879d14005386251842fb0a"
dependencies = [
"graphql-introspection-query",
"graphql-parser",
"heck",
"lazy_static",
"proc-macro2",
"quote",
"serde",
"serde_json",
"syn 1.0.109",
]
[[package]]
name = "graphql_query_derive"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83febfa838f898cfa73dfaa7a8eb69ff3409021ac06ee94cfb3d622f6eeb1a97"
dependencies = [
"graphql_client_codegen",
"proc-macro2",
"syn 1.0.109",
]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "proc-macro2"
version = "1.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "serde"
version = "1.0.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
]
[[package]]
name = "serde_json"
version = "1.0.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "unreachable"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
dependencies = [
"void",
]
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"

8
Cargo.toml Normal file
View file

@ -0,0 +1,8 @@
[package]
name = "canvas-autouploader"
version = "0.1.0"
edition = "2021"
[dependencies]
graphql_client = "0.14.0"
serde = "1.0.210"

42635
graphql/canvas-schema.json Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,26 @@
mutation CreateSubmission($file_id: ID!, $assignment_id: ID!) {
createSubmission(
input: {
assignmentId: $assignment_id,
fileIds: [
$file_id
],
submissionType: online_upload
}
) {
errors {
message
attribute
}
submission {
id
assignment {
name
course {
name
courseCode
}
}
}
}
}

View file

@ -0,0 +1,16 @@
query GetCourseAssignments {
allCourses {
_id
courseCode
assignmentGroups {
assignmentsConnection {
nodes {
_id
id
name
submissionTypes
}
}
}
}
}

5
src/main.rs Normal file
View file

@ -0,0 +1,5 @@
mod types;
fn main() {
println!("Hello, world!");
}

View file

@ -0,0 +1,66 @@
#![allow(clippy::all, warnings)]
pub struct CreateSubmission;
pub mod create_submission {
#![allow(dead_code)]
use std::result::Result;
pub const OPERATION_NAME: &str = "CreateSubmission";
pub const QUERY : & str = "mutation CreateSubmission($file_id: ID!, $assignment_id: ID!) {\n createSubmission(\n input: {\n assignmentId: $assignment_id,\n fileIds: [\n $file_id\n ],\n submissionType: online_upload\n }\n ) {\n errors {\n message\n attribute\n }\n submission {\n id\n assignment {\n name\n course {\n name\n courseCode\n }\n }\n }\n }\n}" ;
use super::*;
use serde::{Deserialize, Serialize};
#[allow(dead_code)]
type Boolean = bool;
#[allow(dead_code)]
type Float = f64;
#[allow(dead_code)]
type Int = i64;
#[allow(dead_code)]
type ID = String;
#[derive(Serialize)]
pub struct Variables {
pub file_id: ID,
pub assignment_id: ID,
}
impl Variables {}
#[derive(Deserialize)]
pub struct ResponseData {
#[serde(rename = "createSubmission")]
pub create_submission: Option<CreateSubmissionCreateSubmission>,
}
#[derive(Deserialize)]
pub struct CreateSubmissionCreateSubmission {
pub errors: Option<Vec<CreateSubmissionCreateSubmissionErrors>>,
pub submission: Option<CreateSubmissionCreateSubmissionSubmission>,
}
#[derive(Deserialize)]
pub struct CreateSubmissionCreateSubmissionErrors {
pub message: String,
pub attribute: Option<String>,
}
#[derive(Deserialize)]
pub struct CreateSubmissionCreateSubmissionSubmission {
pub id: ID,
pub assignment: Option<CreateSubmissionCreateSubmissionSubmissionAssignment>,
}
#[derive(Deserialize)]
pub struct CreateSubmissionCreateSubmissionSubmissionAssignment {
pub name: Option<String>,
pub course: Option<CreateSubmissionCreateSubmissionSubmissionAssignmentCourse>,
}
#[derive(Deserialize)]
pub struct CreateSubmissionCreateSubmissionSubmissionAssignmentCourse {
pub name: String,
#[serde(rename = "courseCode")]
pub course_code: Option<String>,
}
}
impl graphql_client::GraphQLQuery for CreateSubmission {
type Variables = create_submission::Variables;
type ResponseData = create_submission::ResponseData;
fn build_query(variables: Self::Variables) -> ::graphql_client::QueryBody<Self::Variables> {
graphql_client::QueryBody {
variables,
query: create_submission::QUERY,
operation_name: create_submission::OPERATION_NAME,
}
}
}

View file

@ -0,0 +1,126 @@
#![allow(clippy::all, warnings)]
pub struct GetCourseAssignments;
pub mod get_course_assignments {
#![allow(dead_code)]
use std::result::Result;
pub const OPERATION_NAME: &str = "GetCourseAssignments";
pub const QUERY : & str = "query GetCourseAssignments {\n\tallCourses {\n\t\t_id\n\t\tcourseCode\n\t\tassignmentGroups {\n\t\t\tassignmentsConnection {\n\t\t\t\tnodes {\n\t\t\t\t\t_id\n\t\t\t\t\tid\n\t\t\t\t\tname\n\t\t\t\t\tsubmissionTypes\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}" ;
use super::*;
use serde::{Deserialize, Serialize};
#[allow(dead_code)]
type Boolean = bool;
#[allow(dead_code)]
type Float = f64;
#[allow(dead_code)]
type Int = i64;
#[allow(dead_code)]
type ID = String;
#[derive()]
pub enum SubmissionType {
attendance,
basic_lti_launch,
discussion_topic,
external_tool,
media_recording,
none,
not_graded,
on_paper,
online_quiz,
online_text_entry,
online_upload,
online_url,
student_annotation,
wiki_page,
Other(String),
}
impl ::serde::Serialize for SubmissionType {
fn serialize<S: serde::Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_str(match *self {
SubmissionType::attendance => "attendance",
SubmissionType::basic_lti_launch => "basic_lti_launch",
SubmissionType::discussion_topic => "discussion_topic",
SubmissionType::external_tool => "external_tool",
SubmissionType::media_recording => "media_recording",
SubmissionType::none => "none",
SubmissionType::not_graded => "not_graded",
SubmissionType::on_paper => "on_paper",
SubmissionType::online_quiz => "online_quiz",
SubmissionType::online_text_entry => "online_text_entry",
SubmissionType::online_upload => "online_upload",
SubmissionType::online_url => "online_url",
SubmissionType::student_annotation => "student_annotation",
SubmissionType::wiki_page => "wiki_page",
SubmissionType::Other(ref s) => &s,
})
}
}
impl<'de> ::serde::Deserialize<'de> for SubmissionType {
fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s: String = ::serde::Deserialize::deserialize(deserializer)?;
match s.as_str() {
"attendance" => Ok(SubmissionType::attendance),
"basic_lti_launch" => Ok(SubmissionType::basic_lti_launch),
"discussion_topic" => Ok(SubmissionType::discussion_topic),
"external_tool" => Ok(SubmissionType::external_tool),
"media_recording" => Ok(SubmissionType::media_recording),
"none" => Ok(SubmissionType::none),
"not_graded" => Ok(SubmissionType::not_graded),
"on_paper" => Ok(SubmissionType::on_paper),
"online_quiz" => Ok(SubmissionType::online_quiz),
"online_text_entry" => Ok(SubmissionType::online_text_entry),
"online_upload" => Ok(SubmissionType::online_upload),
"online_url" => Ok(SubmissionType::online_url),
"student_annotation" => Ok(SubmissionType::student_annotation),
"wiki_page" => Ok(SubmissionType::wiki_page),
_ => Ok(SubmissionType::Other(s)),
}
}
}
#[derive(Serialize)]
pub struct Variables;
#[derive(Deserialize)]
pub struct ResponseData {
#[serde(rename = "allCourses")]
pub all_courses: Option<Vec<GetCourseAssignmentsAllCourses>>,
}
#[derive(Deserialize)]
pub struct GetCourseAssignmentsAllCourses {
#[serde(rename = "_id")]
pub id: ID,
#[serde(rename = "courseCode")]
pub course_code: Option<String>,
#[serde(rename = "assignmentGroups")]
pub assignment_groups: Option<Vec<GetCourseAssignmentsAllCoursesAssignmentGroups>>,
}
#[derive(Deserialize)]
pub struct GetCourseAssignmentsAllCoursesAssignmentGroups {
#[serde(rename = "assignmentsConnection")]
pub assignments_connection:
Option<GetCourseAssignmentsAllCoursesAssignmentGroupsAssignmentsConnection>,
}
#[derive(Deserialize)]
pub struct GetCourseAssignmentsAllCoursesAssignmentGroupsAssignmentsConnection {
pub nodes: Option<
Vec<Option<GetCourseAssignmentsAllCoursesAssignmentGroupsAssignmentsConnectionNodes>>,
>,
}
#[derive(Deserialize)]
pub struct GetCourseAssignmentsAllCoursesAssignmentGroupsAssignmentsConnectionNodes {
pub _id: ID,
pub id: ID,
pub name: Option<String>,
#[serde(rename = "submissionTypes")]
pub submission_types: Option<Vec<SubmissionType>>,
}
}
impl graphql_client::GraphQLQuery for GetCourseAssignments {
type Variables = get_course_assignments::Variables;
type ResponseData = get_course_assignments::ResponseData;
fn build_query(variables: Self::Variables) -> ::graphql_client::QueryBody<Self::Variables> {
graphql_client::QueryBody {
variables,
query: get_course_assignments::QUERY,
operation_name: get_course_assignments::OPERATION_NAME,
}
}
}

3
src/types/README.md Normal file
View file

@ -0,0 +1,3 @@
# GraphQL types
This module is auto-generated with graphql_client_cli, running `for f in ./graphql/queries/*.graphql; do graphql-client generate -d warn -o src/types -s ./graphql/canvas-schema.json $f; done` to generate rust types for each query. Unfortunately, due to there being `id` and `_id` fields in the same type, a manual adjust of the incorrectly-renamed `_id` field is necessary for any types that have both fields.

2
src/types/mod.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod CreateSubmission;
pub mod GetCourseAssignments;