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

Endpoints and oauth for organisers #194

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
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
8 changes: 4 additions & 4 deletions controllers/mentor.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func RegisterMentor(w http.ResponseWriter, r *http.Request) {
}

// Check if the JWT login username is the same as the mentor's given username
login_username := r.Context().Value(middleware.LOGIN_CTX_USERNAME_KEY).(string)
login_username := r.Context().Value(middleware.LOGIN_CTX_USERNAME_KEY).(utils.LoginJwtFields).Username

err = utils.DetectSessionHijackAndRespond(r, w, reqFields.Username, login_username, "Login username and given username do not match.")
if err != nil {
Expand Down Expand Up @@ -225,7 +225,7 @@ func FetchMentorDashboard(w http.ResponseWriter, r *http.Request) {

var modelMentor models.Mentor

login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY))
login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY)).(utils.LoginJwtFields).Username
tx := db.
Table("mentors").
Where("username = ?", login_username).
Expand Down Expand Up @@ -278,7 +278,7 @@ func UpdateMentorDetails(w http.ResponseWriter, r *http.Request) {

var modelMentor models.Mentor

login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY))
login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY)).(utils.LoginJwtFields).Username
tx := db.
Table("mentors").
Where("username = ?", login_username).
Expand Down Expand Up @@ -337,7 +337,7 @@ func GetMentorDetails(w http.ResponseWriter, r *http.Request) {
app := r.Context().Value(middleware.APP_CTX_KEY).(*middleware.App)
db := app.Db

login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY))
login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY)).(utils.LoginJwtFields).Username

mentor := models.Mentor{}
tx := db.
Expand Down
30 changes: 30 additions & 0 deletions controllers/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type OAuthResBodyFields struct {

const OAUTH_TYPE_STUDENT string = "student"
const OAUTH_TYPE_MENTOR string = "mentor"
const OAUTH_TYPE_ORGANISER string = "organiser"

// OAuth godoc
//
Expand Down Expand Up @@ -80,6 +81,34 @@ func OAuth(w http.ResponseWriter, r *http.Request) {
return
}

// Check if the user is a organiser

isOrganiser := utils.CheckUserOrgs(accessToken, userInfo.Username)
if isOrganiser {

jwtString, err := utils.GenerateLoginJwtString(utils.LoginJwtFields{
Username: userInfo.Username,
UserType: OAUTH_TYPE_ORGANISER,
})

if err != nil {
utils.LogErrAndRespond(r, w, err, "Error generating a JWT string.", http.StatusInternalServerError)
return
}
resFields := OAuthResBodyFields{
Username: userInfo.Username,
Name: userInfo.Name,
Email: userInfo.Email,
College: "",
Bikram-ghuku marked this conversation as resolved.
Show resolved Hide resolved
Type: OAUTH_TYPE_ORGANISER,
IsNewUser: false,
Bikram-ghuku marked this conversation as resolved.
Show resolved Hide resolved
Jwt: jwtString,
}

utils.RespondWithJson(r, w, resFields)
return
}

// Check if the user has already registered
var isNewUser bool = true
var userType string = reqFields.Type
Expand Down Expand Up @@ -115,6 +144,7 @@ func OAuth(w http.ResponseWriter, r *http.Request) {
// Generate a JWT string for the user
jwtString, err := utils.GenerateLoginJwtString(utils.LoginJwtFields{
Username: userInfo.Username,
UserType: userType,
})
if err != nil {
utils.LogErrAndRespond(r, w, err, "Error generating a JWT string.", http.StatusInternalServerError)
Expand Down
125 changes: 125 additions & 0 deletions controllers/organiser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package controllers

import (
"fmt"
"net/http"
"strings"

"github.com/kossiitkgp/kwoc-backend/v2/middleware"
"github.com/kossiitkgp/kwoc-backend/v2/models"
"github.com/kossiitkgp/kwoc-backend/v2/utils"
)

type AcceptRejectProject struct {
// Id of the project in the database (required)
Id uint `json:"id"`
// Status to be set of the project
ProjectStatus bool `json:"project_status"`
// Status Remark to be set of the project
StatusRemark string `json:"status_remark"`
}

type ProjectOrg struct {
Bikram-ghuku marked this conversation as resolved.
Show resolved Hide resolved
Id uint `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Tags []string `json:"tags"`
RepoLink string `json:"repo_link"`
CommChannel string `json:"comm_channel"`
ReadmeLink string `json:"readme_link"`
Mentor Mentor `json:"mentor"`
SecondaryMentor Mentor `json:"secondary_mentor"`
ProjectStatus bool `json:"project_status"`
StatusRemark string `json:"status_remark"`
}

func newProjectOrg(dbProject *models.Project) ProjectOrg {
tags := make([]string, 0)
if len(dbProject.Tags) != 0 {
tags = strings.Split(dbProject.Tags, ",")
}

return ProjectOrg{
Id: dbProject.ID,
Name: dbProject.Name,
Description: dbProject.Description,
Tags: tags,
RepoLink: dbProject.RepoLink,
CommChannel: dbProject.CommChannel,
ReadmeLink: dbProject.ReadmeLink,
Mentor: newMentor(&dbProject.Mentor),
SecondaryMentor: newMentor(&dbProject.SecondaryMentor),
ProjectStatus: dbProject.ProjectStatus,
StatusRemark: dbProject.StatusRemark,
}
}

func OrgFetchAllProjectDetails(w http.ResponseWriter, r *http.Request) {
app := r.Context().Value(middleware.APP_CTX_KEY).(*middleware.App)
db := app.Db
user_details := r.Context().Value(middleware.LOGIN_CTX_USERNAME_KEY).(utils.LoginJwtFields)

if user_details.UserType != "organiser" {
utils.LogErrAndRespond(r, w, nil, fmt.Sprintf("Error '%s' is not an organiser", user_details.Username), 400)
return
}

var projects []models.Project

tx := db.
Table("projects").
Preload("Mentor").
Preload("SecondaryMentor").
Select("id", "name", "description", "tags", "repo_link", "comm_channel", "readme_link", "mentor_id", "secondary_mentor_id", "project_status", "status_remark", "pull_count").
Find(&projects)

if tx.Error != nil {
utils.LogErrAndRespond(r, w, tx.Error, "Error fetching projects from the database.", http.StatusInternalServerError)
return
}

var response []ProjectOrg = make([]ProjectOrg, 0)

for _, project := range projects {
response = append(response, newProjectOrg(&project))
}

utils.RespondWithJson(r, w, response)
}

func UpdateStatusProject(w http.ResponseWriter, r *http.Request) {
app := r.Context().Value(middleware.APP_CTX_KEY).(*middleware.App)
db := app.Db
user_details := r.Context().Value(middleware.LOGIN_CTX_USERNAME_KEY).(utils.LoginJwtFields)

if user_details.UserType != OAUTH_TYPE_ORGANISER {
utils.LogErrAndRespond(r, w, nil, fmt.Sprintf("Error '%s' is not an organiser", user_details.Username), 400)
return
}

projectDetails := &AcceptRejectProject{}

err := utils.DecodeJSONBody(r, projectDetails)
if err != nil {
utils.LogErrAndRespond(r, w, err, "Error decoding request JSON body.", http.StatusBadRequest)
return
}

tx := db.
Table("projects").
Where("id = ?", projectDetails.Id).
Select("*").
Updates(projectDetails)

if tx.Error != nil {
utils.LogErrAndRespond(r, w, tx.Error, "Error updating the project.", http.StatusInternalServerError)
return
}

if projectDetails.ProjectStatus {
utils.RespondWithHTTPMessage(r, w, http.StatusOK, "Project accepted successfully.")
} else {
utils.RespondWithHTTPMessage(r, w, http.StatusOK, "Project Rejected successfully.")
}

}
2 changes: 1 addition & 1 deletion controllers/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func FetchProfile(w http.ResponseWriter, r *http.Request) {
app := r.Context().Value(middleware.APP_CTX_KEY).(*middleware.App)
db := app.Db

username := r.Context().Value(middleware.LOGIN_CTX_USERNAME_KEY).(string)
username := r.Context().Value(middleware.LOGIN_CTX_USERNAME_KEY).(utils.LoginJwtFields).Username

// Check if the student already exists in the db
student := models.Student{}
Expand Down
2 changes: 1 addition & 1 deletion controllers/project_fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func FetchProjectDetails(w http.ResponseWriter, r *http.Request) {
app := r.Context().Value(middleware.APP_CTX_KEY).(*middleware.App)
db := app.Db

login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY))
login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY)).(utils.LoginJwtFields).Username

project := models.Project{}
tx := db.
Expand Down
4 changes: 2 additions & 2 deletions controllers/project_reg.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ func RegisterProject(w http.ResponseWriter, r *http.Request) {
return
}

login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY))
login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY)).(utils.LoginJwtFields).Username

err = utils.DetectSessionHijackAndRespond(r, w, reqFields.MentorUsername, login_username.(string), "Login username and mentor username do not match.")
err = utils.DetectSessionHijackAndRespond(r, w, reqFields.MentorUsername, login_username, "Login username and mentor username do not match.")
if err != nil {
return
}
Expand Down
4 changes: 2 additions & 2 deletions controllers/project_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ func UpdateProject(w http.ResponseWriter, r *http.Request) {
return
}

login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY))
login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY)).(utils.LoginJwtFields).Username

err = utils.DetectSessionHijackAndRespond(r, w, reqFields.MentorUsername, login_username.(string), "Login username and mentor username do not match.")
err = utils.DetectSessionHijackAndRespond(r, w, reqFields.MentorUsername, login_username, "Login username and mentor username do not match.")
if err != nil {
return
}
Expand Down
10 changes: 5 additions & 5 deletions controllers/student.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func RegisterStudent(w http.ResponseWriter, r *http.Request) {
}

// Check if the JWT login username is the same as the student's given username
login_username := r.Context().Value(middleware.LOGIN_CTX_USERNAME_KEY).(string)
login_username := r.Context().Value(middleware.LOGIN_CTX_USERNAME_KEY).(utils.LoginJwtFields).Username

err = utils.DetectSessionHijackAndRespond(r, w, reqFields.Username, login_username, "Login username and given username do not match.")
if err != nil {
Expand Down Expand Up @@ -174,7 +174,7 @@ func StudentBlogLink(w http.ResponseWriter, r *http.Request) {
}

// Check if the JWT login username is the same as the student's given username
login_username := r.Context().Value(middleware.LOGIN_CTX_USERNAME_KEY).(string)
login_username := r.Context().Value(middleware.LOGIN_CTX_USERNAME_KEY).(utils.LoginJwtFields).Username

err = utils.DetectSessionHijackAndRespond(r, w, reqFields.Username, login_username, "Login username and given username do not match.")
if err != nil {
Expand Down Expand Up @@ -287,7 +287,7 @@ func FetchStudentDashboard(w http.ResponseWriter, r *http.Request) {

var modelStudent models.Student

login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY))
login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY)).(utils.LoginJwtFields).Username
tx := db.
Table("students").
Where("username = ?", login_username).
Expand Down Expand Up @@ -323,7 +323,7 @@ func UpdateStudentDetails(w http.ResponseWriter, r *http.Request) {

var modelStudent models.Student

login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY))
login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY)).(utils.LoginJwtFields).Username
tx := db.
Table("students").
Where("username = ?", login_username).
Expand Down Expand Up @@ -373,7 +373,7 @@ func GetStudentDetails(w http.ResponseWriter, r *http.Request) {
app := r.Context().Value(middleware.APP_CTX_KEY).(*middleware.App)
db := app.Db

login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY))
login_username := r.Context().Value(middleware.LoginCtxKey(middleware.LOGIN_CTX_USERNAME_KEY)).(utils.LoginJwtFields).Username

student := models.Student{}
tx := db.
Expand Down
2 changes: 1 addition & 1 deletion middleware/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func WithLogin(inner http.HandlerFunc) http.HandlerFunc {
}

reqContext := r.Context()
newContext := context.WithValue(reqContext, LoginCtxKey(LOGIN_CTX_USERNAME_KEY), claims.LoginJwtFields.Username)
newContext := context.WithValue(reqContext, LoginCtxKey(LOGIN_CTX_USERNAME_KEY), claims.LoginJwtFields)

inner.ServeHTTP(w, r.WithContext(newContext))
})
Expand Down
13 changes: 13 additions & 0 deletions server/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ func getRoutes(app *middleware.App) []Route {
"/project/",
middleware.WrapApp(app, controllers.FetchAllProjects),
false,
}, {
"Get All Projects For Admins",
"GET",
"/project/all",
middleware.WithLogin(middleware.WrapApp(app, controllers.OrgFetchAllProjectDetails)),
false,
},
{
"Update Project Details",
Expand Down Expand Up @@ -165,5 +171,12 @@ func getRoutes(app *middleware.App) []Route {
middleware.WrapApp(app, controllers.FetchAllProjectStats),
false,
},
{
"Accept/Reject Project",
"POST",
"/project/updt_status",
Bikram-ghuku marked this conversation as resolved.
Show resolved Hide resolved
middleware.WithLogin(middleware.WrapApp(app, controllers.UpdateStatusProject)),
false,
},
}
}
1 change: 1 addition & 0 deletions utils/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func jwtKeyFunc(*jwt.Token) (interface{}, error) {

type LoginJwtFields struct {
Username string `json:"username"`
UserType string `json:"type"`
}

type LoginJwtClaims struct {
Expand Down
18 changes: 18 additions & 0 deletions utils/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,21 @@ func GetOauthUserInfo(accessToken string) (*GHUserInfo, error) {

return &userInfo, nil
}

func CheckUserOrgs(accessToken string, username string) bool {
Bikram-ghuku marked this conversation as resolved.
Show resolved Hide resolved

client := http.Client{}
url := fmt.Sprintf("https://api.github.com/orgs/kossiitkgp/teams/executies/memberships/%s", username)
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add(
"Authorization",
fmt.Sprintf("Bearer %s", accessToken),
)
resp, _ := client.Do(req)

if resp.StatusCode == 200 {
return true
} else {
return false
}
}
Loading