From a64c28dd341c0a9f91d52c89ec671ea36ef04931 Mon Sep 17 00:00:00 2001 From: PThorpe92 Date: Thu, 30 May 2024 13:45:37 -0400 Subject: [PATCH] feat: finish dashboard + catalogue issues --- backend/seeder/go.mod | 19 ++++--- backend/seeder/go.sum | 21 ++++---- backend/src/database/leftmenulinks.go | 43 +++++++--------- backend/src/handlers/actions.go | 4 +- backend/src/handlers/auth.go | 21 +++++--- backend/src/handlers/programs_handler.go | 1 - .../src/handlers/provider_platform_handler.go | 7 +++ backend/src/models/program.go | 40 ++++----------- backend/tests/test_data/programs.json | 50 ++++--------------- canvas-seeder/go.mod | 13 +++-- canvas-seeder/main.go | 50 ++++++++++++------- config/docker-compose.prod.yml | 1 - config/nginx.conf | 2 + docker-compose.yml | 1 - go.work | 1 + provider-middleware/canvas.go | 5 +- 16 files changed, 132 insertions(+), 147 deletions(-) diff --git a/backend/seeder/go.mod b/backend/seeder/go.mod index b94f634d..820b4c04 100644 --- a/backend/seeder/go.mod +++ b/backend/seeder/go.mod @@ -2,14 +2,21 @@ module seeder go 1.22.3 +require ( + github.com/joho/godotenv v1.5.1 + gorm.io/driver/postgres v1.5.7 + gorm.io/gorm v1.25.10 +) + require ( github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgx/v5 v5.4.3 // indirect + github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect + github.com/jackc/pgx/v5 v5.5.5 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/text v0.13.0 // indirect - gorm.io/driver/postgres v1.5.7 // indirect - gorm.io/gorm v1.25.10 // indirect + github.com/stretchr/testify v1.9.0 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/text v0.14.0 // indirect ) diff --git a/backend/seeder/go.sum b/backend/seeder/go.sum index dfb0705c..3cf17b51 100644 --- a/backend/seeder/go.sum +++ b/backend/seeder/go.sum @@ -1,27 +1,28 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY= -github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= +github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= +github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM= gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA= -gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde h1:9DShaph9qhkIYw7QF91I/ynrr4cOO2PZra2PFD7Mfeg= -gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s= gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= diff --git a/backend/src/database/leftmenulinks.go b/backend/src/database/leftmenulinks.go index 266ea1d3..a2a74fb5 100644 --- a/backend/src/database/leftmenulinks.go +++ b/backend/src/database/leftmenulinks.go @@ -2,11 +2,8 @@ package database import ( "UnlockEdv2/src/models" - "fmt" - "log" - "strings" - "github.com/jackc/pgx" + log "github.com/sirupsen/logrus" ) func (db *DB) GetLeftMenuLinks() ([]models.LeftMenuLink, error) { @@ -24,10 +21,10 @@ func (db *DB) DeleteAllLinks() error { func (db *DB) CreateFreshLeftMenuLinks(links []models.LeftMenuLink) error { if err := db.Conn.Create(&links).Error; err != nil { - log.Printf("Error creating links: %v", err) + log.Errorf("Error creating links: %v", err) return err } - log.Println("Left-Menu-Links created") + log.Infof("Left-Menu-Links created") return nil } @@ -39,30 +36,26 @@ type UserCatalogueJoin struct { ExternalURL string `json:"external_url"` ProgramType string `json:"program_type"` IsFavorited bool `json:"is_favorited"` + OutcomeTypes string `json:"outcome_types"` } func (db *DB) GetUserCatalogue(userId int, tags []string) ([]UserCatalogueJoin, error) { catalogue := []UserCatalogueJoin{} - var queryBuilder strings.Builder - queryBuilder.WriteString(fmt.Sprintf(`SELECT p.id as program_id, p.thumbnail_url, p.name as program_name, - pp.name as provider_name, p.external_url, p.type as program_type, p.outcome_types, - f.user_id IS NOT NULL as is_favorited - FROM programs p - LEFT JOIN provider_platforms pp ON p.provider_platform_id = pp.id - LEFT JOIN favorites f ON f.program_id = p.id AND f.user_id = %d`, userId)) - - if len(tags) > 0 { - queryBuilder.WriteString(` WHERE (p.program_type IN ? OR ? = ANY (p.outcome_types))`) - tagArgs := pgx.QueryArgs{tags} - err := db.Conn.Raw(queryBuilder.String(), tagArgs).Scan(&catalogue).Error - if err != nil { - return nil, err - } - } else { - err := db.Conn.Raw(queryBuilder.String()).Scan(&catalogue).Error - if err != nil { - return nil, err + tx := db.Conn.Table("programs p"). + Select("p.id as program_id, p.thumbnail_url, p.name as program_name, pp.name as provider_name, p.external_url, p.type as program_type, p.outcome_types, f.user_id IS NOT NULL as is_favorited"). + Joins("LEFT JOIN provider_platforms pp ON p.provider_platform_id = pp.id"). + Joins("LEFT JOIN favorites f ON f.program_id = p.id AND f.user_id = ?", userId) + for i, tag := range tags { + if i == 0 { + tx.Where("p.outcome_types ILIKE ?", "%"+tag+"%") + } else { + tx.Or("p.outcome_types ILIKE ?", "%"+tag+"%") } + tx.Or("p.type ILIKE ?", "%"+tag+"%") + } + err := tx.Scan(&catalogue).Error + if err != nil { + return nil, err } return catalogue, nil } diff --git a/backend/src/handlers/actions.go b/backend/src/handlers/actions.go index 729c386b..8e7a33fe 100644 --- a/backend/src/handlers/actions.go +++ b/backend/src/handlers/actions.go @@ -5,6 +5,7 @@ import ( "UnlockEdv2/src/models" "net/http" "strconv" + "strings" log "github.com/sirupsen/logrus" ) @@ -72,6 +73,7 @@ func (srv *Server) HandleImportPrograms(w http.ResponseWriter, r *http.Request) return } for _, item := range content { + outcomeTypes := strings.Join(item.OutcomeTypes, ",") prog := models.Program{ ProviderPlatformID: uint(service.ProviderPlatformID), Name: item.Name, @@ -80,7 +82,7 @@ func (srv *Server) HandleImportPrograms(w http.ResponseWriter, r *http.Request) ThumbnailURL: item.ThumbnailURL, ExternalURL: item.ExternalURL, Type: models.ProgramType(item.Type), - OutcomeTypes: models.OutcomeTypes(item.OutcomeTypes), + OutcomeTypes: outcomeTypes, TotalProgressMilestones: uint(item.TotalProgressMilestones), } _, err := srv.Db.CreateProgram(&prog) diff --git a/backend/src/handlers/auth.go b/backend/src/handlers/auth.go index bab6824d..c00dcf4e 100644 --- a/backend/src/handlers/auth.go +++ b/backend/src/handlers/auth.go @@ -139,7 +139,7 @@ func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) { Path: "/", }) if form.LoginChallenge != "" { - s.handleOidcLogin(w, r, claims, form.LoginChallenge) + s.handleOidcLogin(w, r.WithContext(r.Context()), claims, form.LoginChallenge) } err = s.WriteResponse(w, http.StatusOK, user) if err != nil { @@ -152,6 +152,11 @@ func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) { } } +const ( + ConsentEndpoint = "/admin/oauth2/auth/requests/consent/accept?consent_challenge=" + LoginEndpoint = "/admin/oauth2/auth/requests/login/accept" +) + func (srv *Server) handleConsent(w http.ResponseWriter, r *http.Request) { log.Info("Consent handler") reqBody := map[string]interface{}{} @@ -185,7 +190,7 @@ func (srv *Server) handleConsent(w http.ResponseWriter, r *http.Request) { http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } - req, err := http.NewRequest("PUT", os.Getenv("HYDRA_ADMIN_URL")+"/admin/oauth2/auth/requests/consent/accept?consent_challenge="+consentChallenge, bytes.NewReader(jsonBody)) + req, err := http.NewRequest("PUT", os.Getenv("HYDRA_ADMIN_URL")+ConsentEndpoint+consentChallenge, bytes.NewReader(jsonBody)) if err != nil { log.Error("Error creating request") http.Error(w, "Internal Server Error", http.StatusInternalServerError) @@ -229,7 +234,7 @@ func (s *Server) handleOidcLogin(w http.ResponseWriter, r *http.Request, claims http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } - req, err := http.NewRequest("PUT", os.Getenv("HYDRA_ADMIN_URL")+"/admin/oauth2/auth/requests/login/accept"+loginChallenge, bytes.NewReader(jsonBody)) + req, err := http.NewRequest("PUT", os.Getenv("HYDRA_ADMIN_URL")+LoginEndpoint+loginChallenge, bytes.NewReader(jsonBody)) if err != nil { log.Error("Error creating request") http.Error(w, "Internal Server Error", http.StatusInternalServerError) @@ -255,6 +260,7 @@ func (s *Server) handleOidcLogin(w http.ResponseWriter, r *http.Request, claims return } redirectURI := loginResponse["redirect_to"].(string) + log.Info("redirecting to", redirectURI) http.Redirect(w, r.WithContext(r.Context()), redirectURI, http.StatusSeeOther) } @@ -304,9 +310,12 @@ func (srv *Server) handleResetPassword(w http.ResponseWriter, r *http.Request) { confirm = form.Confirm } defer r.Body.Close() - if password != confirm || !validatePassword(password) { - http.Redirect(w, r, "/reset-password", http.StatusSeeOther) - log.Error("Password validation failed") + if password != confirm { + http.Error(w, "Passwords do not match", http.StatusBadRequest) + return + } + if !validatePassword(password) { + http.Error(w, "Password must be at least 8 characters long and contain a number", http.StatusBadRequest) return } if err := srv.Db.ResetUserPassword(claims.UserID, password); err != nil { diff --git a/backend/src/handlers/programs_handler.go b/backend/src/handlers/programs_handler.go index 83b88edd..75771cef 100644 --- a/backend/src/handlers/programs_handler.go +++ b/backend/src/handlers/programs_handler.go @@ -23,7 +23,6 @@ func (srv *Server) registerProgramsRoutes() { * ?page=: page * ?perPage=: perPage * ?sort=: sort -* ?filter=: filter * ?search=: search * ?searchFields=: searchFields */ diff --git a/backend/src/handlers/provider_platform_handler.go b/backend/src/handlers/provider_platform_handler.go index 5c5057a6..52209b2c 100644 --- a/backend/src/handlers/provider_platform_handler.go +++ b/backend/src/handlers/provider_platform_handler.go @@ -64,12 +64,14 @@ func (srv *Server) HandleCreateProvider(w http.ResponseWriter, r *http.Request) if err != nil { log.Error("Error decoding request body: ", err.Error()) http.Error(w, err.Error(), http.StatusBadRequest) + return } defer r.Body.Close() newProv, err := srv.Db.CreateProviderPlatform(&platform) if err != nil { log.Error("Error creating provider platform: ", err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) + return } response := models.Resource[models.ProviderPlatform]{ Data: make([]models.ProviderPlatform, 0), @@ -87,18 +89,21 @@ func (srv *Server) HandleUpdateProvider(w http.ResponseWriter, r *http.Request) if err != nil { log.Error("PATCH Provider handler Error:", err.Error()) http.Error(w, err.Error(), http.StatusBadRequest) + return } var platform models.ProviderPlatform err = json.NewDecoder(r.Body).Decode(&platform) if err != nil { log.Error("Error decoding request body: ", err.Error()) http.Error(w, err.Error(), http.StatusBadRequest) + return } defer r.Body.Close() updated, err := srv.Db.UpdateProviderPlatform(&platform, uint(id)) if err != nil { log.Error("Error updating provider platform: ", err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) + return } response := models.Resource[models.ProviderPlatform]{ Data: make([]models.ProviderPlatform, 0), @@ -114,10 +119,12 @@ func (srv *Server) HandleDeleteProvider(w http.ResponseWriter, r *http.Request) if err != nil { log.Error("DELETE Provider handler Error: ", err.Error()) http.Error(w, err.Error(), http.StatusBadRequest) + return } if err = srv.Db.DeleteProviderPlatform(id); err != nil { log.Error("Error deleting provider platform: ", err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) + return } w.WriteHeader(http.StatusNoContent) } diff --git a/backend/src/models/program.go b/backend/src/models/program.go index 9e7a1010..2639b331 100644 --- a/backend/src/models/program.go +++ b/backend/src/models/program.go @@ -1,43 +1,23 @@ package models -import ( - "database/sql/driver" - "encoding/json" - "errors" -) - type Program struct { DatabaseFields - ProviderPlatformID uint `gorm:"not null" json:"provider_platform_id"` - Name string `gorm:"size:60" json:"name"` - Description string `gorm:"size:510" json:"description"` - ExternalID string `gorm:"size:255" json:"external_id"` // kolibri: root, canvas: course_id - ThumbnailURL string `gorm:"size:255" json:"thumbnail_url"` - Type ProgramType `gorm:"size:255" json:"type"` - OutcomeTypes OutcomeTypes `gorm:"type:json" json:"outcome_types"` - ExternalURL string `gorm:"size:255" json:"external_url"` - AltName string `gorm:"size:255" json:"alt_name"` - TotalProgressMilestones uint `json:"total_progress_milestones"` + ProviderPlatformID uint `gorm:"not null" json:"provider_platform_id"` + Name string `gorm:"size:60" json:"name"` + Description string `gorm:"size:510" json:"description"` + ExternalID string `gorm:"size:255" json:"external_id"` // kolibri: root, canvas: course_id + ThumbnailURL string `gorm:"size:255" json:"thumbnail_url"` + Type ProgramType `gorm:"size:255" json:"type"` + OutcomeTypes string `gorm:"size:255" json:"outcome_types"` + ExternalURL string `gorm:"size:255" json:"external_url"` + AltName string `gorm:"size:255" json:"alt_name"` + TotalProgressMilestones uint `json:"total_progress_milestones"` ProviderPlatform *ProviderPlatform `gorm:"foreignKey:ProviderPlatformID;constraint:OnDelete SET NULL" json:"-"` Milestones []Milestone `gorm:"foreignKey:ProgramID;constraint:OnDelete SET NULL" json:"-"` Outcomes []Outcome `gorm:"foreignKey:ProgramID;constraint:OnDelete SET NULL" json:"-"` } -type OutcomeTypes []string - -func (sa OutcomeTypes) Value() (driver.Value, error) { - return json.Marshal(sa) -} - -func (sa *OutcomeTypes) Scan(input interface{}) error { - bytes, ok := input.([]byte) - if !ok { - return errors.New("type assertion to []byte failed") - } - return json.Unmarshal(bytes, sa) -} - type ProgramType string const ( diff --git a/backend/tests/test_data/programs.json b/backend/tests/test_data/programs.json index 054527fa..f99a5323 100644 --- a/backend/tests/test_data/programs.json +++ b/backend/tests/test_data/programs.json @@ -9,10 +9,7 @@ "external_id": "98", "thumbnail_url": "", "type": "open_enrollment", - "outcome_types": [ - "grade", - "college_credit" - ], + "outcome_types": "grade,college_credit", "external_url": "https://staging.canvas.unlockedlabs.xyz/courses/98", "alt_name": "", "total_progress_milestones": 12 @@ -27,10 +24,7 @@ "external_id": "101", "thumbnail_url": "", "type": "open_enrollment", - "outcome_types": [ - "grade", - "college_credit" - ], + "outcome_types": "grade,college_credit", "external_url": "https://staging.canvas.unlockedlabs.xyz/courses/101", "alt_name": "", "total_progress_milestones": 10 @@ -45,10 +39,7 @@ "external_id": "103", "thumbnail_url": "", "type": "open_enrollment", - "outcome_types": [ - "grade", - "college_credit" - ], + "outcome_types": "grade,college_credit", "external_url": "https://staging.canvas.unlockedlabs.xyz/courses/103", "alt_name": "", "total_progress_milestones": 10 @@ -63,10 +54,7 @@ "external_id": "258", "thumbnail_url": "", "type": "open_enrollment", - "outcome_types": [ - "grade", - "college_credit" - ], + "outcome_types": "grade,college_credit", "external_url": "https://staging.canvas.unlockedlabs.xyz/courses/258", "alt_name": "", "total_progress_milestones": 10 @@ -81,10 +69,7 @@ "external_id": "176", "thumbnail_url": "", "type": "open_enrollment", - "outcome_types": [ - "grade", - "college_credit" - ], + "outcome_types": "grade,college_credit", "external_url": "https://staging.canvas.unlockedlabs.xyz/courses/176", "alt_name": "", "total_progress_milestones": 12 @@ -99,10 +84,7 @@ "external_id": "754", "thumbnail_url": "", "type": "open_enrollment", - "outcome_types": [ - "grade", - "college_credit" - ], + "outcome_types": "grade,college_credit", "external_url": "https://staging.canvas.unlockedlabs.xyz/courses/754", "alt_name": "", "total_progress_milestones": 8 @@ -117,10 +99,7 @@ "external_id": "886", "thumbnail_url": "", "type": "open_enrollment", - "outcome_types": [ - "grade", - "college_credit" - ], + "outcome_types": "grade,college_credit", "external_url": "https://staging.canvas.unlockedlabs.xyz/courses/886", "alt_name": "", "total_progress_milestones": 8 @@ -135,10 +114,7 @@ "external_id": "894", "thumbnail_url": "", "type": "open_enrollment", - "outcome_types": [ - "grade", - "college_credit" - ], + "outcome_types": "grade,college_credit", "external_url": "https://staging.canvas.unlockedlabs.xyz/courses/894", "alt_name": "", "total_progress_milestones": 14 @@ -153,10 +129,7 @@ "external_id": "489", "thumbnail_url": "", "type": "open_enrollment", - "outcome_types": [ - "grade", - "college_credit" - ], + "outcome_types": "grade,college_credit", "external_url": "https://staging.canvas.unlockedlabs.xyz/courses/489", "alt_name": "", "total_progress_milestones": 11 @@ -171,10 +144,7 @@ "external_id": "602", "thumbnail_url": "", "type": "open_enrollment", - "outcome_types": [ - "grade", - "college_credit" - ], + "outcome_types": "grade,college_credit", "external_url": "https://staging.canvas.unlockedlabs.xyz/courses/602", "alt_name": "", "total_progress_milestones": 10 diff --git a/canvas-seeder/go.mod b/canvas-seeder/go.mod index a10fa9f4..afea78b6 100644 --- a/canvas-seeder/go.mod +++ b/canvas-seeder/go.mod @@ -1,9 +1,8 @@ -module test +module canvas_seeder -go 1.21 +go 1.22.3 -toolchain go1.22.2 - -require github.com/brianvoe/gofakeit/v6 v6.28.0 - -require github.com/joho/godotenv v1.5.1 +require ( + github.com/brianvoe/gofakeit/v6 v6.28.0 + github.com/joho/godotenv v1.5.1 +) diff --git a/canvas-seeder/main.go b/canvas-seeder/main.go index 085c12db..8cf7beae 100644 --- a/canvas-seeder/main.go +++ b/canvas-seeder/main.go @@ -16,16 +16,20 @@ import ( "github.com/joho/godotenv" ) -const post = "POST" -const put = "PUT" +const ( + post = "POST" + put = "PUT" +) -const defaultAssignments = 10 -const defaultCourses = 3 -const defaultUsers = 10 +const ( + defaultAssignments = 10 + defaultCourses = 3 + defaultUsers = 10 +) func createCourse(apiToken string, - canvasURL string) ([]map[string]interface{}, error) { - + canvasURL string, +) ([]map[string]interface{}, error) { coursesUrl := fmt.Sprintf("%s/api/v1/accounts/self/courses", canvasURL) payload := url.Values{} payload.Set("course[name]", gofakeit.Sentence(5)) @@ -54,7 +58,8 @@ func createCourseAssignments(apiToken string, canvasURL string, users []map[string]interface{}, courseId string, - targetAssignments int) error { + targetAssignments int, +) error { assignmentsUrl := fmt.Sprintf("%s/api/v1/courses/%v/assignments", canvasURL, courseId) submission_limit := make(map[int]int) @@ -113,8 +118,8 @@ func createCourseAssignmentSubmission(apiToken string, canvasURL string, courseId string, assignmentId string, - userId string) error { - + userId string, +) error { submissionsUrl := fmt.Sprintf("%s/api/v1/courses/%v/assignments/%v/submissions", canvasURL, courseId, assignmentId) payload := url.Values{} payload.Set("submission[submission_type]", "online_text_entry") @@ -141,8 +146,8 @@ func createCourseAssignmentSubmissionGrade(apiToken string, canvasURL string, courseId string, assignmentId string, - userId string) error { - + userId string, +) error { submissionsUrl := fmt.Sprintf("%s/api/v1/courses/%v/assignments/%v/submissions/%v", canvasURL, courseId, assignmentId, userId) grade := gofakeit.Number(60, 100) body := fmt.Sprintf("{\"submission\": {\"posted_grade\":\"%v\"}}", grade) @@ -161,7 +166,8 @@ func createCourseAssignmentSubmissionGrade(apiToken string, } func createUser(apiToken string, - canvasURL string) ([]map[string]interface{}, error) { + canvasURL string, +) ([]map[string]interface{}, error) { usersUrl := fmt.Sprintf("%s/api/v1/accounts/self/users", canvasURL) payload := url.Values{} @@ -189,8 +195,8 @@ func createUser(apiToken string, func enrollAllUsers(apiToken string, canvasURL string, users []map[string]interface{}, - courseId interface{}) error { - + courseId interface{}, +) error { enrollmentsUrl := fmt.Sprintf("%s/api/v1/courses/%v/enrollments", canvasURL, courseId) for i, user := range users { @@ -263,7 +269,8 @@ func requestUrlTokenPayload(method string, url string, apiToken string, body string, - headers map[string]string) (*http.Response, error) { + headers map[string]string, +) (*http.Response, error) { req, err := http.NewRequest(method, url, strings.NewReader(body)) if err != nil { return nil, fmt.Errorf("error creating request: %s", err) @@ -283,7 +290,8 @@ func requestUrlTokenPayload(method string, } func retrieveCourses(apiToken string, - canvasURL string) ([]map[string]interface{}, error) { + canvasURL string, +) ([]map[string]interface{}, error) { endPoint := "/api/v1/accounts/self/courses" url := canvasURL + endPoint @@ -309,7 +317,8 @@ func retrieveCourses(apiToken string, } func retrieveUsers(apiToken string, - canvasURL string) ([]map[string]interface{}, error) { + canvasURL string, +) ([]map[string]interface{}, error) { endPoint := "/api/v1/accounts/self/users" url := canvasURL + endPoint @@ -351,6 +360,10 @@ func main() { targetUsers := defaultUsers if apiToken == "" || canvasURL == "" { + log.Printf("API_TOKEN: %s\n", apiToken) + log.Printf("CANVAS_URL: %s\n", canvasURL) + log.Printf("TARGET_ASSIGNMENTS: %s\n", targetAssignmentsStr) + log.Printf("TARGET_COURSES: %s\n", targetCoursesStr) log.Fatal("API_TOKEN or CANVAS_URL not set in environment variables") } @@ -386,6 +399,7 @@ func main() { if err != nil { log.Fatal("error creating user:", err) } + log.Printf("Created user %v\n", i) } users, err = retrieveUsers(apiToken, canvasURL) diff --git a/config/docker-compose.prod.yml b/config/docker-compose.prod.yml index ada376f6..068c12fb 100644 --- a/config/docker-compose.prod.yml +++ b/config/docker-compose.prod.yml @@ -54,7 +54,6 @@ services: env_file: frontend/.env networks: - intranet - volumes: - ./config/nginx.conf:/etc/nginx/conf.d/default.conf - ./logs:/var/log/nginx/ diff --git a/config/nginx.conf b/config/nginx.conf index 0117174b..e0616527 100644 --- a/config/nginx.conf +++ b/config/nginx.conf @@ -10,6 +10,8 @@ server { location /api { proxy_pass http://server:8080; + proxy_buffering on; + proxy_cache_methods GET HEAD; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Host $host; diff --git a/docker-compose.yml b/docker-compose.yml index 68ac0978..6fc23bfd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -63,4 +63,3 @@ networks: volumes: postgres_data: hydra-sqlite: - logs: diff --git a/go.work b/go.work index 95655f65..86d06743 100644 --- a/go.work +++ b/go.work @@ -4,5 +4,6 @@ use ( ./backend ./backend/migrations ./backend/seeder + ./canvas-seeder ./provider-middleware ) diff --git a/provider-middleware/canvas.go b/provider-middleware/canvas.go index 1b3d4c68..5d4ec373 100644 --- a/provider-middleware/canvas.go +++ b/provider-middleware/canvas.go @@ -140,8 +140,11 @@ func (srv *CanvasService) GetPrograms() ([]UnlockEdImportProgram, error) { description = course["course_code"].(string) } progType := "fixed_enrollment" - if course["is_public"].(bool) { + is_pub := course["is_public"].(bool) + if is_pub { progType = "open_enrollment" + } else { + progType = "fixed_enrollment" } unlockedCourse := UnlockEdImportProgram{ ProviderPlatformID: srv.ProviderPlatformID,