chawk

package module
v0.8.16 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 17, 2026 License: MIT Imports: 13 Imported by: 0

README

Chawk

A Go client for the Blackboard REST API designed to make common admin tasks like managing users, enrollments, and course data easier to automate.

[!WARNING]
This project is a work in progress.

Setup

You will need to create an application to get the needed keys. You can request access to the Blackboard REST APIs through the Developer Portal.

Example of using the library

Installing
go get codeberg.org/sugarvoid/chawk
Creating a client
clientID := "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
clientSecret := "xxxxxxxxxxxxxxxxxxxxxxxxx"
baseURL := "https://blackboard.xxxx.edu"
ctx, cancel := context.WithTimeout(context.Background(), 6*time.Second)
defer cancel()

client, err := chawk.NewClient(clientID, clientSecret, baseURL)
if err != nil {
    fmt.Printf("Failed to create BlackboardClient: %v", err)
} 
Updating a user
update := chawk.UserUpdate{
    Name:    &chawk.NameUpdate{ Family: chawk.ToPtr("Smith") },
    Contact: &chawk.ContactUpdate{ Email: chawk.ToPtr("jsmith@univ.edu") },
    InstitutionRoleIDs: []string{"FACULTY"},
}

err := client.Users.Update(ctx, "jdoe", update)

// or use the convenience method

err = client.Users.UpdateEmail(ctx, "jdoe", "jsmith@univ.edu")

Documentation

Overview

This file contains internal utilities for sanitizing and validating user-provided input for data integrity before sending requests to the API.

Index

Constants

View Source
const (
	AvailabilityYes      string = "Yes"
	AvailabilityNo       string = "No"
	AvailabilityDisabled string = "Disabled"

	RoleStudent    string = "Student"
	RoleInstructor string = "Instructor"
	RoleTA         string = "TeachingAssistant"

	// These may not be universal..
	// Will need to check at some point
	RoleCourseBuilder string = "CourseBuilder"
	RoleFacilitator   string = "BbFacilitator"
	RoleSpectator     string = "BbSpectator"
	RoleGrader        string = "Grader"
	RoleGuest         string = "Guest"
)
View Source
const (
	HTTP_TIMEOUT_SECS = 10
)

Variables

View Source
var (
	ErrInsufficientPrivileges = errors.New("insufficient privileges")
	ErrClientInitError        = errors.New("clientID, clientSecret, and baseURL are required")
	ErrTokenExpired           = errors.New("token expired")
	ErrTokenMissing           = errors.New("token file missing")
)
View Source
var ErrCourseExist = errors.New("course already exists")
View Source
var ErrCourseNotFound = errors.New("course doesn't exist")

Course

View Source
var ErrEmptyStringParameter = errors.New("there is a parameter that is empty string")

Client

View Source
var ErrInvalidRole = errors.New("invalid course role")
View Source
var ErrInvalidUsername = errors.New("invalid username")
View Source
var ErrMissingName = errors.New("missing first and last name")
View Source
var ErrUserAlreadyEnrolled = errors.New("user already enrolled in course, use UpdateMembership() if needed")
View Source
var ErrUserExist = errors.New("user already exists")
View Source
var ErrUserNotFound = errors.New("user account doesn't exist")

User

Functions

func OptionalString

func OptionalString(value string) string

OptionalString trims whitespace from a string. Unlike RequiredString, it returns the trimmed value even if it is empty, without an error.

Use this for non-mandatory fields where a blank value is acceptable like user's email

func RequiredString

func RequiredString(value string, fieldName string) (string, error)

RequiredString trims leading and trailing whitespace from a string and returns an error if the resulting string is empty.

Use this for mandatory fields like usernames and courseIDs.

func ToPtr

func ToPtr[T any](v T) *T

Ptr is a helper that returns a pointer to the value passed in. This is particularly useful for filling out "omitempty" pointer fields in update structs without needing to declare local variables.

Types

type Address

type Address struct {
	Street1 string `json:"street1,omitempty"`
	Street2 string `json:"street2,omitempty"`
	City    string `json:"city,omitempty"`
	State   string `json:"state,omitempty"`
	ZipCode string `json:"zipCode,omitempty,omitempty"`
	Country string `json:"country,omitempty,omitempty"`
}

type Announcement

type Announcement struct {
	ID            string                   `json:"id"`
	Title         string                   `json:"title"`
	Body          string                   `json:"body"`
	Draft         bool                     `json:"draft"`
	Availability  AnnouncementAvailability `json:"availability"`
	CreatorUserID string                   `json:"creatorUserId"`
	Created       string                   `json:"created"`
	Modified      string                   `json:"modified"`
	Position      int                      `json:"position"`
	Creator       string                   `json:"creator"`
}

type AnnouncementAvailability

type AnnouncementAvailability struct {
	Duration Duration `json:"duration"`
}

type AnnouncementService

type AnnouncementService struct {
	// contains filtered or unexported fields
}

func (*AnnouncementService) DeleteAllAnnouncements

func (c *AnnouncementService) DeleteAllAnnouncements(ctx context.Context, courseID string) error

func (*AnnouncementService) DeleteAnnouncement

func (c *AnnouncementService) DeleteAnnouncement(ctx context.Context, courseID string, announcementID string) error

func (*AnnouncementService) GetAllAnnouncements

func (c *AnnouncementService) GetAllAnnouncements(ctx context.Context, courseID string) ([]Announcement, error)

GetAllAnnouncements returns all the announcements from a course

func (*AnnouncementService) GetAnnouncement

func (c *AnnouncementService) GetAnnouncement(ctx context.Context, courseID string, announcementID string) (Announcement, error)

GetAnnouncement get a single announcement by its ID

func (*AnnouncementService) UpdateAnnouncement

func (c *AnnouncementService) UpdateAnnouncement(ctx context.Context, courseID string, announcementID string) error

type Avatar

type Avatar struct {
	Source     string `json:"source,omitempty"`
	UploadID   string `json:"uploadId,omitempty"`
	ResourceID string `json:"resourceId,omitempty"`
}

type BlackboardClient

type BlackboardClient struct {
	BaseURL string

	UserAgent string

	// Sub Services
	// TODO: Rename Service to Client
	Users        *UserService
	Courses      *CourseService
	Announcement *AnnouncementService
	Gradebook    *GradebookService
	Discussion   *DiscussionService
	// contains filtered or unexported fields
}

func NewClient

func NewClient(clientID, clientSecret, baseURL string) (*BlackboardClient, error)

NewClient initializes and returns a new Blackboard API Client. It requires a Client ID and Client Secret obtained from the Blackboard Developer Portal.

func (*BlackboardClient) Delete

func (c *BlackboardClient) Delete(ctx context.Context, path string) (*http.Response, error)

func (*BlackboardClient) Get

func (c *BlackboardClient) Get(ctx context.Context, path string) (*http.Response, error)

func (*BlackboardClient) GetRemainingCalls

func (c *BlackboardClient) GetRemainingCalls(ctx context.Context) (int, error)

GetRemainingCalls returns the number of apis calls left of the key. This does consume a call.

func (*BlackboardClient) Patch

func (c *BlackboardClient) Patch(ctx context.Context, path string, jsonBody interface{}) (*http.Response, error)

func (*BlackboardClient) Post

func (c *BlackboardClient) Post(ctx context.Context, path string, jsonBody interface{}) (*http.Response, error)

func (*BlackboardClient) Put

func (c *BlackboardClient) Put(ctx context.Context, path string, jsonBody interface{}) (*http.Response, error)

type ColumnAvailability

type ColumnAvailability struct {
	Available string `json:"available"`
}

type ColumnScore

type ColumnScore struct {
	Possible float64 `json:"possible"`
}

type Contact

type Contact struct {
	HomePhone        string `json:"homePhone,omitempty"`
	MobilePhone      string `json:"mobilePhone,omitempty"`
	BusinessPhone    string `json:"businessPhone,omitempty"`
	BusinessFax      string `json:"businessFax,omitempty"`
	Email            string `json:"email,omitempty"`
	InstitutionEmail string `json:"institutionEmail,omitempty"`
	WebPage          string `json:"webPage,omitempty"`
}

type ContactUpdate

type ContactUpdate struct {
	Email            *string `json:"email,omitempty"`
	InstitutionEmail *string `json:"institutionEmail,omitempty"`
}

type CopyHistory

type CopyHistory struct {
	UUID string `json:"uuid,omitempty"`
}

type Course

type Course struct {
	// Required for creation
	CourseID string `json:"courseId"`
	Name     string `json:"name"`
	TermID   string `json:"termId"`

	// Optional for creation
	Description    string             `json:"description,omitempty"`
	Availability   CourseAvailability `json:"availability"`
	Organization   bool               `json:"organization,omitempty"`
	UltraStatus    string             `json:"ultraStatus,omitempty"`
	AllowGuests    bool               `json:"allowGuests,omitempty"`
	AllowObservers bool               `json:"allowObservers"`
	ClosedComplete bool               `json:"closedComplete"`
	Enrollment     Enrollment         `json:"enrollment,omitzero"`
	Locale         CourseLocale       `json:"locale,omitzero"`

	// Read-only (set by server, ignored on create)
	ID           string     `json:"id,omitempty"`
	UUID         string     `json:"uuid,omitempty"`
	Created      *time.Time `json:"created,omitempty"`
	Modified     *time.Time `json:"modified,omitempty"`
	ExternalID   string     `json:"externalId,omitempty"`
	DataSourceID string     `json:"dataSourceId,omitempty"`

	// Stuff Populated on GET'ing
	HasChildren       bool          `json:"hasChildren,omitempty"`
	ParentID          string        `json:"parentId,omitempty"`
	ExternalAccessURL string        `json:"externalAccessUrl,omitempty"`
	GuestAccessURL    string        `json:"guestAccessUrl,omitempty"`
	CopyHistory       []CopyHistory `json:"copyHistory"`
	IsChild           bool          `json:"-"`
}

type CourseAvailability

type CourseAvailability struct {
	Available string         `json:"available"`
	Duration  CourseDuration `json:"duration,omitzero"`
}

type CourseCreateRequest

type CourseCreateRequest struct {
	Name         *string             `json:"name,omitempty"`
	ExternalID   *string             `json:"termId,omitempty"`
	TermID       *string             `json:"externalId,omitempty"`
	Availability *CourseAvailability `json:"availability,omitempty"`
	DataSourceID *string             `json:"dataSourceId,omitempty"`
	Description  *string             `json:"description,omitempty"`
}

type CourseDuration

type CourseDuration struct {
	Type      string    `json:"type,omitempty"`
	Start     time.Time `json:"start,omitzero"`
	End       time.Time `json:"end,omitzero"`
	DaysOfUse int       `json:"daysOfUse,omitempty"`
}

type CourseEnrollment

type CourseEnrollment struct {
	CourseID     string
	ExternalID   string
	CourseRoleID string
	Created      time.Time
	Name         string
}

type CourseLocale

type CourseLocale struct {
	ID    string `json:"id,omitempty"`
	Force bool   `json:"force,omitempty"`
}

type CourseMembership

type CourseMembership struct {
	ID            string                  `json:"id,omitempty"`
	ChildCourseID *string                 `json:"childCourseId,omitempty"`
	UserID        string                  `json:"userId,omitempty"`
	CourseID      string                  `json:"courseId,omitempty"`
	DataSourceID  string                  `json:"dataSourceId,omitempty"`
	Created       time.Time               `json:"created,omitempty"`
	Modified      time.Time               `json:"modified,omitempty"`
	CourseRoleID  *string                 `json:"courseRoleId"`
	Availability  *MembershipAvailability `json:"availability,omitempty"`
	User          *User                   `json:"user,omitempty"`
}

type CourseService

type CourseService struct {
	// contains filtered or unexported fields
}

func (*CourseService) AddChildCourse

func (cs *CourseService) AddChildCourse(ctx context.Context, courseID string, childID string) error

func (*CourseService) CopyCourseByCourseID

func (cs *CourseService) CopyCourseByCourseID(ctx context.Context, sourceID, destinationID string) (string, error)

TODO: Rename parameters

func (*CourseService) Create

func (cs *CourseService) Create(ctx context.Context, courseID string, title string, termID string) (*Course, error)

Create function that only needs the bare minimum. For simple creates.

func (*CourseService) CreateMembership

func (cs *CourseService) CreateMembership(ctx context.Context, username, courseID string, update EnrollmentRequest) error

func (*CourseService) CreatePro

func (cs *CourseService) CreatePro(ctx context.Context, req *CourseCreateRequest) (*Course, error)

A more advanced version of Create()

func (*CourseService) DeleteCourse

func (cs *CourseService) DeleteCourse(ctx context.Context, courseID string) error

Tested 11/4/25

func (*CourseService) DoesCourseExist

func (cs *CourseService) DoesCourseExist(ctx context.Context, courseID string) (bool, error)

func (*CourseService) EnrollUserIntoCourse

func (cs *CourseService) EnrollUserIntoCourse(ctx context.Context, courseID string, username string, role string, availability string) error

EnrollUserIntoCourse is a wrapper function that calls CreateMembership.

func (*CourseService) GetCourseByCourseId

func (cs *CourseService) GetCourseByCourseId(ctx context.Context, courseID string) (*Course, error)

func (*CourseService) GetCourseById

func (cs *CourseService) GetCourseById(ctx context.Context, id string) (*Course, error)

func (*CourseService) GetMembershipByID

func (cs *CourseService) GetMembershipByID(ctx context.Context, userID string, courseID string) (*CourseMembership, error)

func (*CourseService) GetMembershipByUsername

func (cs *CourseService) GetMembershipByUsername(ctx context.Context, username string, courseID string) (*CourseMembership, error)

func (*CourseService) GetUsers

func (cs *CourseService) GetUsers(ctx context.Context, courseID string) ([]CourseUser, error)

func (*CourseService) RemoveUser

func (cs *CourseService) RemoveUser(ctx context.Context, courseID string, username string) error

RemoveUser will remove a user from a course.

func (*CourseService) Update

func (cs *CourseService) Update(ctx context.Context, courseID string, req *CourseUpdateRequest) (*Course, error)

func (*CourseService) UpdateMembership

func (cs *CourseService) UpdateMembership(ctx context.Context, username, courseID string, update EnrollmentRequest) error

func (*CourseService) UpdateMembershipAvailability

func (cs *CourseService) UpdateMembershipAvailability(ctx context.Context, username string, courseID string, availability string) error

type CourseUpdateRequest

type CourseUpdateRequest struct {
	Name         *string             `json:"name,omitempty"`
	TermID       *string             `json:"termId,omitempty"`
	Availability *CourseAvailability `json:"availability,omitempty"`
	DataSourceID *string             `json:"dataSourceId,omitempty"`
	Description  *string             `json:"description,omitempty"`
}

type CourseUser

type CourseUser struct {
	ID           string
	UserName     string
	FirstName    string
	LastName     string
	Available    string
	CourseRoleID string
}

type CreateResult

type CreateResult struct {
	Created []string
	Failed  []FailedOperation
}

func (CreateResult) Error

func (r CreateResult) Error() string

func (CreateResult) HasErrors

func (r CreateResult) HasErrors() bool

func (CreateResult) Summary

func (r CreateResult) Summary() string

type DeleteResult

type DeleteResult struct {
	Deleted []string
	Failed  []FailedOperation
}

func (DeleteResult) Error

func (r DeleteResult) Error() string

func (DeleteResult) HasErrors

func (r DeleteResult) HasErrors() bool

func (DeleteResult) Summary

func (r DeleteResult) Summary() string

type DiscussionService

type DiscussionService struct {
	// contains filtered or unexported fields
}

func (*DiscussionService) DeleteStudentReplies

func (d *DiscussionService) DeleteStudentReplies(ctx context.Context, courseID string) (DeleteResult, error)

ClearDiscussionStudentReplies deletes all posts where author is a student.

type Duration

type Duration struct {
	Type  *string `json:"type"`
	Start *string `json:"start"`
	End   *string `json:"end"`
}

type Enrollment

type Enrollment struct {
	Type       string    `json:"type,omitempty"`
	Start      time.Time `json:"start,omitzero"`
	End        time.Time `json:"end,omitzero"`
	AccessCode string    `json:"accessCode,omitempty"`
}

type EnrollmentRequest

type EnrollmentRequest struct {
	ChildCourseID *string                 `json:"childCourseId,omitempty"`
	DataSourceID  *string                 `json:"dataSourceId,omitempty"`
	Availability  *MembershipAvailability `json:"availability,omitempty"`
	CourseRoleID  *string                 `json:"courseRoleId,omitempty"`
	DisplayOrder  *int                    `json:"displayOrder,omitempty"`
}

type FailedOperation

type FailedOperation struct {
	ID  string
	Err error
}

type GradebookColumn

type GradebookColumn struct {
	ID                       string             `json:"id,omitempty"`
	ExternalID               string             `json:"externalId,omitempty"`
	Name                     string             `json:"name,omitempty"`
	DisplayName              string             `json:"displayName,omitempty"`
	Description              string             `json:"description,omitempty"`
	Created                  string             `json:"created,omitempty"`
	Modified                 string             `json:"modified,omitempty"`
	Score                    ColumnScore        `json:"score,omitzero"`
	Availability             ColumnAvailability `json:"availability,omitzero"`
	Grading                  GradebookGrading   `json:"grading,omitzero"`
	IncludeInCalculations    bool               `json:"includeInCalculations,omitempty"`
	ShowStatisticsToStudents bool               `json:"showStatisticsToStudents,omitempty"`
}

type GradebookGrading

type GradebookGrading struct {
	Type            string `json:"type,omitempty"`
	Due             string `json:"due,omitempty"`
	AttemptsAllowed int    `json:"attemptsAllowed,omitempty"`
	ScoringModel    string `json:"scoringModel,omitempty"`
}

type GradebookService

type GradebookService struct {
	// contains filtered or unexported fields
}

func (*GradebookService) CreateColumn

func (gs *GradebookService) CreateColumn(ctx context.Context, courseID, name, description string, score float64) error

func (*GradebookService) CreateColumnPro

func (gs *GradebookService) CreateColumnPro(ctx context.Context, courseID string, column GradebookColumn) error

func (*GradebookService) DeleteColumn

func (gs *GradebookService) DeleteColumn(ctx context.Context, courseID string, columnID string) error

func (*GradebookService) DeleteColumns

func (gs *GradebookService) DeleteColumns(ctx context.Context, courseID string) error

func (*GradebookService) GetColumn

func (gs *GradebookService) GetColumn(ctx context.Context, courseID string, columnID string) (*GradebookColumn, error)

func (*GradebookService) GetColumns

func (gs *GradebookService) GetColumns(ctx context.Context, courseID string) ([]GradebookColumn, error)

func (*GradebookService) UpdateColumnPro

func (gs *GradebookService) UpdateColumnPro(ctx context.Context, courseID string, columnID string) error

func (*GradebookService) UpdateColumnValue

func (gs *GradebookService) UpdateColumnValue(ctx context.Context, courseID string, columnID string) error

type Job

type Job struct {
	Title      string `json:"title,omitempty"`
	Department string `json:"department,omitempty"`
	Company    string `json:"company,omitempty"`
}

type Locale

type Locale struct {
	ID             string  `json:"id,omitempty"`
	Calendar       *string `json:"calendar,omitempty"`
	FirstDayOfWeek *string `json:"firstDayOfWeek,omitempty"`
}

type MembershipAvailability

type MembershipAvailability struct {
	Available *string `json:"available,omitempty"`
}

type Name

type Name struct {
	Given                string `json:"given,omitempty"`
	Family               string `json:"family,omitempty"`
	Middle               string `json:"middle,omitempty"`
	Other                string `json:"other,omitempty"`
	Suffix               string `json:"suffix,omitempty"`
	Title                string `json:"title,omitempty"`
	PreferredDisplayName string `json:"preferredDisplayName,omitempty"`
}

type NameUpdate

type NameUpdate struct {
	Given  *string `json:"given,omitempty"`
	Family *string `json:"family,omitempty"`
}

type PronunciationAudio

type PronunciationAudio struct {
	UploadID string `json:"uploadId,omitempty"`
}

type Token

type Token struct {
	AccessToken  string    `json:"access_token"`
	TokenType    string    `json:"token_type"`
	RefreshToken string    `json:"refresh_token,omitempty"`
	ExpiresIn    int64     `json:"expires_in"`
	Expiry       time.Time `json:"expiry"`
}

func (*Token) IsExpired

func (t *Token) IsExpired() bool

type UpdateResult

type UpdateResult struct {
	Updated []string
	Failed  []FailedOperation
}

func (UpdateResult) Error

func (r UpdateResult) Error() string

func (UpdateResult) HasErrors

func (r UpdateResult) HasErrors() bool

func (UpdateResult) Summary

func (r UpdateResult) Summary() string

type User

type User struct {
	ID                 string             `json:"id,omitempty"`
	UUID               string             `json:"uuid,omitempty"`
	ExternalID         string             `json:"externalId,omitempty"`
	DataSourceID       string             `json:"dataSourceId,omitempty"`
	UserName           string             `json:"userName"`
	StudentID          string             `json:"studentId,omitempty"`
	Password           string             `json:"password,omitempty"`
	EducationLevel     string             `json:"educationLevel,omitempty"`
	Gender             string             `json:"gender,omitempty"`
	Pronouns           string             `json:"pronouns,omitempty"`
	BirthDate          *time.Time         `json:"birthDate,omitempty"`
	InstitutionRoleIDs []string           `json:"institutionRoleIds"`
	SystemRoleIDs      []string           `json:"systemRoleIds,omitempty"`
	Availability       UserAvailability   `json:"availability,omitzero"`
	Name               Name               `json:"name,omitzero"`
	Job                Job                `json:"job,omitzero"`
	Contact            Contact            `json:"contact,omitzero"`
	Address            Address            `json:"address,omitzero"`
	Locale             Locale             `json:"locale,omitzero"`
	Avatar             Avatar             `json:"avatar,omitzero"`
	Pronunciation      string             `json:"pronunciation,omitempty"`
	PronunciationAudio PronunciationAudio `json:"pronunciationAudio,omitzero"`
}

type UserAvailability

type UserAvailability struct {
	Available string `json:"available"`
}

type UserService

type UserService struct {
	// contains filtered or unexported fields
}

func (*UserService) AddInstitutionRoles

func (us *UserService) AddInstitutionRoles(ctx context.Context, username string, roles []string) error

func (*UserService) CreateUser

func (us *UserService) CreateUser(ctx context.Context, username string, fName string, lName string, email string, password string) error

func (*UserService) Delete

func (us *UserService) Delete(ctx context.Context, username string) error

func (*UserService) DoesUserExist

func (s *UserService) DoesUserExist(ctx context.Context, username string) (bool, error)

func (*UserService) GetCourses

func (us *UserService) GetCourses(ctx context.Context, username string) ([]CourseEnrollment, error)

func (*UserService) GetUserByUsername

func (us *UserService) GetUserByUsername(ctx context.Context, username string) (*User, error)

GetUserObject fetches user data and maps to User struct

func (*UserService) Update

func (us *UserService) Update(ctx context.Context, username string, update UserUpdate) error

func (*UserService) UpdateEmail

func (us *UserService) UpdateEmail(ctx context.Context, username, newEmail string) error

func (*UserService) UpdateInstitutionEmail

func (us *UserService) UpdateInstitutionEmail(ctx context.Context, username, newEmail string) error

func (*UserService) UpdateName

func (us *UserService) UpdateName(ctx context.Context, username, fName, lName string) error

func (*UserService) UpdatePassword

func (us *UserService) UpdatePassword(ctx context.Context, username, newPassword string) error

func (*UserService) UpdateUserAvailability

func (us *UserService) UpdateUserAvailability(ctx context.Context, username string, availability string) error

type UserUpdate

type UserUpdate struct {
	Contact            *ContactUpdate    `json:"contact,omitempty"`
	Name               *NameUpdate       `json:"name,omitempty"`
	Password           *string           `json:"password,omitempty"`
	InstitutionRoleIDs []string          `json:"institutionRoleIds,omitempty"`
	Availability       *UserAvailability `json:"availability,omitempty"`
}

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL