Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/disallow invalid assignment names, join on assignment accept (KHO-311, KHO-242, KHO-310) #194

Merged
merged 120 commits into from
Apr 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
120 commits
Select commit Hold shift + click to select a range
8c83e72
add githubuser + user loading
ntietje1 Dec 13, 2024
485f6b5
improve link generation efficiency
ntietje1 Dec 13, 2024
41f6dff
add react query + better error & loading states
ntietje1 Dec 13, 2024
30462a3
replace old spinner
ntietje1 Dec 13, 2024
e8dee54
Merge branch 'main' into feature/react-query
ntietje1 Dec 13, 2024
9370417
add missing imports
ntietje1 Dec 13, 2024
c86979a
Merge branch 'main' into feature/react-query
ntietje1 Dec 13, 2024
a4aa3c8
merge fix
ntietje1 Dec 13, 2024
df59761
fix bad merge div
ntietje1 Dec 13, 2024
b83e24b
Merge branch 'main' into feature/react-query
ntietje1 Dec 16, 2024
aaee543
improve loading state appearence
ntietje1 Dec 16, 2024
bca24d1
fix orgID key
ntietje1 Dec 16, 2024
77dce96
add cacheing, loading, and error states to grading tab
ntietje1 Dec 16, 2024
68baef8
add empty banner to grading and rubric tabs
ntietje1 Dec 16, 2024
3c83a03
make create assignent button primary
ntietje1 Dec 16, 2024
352d118
add automatic reroute based on permissions
ntietje1 Dec 17, 2024
a2a545a
use react query for auth calls
ntietje1 Dec 17, 2024
4afadad
reactquery for userlist
ntietje1 Dec 17, 2024
bb86c10
Merge branch 'main' into feature/react-query
ntietje1 Dec 17, 2024
f1b1deb
add disabled button
ntietje1 Dec 18, 2024
4e61f24
fix error case
ntietje1 Dec 18, 2024
d771b18
fix login issue
ntietje1 Dec 18, 2024
d50e3c5
Merge branch 'main' into feature/react-query
ntietje1 Dec 18, 2024
68d47c1
remove unused navigate
ntietje1 Dec 18, 2024
272c49c
Merge branch 'main' into feature/access-denied
ntietje1 Dec 18, 2024
78aa33e
fix
ntietje1 Dec 18, 2024
a5831a2
hotfix assignment template function
ntietje1 Dec 19, 2024
4ee2d91
disallow TAs to view create assignment page
ntietje1 Dec 19, 2024
ba829be
revamp user operation perms
ntietje1 Dec 19, 2024
f535b30
fixes
ntietje1 Dec 19, 2024
57f7caf
Merge branch 'main' into feature/access-denied
ntietje1 Dec 19, 2024
fca31f4
Merge branch 'main' into feature/access-denied
ntietje1 Dec 19, 2024
3edb3b2
Merge branch 'main' of https://github.com/NUSpecialProjects/khoury-cl…
ntietje1 Dec 19, 2024
4c6c96d
Merge branch 'main' into feature/react-query
ntietje1 Dec 19, 2024
1e1a98d
update metric call to use react query
ntietje1 Dec 19, 2024
3cdb0eb
Merge branch 'feature/access-denied' into merge/react-query-and-acces…
ntietje1 Dec 19, 2024
4bcef5a
add logout button on access denied screen
ntietje1 Dec 19, 2024
1fdce52
add disabled button & centered table items
ntietje1 Dec 19, 2024
aa8f563
Merge branch 'main' into feature/access-denied
ntietje1 Dec 19, 2024
b5e99d7
fix extra height issue
ntietje1 Dec 19, 2024
4a7f9e3
Merge branch 'feature/access-denied' into merge/react-query-and-acces…
ntietje1 Dec 19, 2024
1b57741
Merge branch 'main' into merge/react-query-and-access-denied
ntietje1 Dec 19, 2024
1b10531
reset lock file
ntietje1 Dec 19, 2024
1001264
fix missing id name change
ntietje1 Dec 19, 2024
c49bb4b
reset packagelock
ntietje1 Dec 19, 2024
dba1e43
Merge branch 'main' into merge/react-query-and-access-denied
ntietje1 Jan 16, 2025
c21badf
reduce cache lifetime
ntietje1 Jan 21, 2025
d6041bb
add clarifying comment
ntietje1 Jan 21, 2025
3b732d6
add clarifying comment 2
ntietje1 Jan 21, 2025
ba0fbb0
refactor useQueries
ntietje1 Jan 22, 2025
d5a982b
refactor invite links and classroom user lists
ntietje1 Jan 22, 2025
b7ed35e
remove invite all requested users
ntietje1 Jan 22, 2025
3d11d35
revamp navigation and auth!!
ntietje1 Jan 24, 2025
5edddb3
Merge branch 'main' into merge/react-query-and-access-denied
ntietje1 Jan 24, 2025
bf8d108
refactor classroom validation query
ntietje1 Jan 24, 2025
9930c7e
format
ntietje1 Jan 24, 2025
d02bd2d
lint
ntietje1 Jan 24, 2025
7c42a85
fix "revoke org invitation" functionality, fix permissions issues
ntietje1 Jan 25, 2025
f2b8cf4
refactor useClassroomUser
ntietje1 Jan 25, 2025
0d78898
add initial org select
ntietje1 Jan 25, 2025
a78effe
improve user state and invitation handling
ntietje1 Jan 25, 2025
dbd3bf4
react query refactors
ntietje1 Jan 25, 2025
44c80ea
improve access denied page functionality
ntietje1 Jan 25, 2025
ca985ab
add better handling of edge status cases
ntietje1 Jan 25, 2025
04e5c0d
remove auto select
ntietje1 Jan 25, 2025
a1f6e9a
remove redundant access denied
ntietje1 Jan 25, 2025
7cdd5cb
remove redundant access denied
ntietje1 Jan 25, 2025
aaeab0e
fix classroom does not exist case
ntietje1 Jan 25, 2025
2dcf4d8
refactor + add comments
ntietje1 Jan 25, 2025
8314fe4
add debounce to classroom name check
ntietje1 Jan 25, 2025
4911d0b
fix auth redirect
ntietje1 Jan 29, 2025
451ac28
Merge branch 'main' into merge/react-query-and-access-denied
ntietje1 Jan 29, 2025
b6d3df5
fix http codes
ntietje1 Jan 31, 2025
6491061
use hook for current user
ntietje1 Jan 31, 2025
f4d6a44
fix auth code callback
ntietje1 Jan 31, 2025
4c02a29
squashed react-query-and-access-denied
ntietje1 Jan 31, 2025
07ed306
fix assignment token apply page UI
ntietje1 Jan 31, 2025
3ce1f85
fix assignment token apply page UI
ntietje1 Jan 31, 2025
f31c6e7
add redundant base repo init, laso auto invite on assignment accept
ntietje1 Feb 5, 2025
583d5d2
Merge branch 'main' into feature/classroom-join-on-assignment-accept
ntietje1 Feb 5, 2025
08629b3
disallow invalid characters
ntietje1 Feb 5, 2025
8e54266
revamp student work exists check
ntietje1 Feb 5, 2025
6dd2506
Merge branch 'merge/react-query-and-access-denied' into feature/disal…
ntietje1 Feb 5, 2025
e89cff7
fix nil reference
ntietje1 Feb 5, 2025
4a2fcf6
Merge branch 'feature/classroom-join-on-assignment-accept' into featu…
ntietje1 Feb 5, 2025
abc0054
fix assignment creation name
ntietje1 Feb 5, 2025
1f115c5
add initialized repo field
ntietje1 Feb 5, 2025
d053f25
fix bad merge
ntietje1 Feb 5, 2025
6b33039
disallow duplicate names
ntietje1 Feb 5, 2025
c1f312f
cleanup
ntietje1 Feb 5, 2025
686c714
add additional recovery from desync
ntietje1 Feb 5, 2025
b02fbec
change control logic
ntietje1 Feb 5, 2025
e2dc2c8
Merge branch 'main' into feature/disallow-invalid-assignment-names
ntietje1 Feb 11, 2025
74ad924
fix merge changes
ntietje1 Feb 11, 2025
52acda4
fix spelling
ntietje1 Feb 11, 2025
654279e
add reference to ticket for this TODO
ntietje1 Feb 11, 2025
2e7ad24
fix assignment name validation
ntietje1 Feb 12, 2025
2090aa8
Merge branch 'main' into feature/disallow-invalid-assignment-names
ntietje1 Feb 12, 2025
09e39f8
fix merge
ntietje1 Feb 12, 2025
1adea0a
add '~' and '!' to illegal repo/assignment names
ntietje1 Feb 20, 2025
247369e
add repo name validation for classrooms
ntietje1 Feb 20, 2025
3f08b91
add #
ntietje1 Feb 20, 2025
7ff3047
improve special character validation
ntietje1 Feb 20, 2025
95271f5
Merge branch 'main' into feature/disallow-invalid-assignment-names
ntietje1 Feb 27, 2025
9b4d760
fix syntax error
ntietje1 Mar 1, 2025
fed7f19
add logs and fix accept assignment on mock data bug
ntietje1 Mar 12, 2025
96df693
Merge branch 'main' into feature/disallow-invalid-assignment-names
ntietje1 Mar 12, 2025
de43cc2
Merge branch 'main' into feature/disallow-invalid-assignment-names
ntietje1 Mar 12, 2025
ad03241
Merge branch 'main' into feature/disallow-invalid-assignment-names
ntietje1 Mar 12, 2025
49fe091
Merge branch 'main' into feature/disallow-invalid-assignment-names
ntietje1 Mar 13, 2025
a4b4f68
Merge branch 'main' into feature/disallow-invalid-assignment-names
alexangione419 Mar 19, 2025
d28d9b8
new pic new me
ntietje1 Mar 25, 2025
90bc48c
fix file check
ntietje1 Mar 25, 2025
7e99c53
Merge branch 'main' of https://github.com/NUSpecialProjects/khoury-cl…
ntietje1 Mar 25, 2025
a6a1bc2
refactor + add workaround for enable actions button
ntietje1 Mar 26, 2025
3ce2e7b
Merge branch 'main' of https://github.com/NUSpecialProjects/khoury-cl…
ntietje1 Mar 26, 2025
dac6462
Merge branch 'main' into feature/disallow-invalid-assignment-names
ntietje1 Mar 26, 2025
8980484
reorder to trim first before validation
ntietje1 Mar 30, 2025
9743bb9
improve var name
ntietje1 Mar 30, 2025
8b5c615
Merge branch 'main' into feature/disallow-invalid-assignment-names
alexangione419 Apr 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion backend/database/migrations/001_khouryclassroom.sql
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ CREATE TABLE IF NOT EXISTS assignment_base_repos (
base_repo_id INTEGER PRIMARY KEY,
base_repo_owner VARCHAR(255) NOT NULL,
base_repo_name VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT (NOW() AT TIME ZONE 'UTC')
created_at TIMESTAMP DEFAULT (NOW() AT TIME ZONE 'UTC'),
initialized BOOLEAN DEFAULT FALSE NOT NULL
);

CREATE TABLE IF NOT EXISTS rubrics (
Expand Down
13 changes: 11 additions & 2 deletions backend/internal/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ type GitHubAppClient interface { // All methods in the APP client
// Add a repository permission to a user
AssignPermissionToUser(ctx context.Context, ownerName string, repoName string, userName string, permission string) error

CreateDeadlineEnforcement(ctx context.Context, deadline *time.Time, orgName, repoName, branchName string) error

// Create instance of template repository
CreateRepoFromTemplate(ctx context.Context, orgName, templateRepoName, newRepoName string) (*models.AssignmentBaseRepo, error)
}
Expand All @@ -52,6 +50,12 @@ type GitHubUserClient interface { // All methods in the OAUTH client
// Fork a repository as a student
ForkRepository(ctx context.Context, srcOwner, srcRepo, dstOrg, dstRepo string) error

// Set a branch to a specific commit
SetBranchToCommit(ctx context.Context, owner, repo, branch, sha string) error

// Sync a fork with its upstream repository
SyncForkWithUpstream(ctx context.Context, owner, repo, branch string) error

// Create initial feedback pull request
CreateFeedbackPR(ctx context.Context, owner, repo string) error
}
Expand Down Expand Up @@ -158,4 +162,9 @@ type GitHubBaseClient interface { //All methods in the SHARED client
EnableWorkflow(ctx context.Context, repoOwner, forkName, workflowName string) error

EnableActions(ctx context.Context, ownerName, repoName string) error

// Check if a file or directory exists in a repository
FileExists(owner string, repo string, path string) (bool, error)

CreateDeadlineEnforcement(ctx context.Context, deadline *time.Time, orgName, repoName, branchName string) error
}
160 changes: 90 additions & 70 deletions backend/internal/github/sharedclient/sharedclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/base64"
"fmt"
"time"

"github.com/CamPlume1/khoury-classroom/internal/errs"
"github.com/CamPlume1/khoury-classroom/internal/models"
"github.com/google/go-github/github"
Expand Down Expand Up @@ -78,6 +79,11 @@ func (api *CommonAPI) getBranchHead(ctx context.Context, owner, repo, branchName
return &branchRef, nil
}

func (api *CommonAPI) GetBranches(ctx context.Context, owner, repo string) ([]*github.Branch, error) {
branches, _, err := api.Client.Repositories.ListBranches(ctx, owner, repo, nil)
return branches, err
}

func (api *CommonAPI) CreateBranch(ctx context.Context, owner, repo, baseBranch, newBranchName string) (*github.Reference, error) {
endpoint := fmt.Sprintf("/repos/%s/%s/git/refs", owner, repo)

Expand Down Expand Up @@ -196,8 +202,6 @@ func (api *CommonAPI) GetUser(ctx context.Context, userName string) (*github.Use
return user, err
}



func (api *CommonAPI) createRuleSet(ctx context.Context, ruleset interface{}, orgName, repoName string) error {
endpoint := fmt.Sprintf("/repos/%s/%s/rulesets", orgName, repoName)
req, err := api.Client.NewRequest("POST", endpoint, ruleset)
Expand All @@ -208,7 +212,7 @@ func (api *CommonAPI) createRuleSet(ctx context.Context, ruleset interface{}, or
return err
}

//Given a repo name and org name, create a push ruleset to protect the .github directory
// Given a repo name and org name, create a push ruleset to protect the .github directory
func (api *CommonAPI) CreatePushRuleset(ctx context.Context, orgName, repoName string) error {
body := map[string]interface{}{
"name": "Restrict .github Directory Edits: Preserves Submission Deadline",
Expand All @@ -226,12 +230,10 @@ func (api *CommonAPI) CreatePushRuleset(ctx context.Context, orgName, repoName s
return api.createRuleSet(ctx, body, orgName, repoName)
}



func (api *CommonAPI) CreateBranchRuleset(ctx context.Context, orgName, repoName string) error {
func (api *CommonAPI) CreateBranchRuleset(ctx context.Context, orgName, repoName string) error {
body := map[string]interface{}{
"name": "Feedback and Main Branch Protedtion: PR Enforcement",
"target": "branch",
"name": "Feedback and Main Branch Protedtion: PR Enforcement",
"target": "branch",
"enforcement": "active",
"conditions": map[string]interface{}{
"ref_name": map[string]interface{}{
Expand All @@ -246,72 +248,63 @@ func (api *CommonAPI) CreateBranchRuleset(ctx context.Context, orgName, repoNam

// KHO-315
/*
map[string]interface{}{
"type": "deletion",
},
map[string]interface{}{
"type": "deletion",
},
*/
/*
map[string]interface{}{
"type": "update",
"parameters": map[string]interface{}{
"update_allows_fetch_and_merge": true,
},
},
*/
map[string]interface{}{
"type": "update",
"parameters": map[string]interface{}{
"update_allows_fetch_and_merge": true,
},
},
*/
map[string]interface{}{
"type": "pull_request",
"parameters" : map[string]interface{}{
"required_approving_review_count": 0,
"dismiss_stale_reviews_on_push": true,
"require_code_owner_review": false,
"require_last_push_approval": false,
"required_review_thread_resolution": false,
"automatic_copilot_code_review_enabled": false,
"parameters": map[string]interface{}{
"required_approving_review_count": 0,
"dismiss_stale_reviews_on_push": true,
"require_code_owner_review": false,
"require_last_push_approval": false,
"required_review_thread_resolution": false,
"automatic_copilot_code_review_enabled": false,
},
},
map[string]interface{}{
"type": "required_status_checks",
"parameters": map[string]interface{}{
"strict_required_status_checks_policy": false,
"do_not_enforce_on_create": false,
"do_not_enforce_on_create": false,
"required_status_checks": []map[string]string{
map[string]string{
{
"context": "deadline-enforcement",
},
map[string]string{
{
"context": "check-pr-target-branch",
},

},

},
},
},
}
return api.createRuleSet(ctx, body, orgName, repoName)
}





func (api *CommonAPI) CreateDeadlineEnforcement(ctx context.Context, deadline *time.Time, orgName, repoName, branchName string) error {
addition := models.RepositoryAddition{
FilePath: ".github/workflows/deadline-enforcement.yml",
RepoName: repoName,
OwnerName: orgName,
FilePath: ".github/workflows/deadline-enforcement.yml",
RepoName: repoName,
OwnerName: orgName,
DestinationBranch: branchName,
Content: actionWithDeadline(repoName),
CommitMessage: "Deadline enforcement GH action files",
Content: actionWithDeadline(),
CommitMessage: "Deadline enforcement GH action files",
}
return api.EditRepository(ctx, &addition)

}


func actionWithDeadline(repoName string) string {
fmt.Printf(repoName)
var scriptString = `name: deadline-enforcement
func actionWithDeadline() string {
var scriptString = `name: deadline-enforcement

on:
pull_request:
Expand Down Expand Up @@ -345,13 +338,12 @@ jobs:
echo "::warning::Unexpected response: $CONTENT"
exit 1
fi`
return scriptString

return scriptString
}


func targetBranchProtectionAction() string {
var actionString = `name: check-pr-target-branch

func targetBranchProtectionAction() string {
var actionString = `name: check-pr-target-branch

on:
pull_request:
Expand All @@ -367,42 +359,64 @@ jobs:
echo "Error: Pull requests targeting the 'feedback' branch are not allowed"
exit 1
fi`
return actionString
}

return actionString
}

func (api *CommonAPI) CreatePREnforcement(ctx context.Context, orgName, repoName, branchName string) error {

addition := models.RepositoryAddition{
FilePath: ".github/workflows/check-pr-target-branch.yml",
RepoName: repoName,
OwnerName: orgName,
FilePath: ".github/workflows/check-pr-target-branch.yml",
RepoName: repoName,
OwnerName: orgName,
DestinationBranch: branchName,
Content: targetBranchProtectionAction(),
CommitMessage: "Deadline enforcement GH action files",
Content: targetBranchProtectionAction(),
CommitMessage: "Deadline enforcement GH action files",
}
return api.EditRepository(ctx, &addition)

}

func (api *CommonAPI) EditRepository(ctx context.Context, addition *models.RepositoryAddition) error {
// Get the current file info if it exists
endpoint := fmt.Sprintf("/repos/%s/%s/contents/%s", addition.OwnerName, addition.RepoName, addition.FilePath)
encodedContent := base64.StdEncoding.EncodeToString([]byte(addition.Content))
req, err := api.Client.NewRequest("GET", endpoint, nil)
if err != nil {
fmt.Println("Error getting current file info", err)
return err
}

var existingFile struct {
SHA string `json:"sha"`
}
_, err = api.Client.Do(ctx, req, &existingFile)

encodedContent := base64.StdEncoding.EncodeToString([]byte(addition.Content))
body := map[string]interface{}{
"message": addition.CommitMessage,
"content": encodedContent,
"branch": addition.DestinationBranch,
"branch": addition.DestinationBranch,
}
req, err := api.Client.NewRequest("PUT", endpoint, body)

// If the file already exists, include its SHA
if err == nil && existingFile.SHA != "" {
body["sha"] = existingFile.SHA
}

// Make the update request
req, err = api.Client.NewRequest("PUT", endpoint, body)
if err != nil {
fmt.Println("Error creating update request", err)
return err
}
_, err = api.Client.Do(ctx, req, nil)
return err
}

_, err = api.Client.Do(ctx, req, nil)
if err != nil {
fmt.Println("Error updating file", err)
return err
}

return nil
}

func (api *CommonAPI) InviteUserToOrganization(ctx context.Context, orgName string, userID int64) error {
body := map[string]interface{}{
Expand Down Expand Up @@ -723,7 +737,6 @@ func (api *CommonAPI) CheckForkIsReady(ctx context.Context, repo *github.Reposit
return len(branches) == len(srcBranches)
}


func (api *CommonAPI) EnableWorkflow(ctx context.Context, ownerName, repoName, workflowName string) error {
endpoint := fmt.Sprintf("/repos/%s/%s/actions/worflows/%s/enable", ownerName, repoName, workflowName)

Expand All @@ -733,17 +746,16 @@ func (api *CommonAPI) EnableWorkflow(ctx context.Context, ownerName, repoName, w
}

_, err = api.Client.Do(ctx, req, nil)

return err
}


// /repos/{owner}/{repo}/actions/permissions
func (api *CommonAPI) EnableActions(ctx context.Context, ownerName, repoName string) error {
endpoint := fmt.Sprintf("/repos/%s/%s/actions/permissions", ownerName, repoName)

body := map[string]interface{}{
"enabled": true,
"enabled": true,
"allowed_actions": "all",
}

Expand All @@ -753,6 +765,14 @@ func (api *CommonAPI) EnableActions(ctx context.Context, ownerName, repoName str
}

_, err = api.Client.Do(ctx, req, nil)

return err
}
}

func (api *CommonAPI) FileExists(owner string, repo string, path string) (bool, error) {
fileContent, directoryContents, _, err := api.Client.Repositories.GetContents(context.Background(), owner, repo, path, nil)
if err != nil {
return false, fmt.Errorf("error fetching contents: %v", err)
}
return fileContent != nil || directoryContents != nil, nil
}
Loading
Loading