diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 5ac025f..95a5cb9 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -5,9 +5,11 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 + - name: Install modules run: yarn + - name: Run ESLint run: yarn run lint @@ -17,4 +19,4 @@ jobs: slack_hook_url: ${{ secrets.SLACK_WEBHOOK_URL }} message: " for ${{ github.repository }} by ${{ github.actor }} has ${{ job.status }} on branch ${{ github.ref }}" success: ${{ job.status }} - if: always() \ No newline at end of file + if: always() diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index fe71b61..c73ca4b 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -8,11 +8,13 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v5 + + - uses: actions/setup-node@v6 with: node-version: '16.x' registry-url: 'https://registry.npmjs.org' + - run: yarn && yarn build - uses: JS-DevTools/npm-publish@v1 diff --git a/.gitignore b/.gitignore index 1de3458..ca567e2 100644 --- a/.gitignore +++ b/.gitignore @@ -106,3 +106,5 @@ dist /lib *.iml +*.ipr +*.iws diff --git a/README.md b/README.md index 3d12e8c..f8fbabd 100644 --- a/README.md +++ b/README.md @@ -140,11 +140,16 @@ return `Course` object Course = { id: string, name: string, + description?: string, modules: Module[], assignments: Assignment[], creationDate: Date, - archivedDate?: Date, - archived: boolen + archivedDate: Date, + archived: boolean, + start?: Date, + end?: Date, + timezone?: string, + tags?: string[] } Module = { id: string, @@ -169,8 +174,16 @@ return `Course` object Course = { id: string, name: string, + description?: string, modules: Module[], - assignments: Assignment[] + assignments: Assignment[], + creationDate: Date, + archivedDate: Date, + archived: boolean, + start?: Date, + end?: Date, + timezone?: string, + tags?: string[] } Module = { id: string, @@ -271,6 +284,71 @@ Fetch course teachers ``` returns user `User[]` object +Add teacher to course + +``` + await codio.v1.course.addTeacher(courseId, userId, readOnly?) +``` +- `readOnly` (optional, default `false`): when `true`, the user is added as a read‑only teacher. +- returns `boolean` — true if the teacher was successfully added + +Example: +```javascript +// Add full teacher (default) +await codio.v1.course.addTeacher(courseId, userId) + +// Add read-only teacher +await codio.v1.course.addTeacher(courseId, userId, true) +``` + +#### Course management + +Create course + +``` + await codio.v1.course.createCourse(courseData) +``` +Parameters: +``` +CreateCourseRequest = { + name: string, + description?: string, + start?: string, + end?: string, + timezone?: string, + tags?: string[] +} +``` +Notes: +- `start` and `end` are ISO 8601 strings (e.g., `2025-09-01T13:00:00Z`). +- `timezone` should be an IANA timezone name (e.g., `America/New_York`). +- In responses, `Course.start` is a `Date` (or absent), while `CreateCourseRequest.start` is a string. +returns `string` — newly created courseId + +Example: +```javascript +const courseId = await codio.v1.course.createCourse({ + name: 'Intro to CS', + description: 'Fall 2025 section', + start: '2025-09-01T13:00:00Z', // ISO 8601 string + end: '2025-12-20T23:59:59Z', // ISO 8601 string + timezone: 'America/New_York', + tags: ['CS101','Fall-2025'] +}) +``` + +Create module + +``` + await codio.v1.course.createModule(courseId, moduleName) +``` +returns `string` — newly created moduleId + +Example: +```javascript +const moduleId = await codio.v1.course.createModule(courseId, 'Module 1: Basics') +``` + #### Export student CSV @@ -509,7 +587,7 @@ returns `AssignmentSettings` - Settings, missed properties won't be updated const settings = await codio.assignment.getSettings('', '') ``` -```javascript +``` enableResetAssignmentByStudent?: boolean disableDownloadByStudent?: boolean visibilityOnDisabled?: string, // "READ_ONLY", "NO_ACCESS", @@ -575,7 +653,7 @@ Set time limits on a per-student basis ```javascript await codio.assignment.updateStudentTimeExtension(courseId, assignmentId, studentId, { - extendedDeadline: minutes + extendedDeadline: minutes, extendedTimeLimit: minutes }) ``` diff --git a/examples/course/addTeacher.js b/examples/course/addTeacher.js new file mode 100644 index 0000000..ae65f5b --- /dev/null +++ b/examples/course/addTeacher.js @@ -0,0 +1,13 @@ +const { codio, auth } = require('../auth.js') +const { courseId, userIdToAdd } = require('../data.js') + +async function main() { + await auth + + // Add the user as a read-only teacher (third param is optional; default is false) + const result = await codio.course.addTeacher(courseId, userIdToAdd, true) + console.log(result) + +} + +main() diff --git a/examples/data.js b/examples/data.js index 2131e89..0100f91 100644 --- a/examples/data.js +++ b/examples/data.js @@ -43,5 +43,26 @@ const assignmentData = { } } } +const userIdToAdd = "your user id" -module.exports = { courseId, courseName, assignmentId, studentId, studentEmail, studentLogin, libraryId, libraryName, projectPath, stackId, stackVersionId, archivePath, yamlMapDir, courseIdToArchive, leanersMapping, moduleName, courseData, assignmentData } +module.exports = { + courseId, + courseName, + assignmentId, + studentId, + studentEmail, + studentLogin, + libraryId, + libraryName, + projectPath, + stackId, + stackVersionId, + archivePath, + yamlMapDir, + courseIdToArchive, + leanersMapping, + moduleName, + courseData, + assignmentData, + userIdToAdd +} diff --git a/package.json b/package.json index 129fdb8..bf69fcf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codio-api-js", - "version": "0.16.0", + "version": "0.17.0", "description": "JS client to Codio API", "repository": "https://github.com/codio/codio-api-js", "author": "Max Kraev ", diff --git a/src/lib/course.ts b/src/lib/course.ts index fef4b43..d77321e 100644 --- a/src/lib/course.ts +++ b/src/lib/course.ts @@ -21,11 +21,16 @@ export type Module = { export type Course = { id: string name: string + description: string | undefined modules: Module[] assignments: Assignment[] creationDate: Date archivedDate: Date archived: boolean + start: Date | undefined + end: Date | undefined + timezone: string | undefined + tags: string[] | undefined } export type StudentProgress = { @@ -94,6 +99,12 @@ function flattenAssignments(course: any) { if (course.archivedDate) { course.archivedDate = new Date(course.archivedDate) } + if (course.start) { + course.start = new Date(course.start) + } + if (course.end) { + course.end = new Date(course.end) + } } export async function info(courseId: string, withHiddenAssignments = true): Promise { @@ -625,6 +636,25 @@ export async function createModule(courseId: string, moduleName: string): Promis } } +export async function addTeacher(courseId: string, userId: string, readOnly = false): Promise { + const api = bent(getApiV1Url(), 'POST', 'json', 200) + try { + const body = { userId: userId, readOnly: readOnly } + const res = await api(`/courses/${courseId}/teachers`, body, getBearer()) + const completed = res['completed'] + if (!completed) { + throw new Error('Something went wrong') + } + return completed + } catch (error: any) { + if (error.json) { + const message = JSON.stringify(await error.json()) + throw new Error(message) + } + throw error + } +} + const course = { assignmentStudentsProgress, info, @@ -654,7 +684,8 @@ const course = { exportLLMProxyData, filterLearnersForMentors, createCourse, - createModule + createModule, + addTeacher } export default course