Skip to content

Commit

Permalink
Merge pull request #255 from UnlockedLabs/dockerenv
Browse files Browse the repository at this point in the history
feat: finish dashboard + catalogue issues
  • Loading branch information
PThorpe92 authored May 30, 2024
2 parents 01b4b34 + a64c28d commit d08d284
Show file tree
Hide file tree
Showing 16 changed files with 132 additions and 147 deletions.
19 changes: 13 additions & 6 deletions backend/seeder/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
21 changes: 11 additions & 10 deletions backend/seeder/go.sum
Original file line number Diff line number Diff line change
@@ -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=
43 changes: 18 additions & 25 deletions backend/src/database/leftmenulinks.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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
}

Expand All @@ -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
}
4 changes: 3 additions & 1 deletion backend/src/handlers/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"UnlockEdv2/src/models"
"net/http"
"strconv"
"strings"

log "github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -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,
Expand All @@ -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)
Expand Down
21 changes: 15 additions & 6 deletions backend/src/handlers/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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{}{}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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)
}

Expand Down Expand Up @@ -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 {
Expand Down
1 change: 0 additions & 1 deletion backend/src/handlers/programs_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ func (srv *Server) registerProgramsRoutes() {
* ?page=: page
* ?perPage=: perPage
* ?sort=: sort
* ?filter=: filter
* ?search=: search
* ?searchFields=: searchFields
*/
Expand Down
7 changes: 7 additions & 0 deletions backend/src/handlers/provider_platform_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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),
Expand All @@ -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)
}
40 changes: 10 additions & 30 deletions backend/src/models/program.go
Original file line number Diff line number Diff line change
@@ -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 (
Expand Down
Loading

0 comments on commit d08d284

Please sign in to comment.