Skip to content

Commit a56519c

Browse files
committed
feat: add logic for the integration of brightspace courses
1 parent 8855b74 commit a56519c

File tree

3 files changed

+238
-27
lines changed

3 files changed

+238
-27
lines changed

provider-middleware/brightspace.go

+77-14
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,21 @@ package main
22

33
import (
44
"UnlockEdv2/src/models"
5+
"encoding/json"
56
"errors"
7+
"fmt"
68
"net/http"
79
"net/url"
810
"os"
911
"strings"
1012
"time"
1113

14+
log "github.com/sirupsen/logrus"
1215
"gorm.io/gorm"
1316
)
1417

1518
const (
19+
CsvDownloadPath = "csvs"
1620
TokenEndpoint = "https://auth.brightspace.com/core/connect/token"
1721
DataSetsEndpoint = "https://unlocked.brightspacedemo.com/d2l/api/lp/1.28/dataExport/bds/list"
1822
DataDownloadEnpoint = "https://unlocked.brightspacedemo.com/d2l/api/lp/1.28/dataExport/bds/download/%s"
@@ -31,8 +35,7 @@ type BrightspaceService struct {
3135
JobParams *map[string]interface{}
3236
}
3337

34-
// for linting reasons changed new to New below temporarily so this can be reviewed,
35-
func NewBrightspaceService(provider *models.ProviderPlatform, db *gorm.DB, params *map[string]interface{}) (*BrightspaceService, error) {
38+
func newBrightspaceService(provider *models.ProviderPlatform, db *gorm.DB, params *map[string]interface{}) (*BrightspaceService, error) {
3639
keysSplit := strings.Split(provider.AccessKey, ";")
3740
if len(keysSplit) < 2 {
3841
return nil, errors.New("unable to find refresh token, unable to intialize BrightspaceService")
@@ -42,23 +45,50 @@ func NewBrightspaceService(provider *models.ProviderPlatform, db *gorm.DB, param
4245
return nil, errors.New("no brightspace scope found, unable to intialize BrightspaceService")
4346
}
4447
brightspaceService := BrightspaceService{
45-
//brightspace - set fields
46-
JobParams: params,
48+
ProviderPlatformID: provider.ID,
49+
Client: &http.Client{},
50+
BaseURL: provider.BaseUrl,
51+
ClientID: provider.AccountID,
52+
ClientSecret: keysSplit[0],
53+
RefreshToken: keysSplit[1],
54+
Scope: scope,
55+
JobParams: params,
4756
}
4857
data := url.Values{}
4958
data.Add("grant_type", "refresh_token")
5059
data.Add("refresh_token", brightspaceService.RefreshToken)
5160
data.Add("client_id", brightspaceService.ClientID)
5261
data.Add("client_secret", brightspaceService.ClientSecret)
5362
data.Add("scope", brightspaceService.Scope)
54-
//a send post request to brightspace
55-
//b parse response for access_token and refresh_token
56-
//c save new refresh_token (tack it onto the end of the client secret separated by semicolon)
63+
log.Infof("refreshing token using endpoint url %v", TokenEndpoint)
64+
resp, err := brightspaceService.SendPostRequest(TokenEndpoint, data)
65+
if err != nil {
66+
log.Errorf("error sending post request to url %v", TokenEndpoint)
67+
return nil, err
68+
}
69+
var tokenMap map[string]interface{}
70+
if err := json.NewDecoder(resp.Body).Decode(&tokenMap); err != nil {
71+
log.Errorf("error decoding to response from url %v, error is: %v", TokenEndpoint, err)
72+
return nil, err
73+
}
74+
if resp.StatusCode != http.StatusOK {
75+
errType, okError := tokenMap["error"].(string)
76+
errMsg, okDesc := tokenMap["error_description"].(string)
77+
msg := "unable to request new refresh token from brightspace"
78+
if okError && okDesc {
79+
msg = fmt.Sprintf("unable to request new refresh token from brightspace, response error message is: %s: %s", errType, errMsg)
80+
return nil, errors.New(msg)
81+
}
82+
return nil, errors.New(msg)
83+
}
84+
brightspaceService.AccessToken = tokenMap["access_token"].(string)
85+
brightspaceService.RefreshToken = tokenMap["refresh_token"].(string)
5786
provider.AccessKey = brightspaceService.ClientSecret + ";" + brightspaceService.RefreshToken
58-
if err := db.Debug().Save(&provider).Error; err != nil {
87+
if err := db.Save(&provider).Error; err != nil {
88+
log.Errorf("error trying to update provider access_key with new refresh token, error is %v", err)
5989
return nil, err
6090
}
61-
//d set headers that are required for requests to brightspace
91+
log.Info("refresh token updated successfully on the provider_platform")
6292
headers := make(map[string]string)
6393
headers["Authorization"] = "Bearer " + brightspaceService.AccessToken
6494
headers["Accept"] = "application/json"
@@ -70,11 +100,13 @@ func (srv *BrightspaceService) SendPostRequest(url string, data url.Values) (*ht
70100
encodedUrl := data.Encode()
71101
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(encodedUrl))
72102
if err != nil {
103+
log.Errorf("error creating new POST request to url %v and error is: %v", url, err)
73104
return nil, err
74105
}
75106
req.Header.Add("Content-Type", "application/x-www-form-urlencoded") //standard header for url.Values (encoded)
76107
resp, err := srv.Client.Do(req)
77108
if err != nil {
109+
log.Errorf("error executing POST request to url %v and error is: %v", url, err)
78110
return nil, err
79111
}
80112
return resp, nil
@@ -83,39 +115,70 @@ func (srv *BrightspaceService) SendPostRequest(url string, data url.Values) (*ht
83115
func (srv *BrightspaceService) SendRequest(url string) (*http.Response, error) {
84116
req, err := http.NewRequest("GET", url, nil)
85117
if err != nil {
118+
log.Errorf("error creating new GET request to url %v and error is: %v", url, err)
86119
return nil, err
87120
}
88121
for key, value := range *srv.BaseHeaders {
89122
req.Header.Add(key, value)
90123
}
91124
resp, err := srv.Client.Do(req)
92125
if err != nil {
126+
log.Errorf("error executing GET request to url %v and error is: %v", url, err)
93127
return nil, err
94128
}
95129
return resp, nil
96130
}
97131

98132
func (srv *BrightspaceService) GetUsers(db *gorm.DB) ([]models.ImportUser, error) {
99-
//get brightspace users
133+
fmt.Println("GetUsers...")
100134
return nil, nil
101135
}
102136

103137
func (srv *BrightspaceService) ImportCourses(db *gorm.DB) error {
104-
//import brightspace courses
138+
pluginId, err := srv.getPluginId("Organizational Units")
139+
if err != nil {
140+
log.Errorf("error attempting to get plugin id for courses, error is: %v", err)
141+
return err
142+
}
143+
log.Infof("successfully retrieved plugin id %v for downloading csv file for courses", pluginId)
144+
downloadUrl := fmt.Sprintf(DataDownloadEnpoint, pluginId)
145+
csvFile, err := srv.downloadAndUnzipFile("OrganizationalUnits.zip", downloadUrl)
146+
if err != nil {
147+
log.Errorf("error attempting to get plugin id for courses, error is: %v", err)
148+
return err
149+
}
150+
log.Infof("successfully downloaded and unzipped %v for importing courses", csvFile)
151+
bsCourses := []BrightspaceCourse{}
152+
readCSV(&bsCourses, csvFile)
153+
cleanUpFiles("OrganizationalUnits.zip", csvFile)
154+
fields := log.Fields{"provider": srv.ProviderPlatformID, "Function": "ImportCourses", "csvFile": csvFile}
155+
log.WithFields(fields).Info("importing courses from provider using csv file")
156+
for _, bsCourse := range bsCourses {
157+
if bsCourse.IsActive == "TRUE" && bsCourse.IsDeleted == "FALSE" && bsCourse.Type == "Course Offering" {
158+
if db.Where("provider_platform_id = ? AND external_id = ?", srv.ProviderPlatformID, bsCourse.OrgUnitId).First(&models.Course{}).Error == nil {
159+
continue
160+
}
161+
log.Infof("importing course named %v with external id %v", bsCourse.Name, bsCourse.OrgUnitId)
162+
course := srv.IntoCourse(bsCourse)
163+
if err := db.Create(&course).Error; err != nil {
164+
log.Errorf("error creating course in db, error is: %v", err)
165+
continue
166+
}
167+
}
168+
}
105169
return nil
106170
}
107171

108172
func (srv *BrightspaceService) ImportMilestones(coursePair map[string]interface{}, mappings []map[string]interface{}, db *gorm.DB, lastRun time.Time) error {
109-
//import milestones
173+
fmt.Println("ImportMilestones...")
110174
return nil
111175
}
112176

113177
func (srv *BrightspaceService) ImportActivityForCourse(coursePair map[string]interface{}, db *gorm.DB) error {
114-
//import activity for course
178+
fmt.Println("ImportActivityForCourse...")
115179
return nil
116180
}
117181

118182
func (srv *BrightspaceService) GetJobParams() *map[string]interface{} {
119-
//get job parameters
120183
return srv.JobParams
121184
}

0 commit comments

Comments
 (0)