Skip to content

Commit

Permalink
fix: issue with consent page/oauth, seeder, retain build info
Browse files Browse the repository at this point in the history
  • Loading branch information
PThorpe92 committed Sep 6, 2024
1 parent 7e83b43 commit 27fa280
Show file tree
Hide file tree
Showing 15 changed files with 145 additions and 72 deletions.
6 changes: 2 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
INSTALL_GOOSE=go install github.com/pressly/goose/v3/cmd/goose@latest
INSTALL_AIR=go install github.com/air-verse/air@latest
INIT_HOOKS=cd frontend && yarn prepare && cd ..
DOCKER_COMPOSE=docker-compose.yml
KOLIBRI_COMPOSE=config/docker-compose.kolibri.yml
MIGRATION_DIR=-dir backend/migrations
Expand Down Expand Up @@ -43,8 +40,9 @@ reset: ascii_art

init: ascii_art
@echo 'Installing dependencies...'
$(INSTALL_GOOSE) && $(INIT_HOOKS) && $(INSTALL_AIR)
go install github.com/pressly/goose/v3/cmd/goose@latest && go install github.com/air-verse/air@latest && cd frontend && yarn install && yarn prepare && cd ..
@echo 'Dependencies installed successfully.'
docker-compose up $(BUILD_RECREATE)

dev: ascii_art
docker-compose up $(BUILD_RECREATE)
Expand Down
28 changes: 21 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ If you would like to contribute, please have a look at our [contribution guideli

### Dependencies (Local)

**Please ensure you have the following installed properly before the further steps**

- Go 1.23
- Node.js > 18.0

- Node.js >= v18.0

- Yarn 1.22.22

- Docker && Docker-Compose

### Dependencies (Deployment/Production)
Expand All @@ -29,22 +35,30 @@ If you would like to contribute, please have a look at our [contribution guideli

### Steps

- Clone the repository
- Clone the repository.

- `cp .env.example .env`.

- `cp .env.example .env`
- run `make init` to install dependencies, setup git hooks, and run the containers.

- run `make init` to install dependencies and setup git hooks
- run `make migrate` to run the initial migrations and populate database tables.

- run `make dev` to start the development environment in docker compose
- Optionally, If you wish to seed the database with some basic test data, run `make seed`.

NOTE: you must be sure to use `127.0.0.1` in place of `localhost`, as the cookies required for authentication are not shared between the two,

Subsequent runs can be done with `make dev`, which will start all the necessary containers
with hot reloading on the client and the backend.


**NOTE:** you _must_ be sure to use `127.0.0.1` in place of `localhost` in your browser, as the cookies required for authentication are not shared between the two,
and this can cause bad states in the browser that will prevent successful login/auth flow.

Login with `SuperAdmin` and password: `ChangeMe!`

You will be prompted immediately to set a new password and name for the default facility, and then you
will be redirected to the dashboard.


**Integrations:**

- _Kolibri_:
Expand All @@ -63,7 +77,7 @@ will be redirected to the dashboard.

### To migrate the database to a fresh state, run `make migrate-fresh` (you can do this while docker is running with all the services, but you must restart the server (e.g. `docker restart unlockedv2-server-1` if your repo directory is called UnlockEdv2)

### To seed the database with some basic test data, run `make seed`


### **Quick fixes to common issues with development**

Expand Down
4 changes: 4 additions & 0 deletions backend/migrations/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ func main() {
if err := goose.Up(db, migrationDir); err != nil {
log.Fatalf("Migration failed: %v", err)
}
if *fresh {
MigrateFresh(db)
}
log.Println("Migrations completed successfully")
os.Exit(0)
}
Expand Down Expand Up @@ -95,6 +98,7 @@ func syncOryKratos() error {
log.Fatal("unable to delete identity from Ory Kratos")
continue
} else {
log.Println("identity deleted successfully")
continue
}
}
Expand Down
36 changes: 16 additions & 20 deletions backend/seeder/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ func seedTestData(db *gorm.DB) {
log.Printf("Failed to create platform: %v", err)
}
}
var newPlatforms []models.ProviderPlatform
if err := db.Find(&newPlatforms).Error; err != nil {
log.Fatal("Failed to get platforms from db")
}
userFile, err := os.ReadFile("backend/tests/test_data/users.json")
if err != nil {
log.Printf("Failed to read test data: %v", err)
Expand All @@ -69,23 +73,23 @@ func seedTestData(db *gorm.DB) {
if err := json.Unmarshal(userFile, &users); err != nil {
log.Printf("Failed to unmarshal test data: %v", err)
}
for idx, u := range users {
u.Password = "ChangeMe!"
if err := u.HashPassword(); err != nil {
for idx := range users {
users[idx].Password = "ChangeMe!"
if err := users[idx].HashPassword(); err != nil {
log.Fatalf("unable to hash user password")
}
log.Printf("Creating user %s", u.Username)
if err := db.Create(&u).Error; err != nil {
log.Printf("Creating user %s", users[idx].Username)
if err := db.Create(&users[idx]).Error; err != nil {
log.Printf("Failed to create user: %v", err)
}
if err := testServer.HandleCreateUserKratos(u.Username, "ChangeMe!"); err != nil {
if err := testServer.HandleCreateUserKratos(users[idx].Username, "ChangeMe!"); err != nil {
log.Fatalf("unable to create test user in kratos")
}
for i := 0; i < len(platform); i++ {
for i := 0; i < len(newPlatforms); i++ {
mapping := models.ProviderUserMapping{
UserID: u.ID,
ProviderPlatformID: platform[i].ID,
ExternalUsername: u.Username,
UserID: users[idx].ID,
ProviderPlatformID: newPlatforms[i].ID,
ExternalUsername: users[idx].Username,
ExternalUserID: strconv.Itoa(idx),
}
if err = db.Create(&mapping).Error; err != nil {
Expand All @@ -101,19 +105,11 @@ func seedTestData(db *gorm.DB) {
if err := json.Unmarshal(progs, &programs); err != nil {
log.Printf("Failed to unmarshal test data: %v", err)
}
for _, p := range programs {
if err := db.Create(&p).Error; err != nil {
for idx := range programs {
if err := db.Create(&programs[idx]).Error; err != nil {
log.Printf("Failed to create program: %v", err)
}
}
var milestones []models.Milestone
mstones, err := os.ReadFile("backend/tests/test_data/milestones.json")
if err != nil {
log.Printf("Failed to read test data: %v", err)
}
if err := json.Unmarshal(mstones, &milestones); err != nil {
log.Printf("Failed to unmarshal test data: %v", err)
}
outcomes := []string{"college_credit", "grade", "certificate", "pathway_completion"}
milestoneTypes := []models.MilestoneType{models.DiscussionPost, models.AssignmentSubmission, models.QuizSubmission, models.GradeReceived}
var dbUsers []models.User
Expand Down
1 change: 1 addition & 0 deletions config/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ FROM node:22.7.0-slim
WORKDIR /app

EXPOSE 5173
RUN yarn install
ENTRYPOINT ["yarn", "dev"]
9 changes: 7 additions & 2 deletions config/docker-compose.kolibri.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ services:
kolibri:
image: unlockedlabs.org/kolibri:latest
environment:
CLIENT_ID: #placeholder for generated
CLIENT_SECRET: #client on first login
CLIENT_ID: # replace with generated client ID
CLIENT_SECRET: # replace with generated client secret
KOLIBRI_OIDC_JWKS_URI: http://hydra:4444/.well-known/jwks.json
KOLIBRI_OIDC_AUTHORIZATION_ENDPOINT: http://hydra:4444/oauth2/auth
KOLIBRI_OIDC_TOKEN_ENDPOINT: http://hydra:4444/oauth2/token
KOLIBRI_OIDC_USERINFO_ENDPOINT: http://hydra:4444/userinfo
KOLIBRI_OIDC_CLIENT_URL: http://127.0.0.1:8000
ports:
- 8000:8000
networks:
Expand Down
1 change: 1 addition & 0 deletions config/hydra/hydra.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@ oidc:
subject_identifiers:
supported_types:
- pairwise
- public
pairwise:
salt: 2839o82hy2839OO#@#$@OFw@ksj8*^@*^$LSwsifw2692oCHANGE_ME_IN_PROD
9 changes: 4 additions & 5 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ services:
- ./frontend:/app
networks:
- intranet
restart: always
restart: on-failure

rev_proxy:
image: nginx:1.21.3-alpine
Expand All @@ -37,7 +37,7 @@ services:
- logs:/var/log/nginx/
networks:
- intranet
restart: "on-failure"
restart: on-failure
depends_on:
kratos-migrate:
condition: service_completed_successfully
Expand Down Expand Up @@ -103,6 +103,7 @@ services:
- intranet
volumes:
- logs:/logs
restart: on-failure
depends_on:
postgres:
condition: service_healthy
Expand Down Expand Up @@ -175,7 +176,6 @@ services:
- keto-migrate
environment:
- DSN=postgres://keto:ChangeMe!@postgres:5432/accesscontroldb?sslmode=prefer&max_conns=20&max_idle_conns=4
restart: on-failure
networks:
- intranet

Expand All @@ -188,7 +188,6 @@ services:
source: ./config/kratos
target: /etc/config/kratos
command: -c /etc/config/kratos/kratos.yml migrate sql -e --yes
restart: on-failure
networks:
- intranet
depends_on:
Expand Down Expand Up @@ -233,7 +232,7 @@ services:
- SERVE_ADMIN_CORS_ENABLED=true
- SERVE_ADMIN_CORS_ALLOWED_METHODS=POST,GET,PUT,DELETE
- DSN=postgres://hydra:ChangeMe!@postgres:5432/hydra?sslmode=prefer&max_conns=20&max_idle_conns=4
restart: unless-stopped
restart: on-failure
depends_on:
- hydra-migrate
networks:
Expand Down
4 changes: 1 addition & 3 deletions frontend/src/Components/PageNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,7 @@ export default function PageNav({
</li>
)}

{path.map((p) => (
<li key={p}>{p}</li>
))}
{path && path.map((p) => <li key={p}>{p}</li>)}
</ul>
</div>
<div className="navbar-end">
Expand Down
36 changes: 26 additions & 10 deletions frontend/src/Components/forms/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,33 @@ export default function LoginForm() {
window.location.replace(BROWSER_URL);
return;
}
let url = kratosUrl + queryParams.get('flow');
const resp = await axios.get(url);
if (resp.status !== 200) {
console.error('Error initializing login flow');
return;
const flowId = queryParams.get('flow');
let url = kratosUrl + flowId;

try {
const resp = await axios.get(url);
if (resp.status !== 200 || !resp.data) {
console.error(
'Error initializing login flow or response data is missing'
);
return;
}
if (
!resp.data.id ||
!resp.data.oauth2_login_challenge ||
!resp.data.ui?.nodes[0]?.attributes?.value
) {
console.error('Required fields from flow are missing');
return;
}
return {
flow_id: resp.data.id,
challenge: resp.data.oauth2_login_challenge,
csrf_token: resp.data.ui.nodes[0].attributes.value
};
} catch (error) {
console.error('Failed to fetch flow data', error);
}
return {
flow_id: resp.data.id,
challenge: resp.data.oauth2_login_challenge,
csrf_token: resp.data.ui.nodes[0].attributes.value
};
};

return (
Expand Down
8 changes: 3 additions & 5 deletions frontend/src/Pages/Auth/Consent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';

export default function Consent() {
return (
<div title="Application Consent">
<AuthenticatedLayout title="External Login Consent">
<ConsentForm />
</AuthenticatedLayout>
</div>
<AuthenticatedLayout title="External Login Consent" path={['consent']}>
<ConsentForm />
</AuthenticatedLayout>
);
}
Loading

0 comments on commit 27fa280

Please sign in to comment.