Documentation ¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
var CreateForm = func(w http.ResponseWriter, r *http.Request) { rno := GetRollNo(w, r, true) if rno == "" { return } form := &models.Form{} err := json.NewDecoder(r.Body).Decode(form) if err != nil { log.Println(err) u.Respond(w, u.Message(false, err.Error()), 400) return } if len(form.Pages) == 0 { u.Respond(w, u.Message(false, "No Pages"), 400) return } assignUids(form) form.Name = form.Pages[0].Title responseToken := u.RandSeq(50) form.ResponseToken = responseToken collection := u.Collection(r.Context(), "forms") // Update or create new var id interface{} if r.Method == "PUT" { cid := mux.Vars(r)["id"] objID, _ := primitive.ObjectIDFromHex(cid) filt := bson.M{"$and": bson.A{ bson.M{"_id": objID}, bson.M{"creator": rno}}} var res *mongo.UpdateResult res, err = collection.ReplaceOne(r.Context(), filt, form) id = cid if res.MatchedCount == 0 { u.Respond(w, u.Message(false, "Not Found"), 404) return } } else { form.Creator = rno form.Timestamp = time.Now() var res *mongo.InsertOneResult res, err = collection.InsertOne(r.Context(), form) id = res.InsertedID } if err != nil { log.Println(err) u.Respond(w, u.Message(false, err.Error()), 400) return } log.Println(rno, ": new form", id) u.Respond(w, map[string]interface{}{"id": id, "token": responseToken}, 200) }
CreateForm : API handler for POST-ing new forms
var CreateResponse = func(w http.ResponseWriter, r *http.Request) { formid := mux.Vars(r)["formid"] rno := GetRollNo(w, r, false) collection := u.Collection(r.Context(), "forms") objID, _ := primitive.ObjectIDFromHex(formid) filt := bson.M{"_id": objID} form := &models.Form{} collection.FindOne(r.Context(), filt).Decode(form) if form.RequireLogin && rno == "" { u.Respond(w, u.Message(false, "Not Found"), 401) return } year2000 := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC) if form.IsClosed || time.Now().UTC().After(form.CloseOn) && year2000.Before(form.CloseOn) { u.Respond(w, u.Message(false, "Form Closed"), 404) return } response := &models.FormResponse{} err := json.NewDecoder(r.Body).Decode(response) if err != nil { u.Respond(w, u.Message(false, err.Error()), 400) return } response.FormID = formid response.Timestamp = time.Now() response.Responses["timestamp"] = response.Timestamp if form.CollectEmail { response.Filler = rno response.Responses["filler"] = response.Filler } if form.SingleResponse && HasFilledAnon(r.Context(), formid, rno) { u.Respond(w, u.Message(false, "User has already filled this form"), 403) return } if form.RequireLogin { anonResponse := &models.FormAnonResponder{} anonResponse.Filler = rno anonResponse.FormID = formid collection = u.Collection(r.Context(), "filler") collection.InsertOne(r.Context(), anonResponse) } collection = u.Collection(r.Context(), "responses") cur, _ := collection.InsertOne(r.Context(), response) id := cur.InsertedID log.Println(rno, ": new response for form", formid) u.Respond(w, map[string]interface{}{"id": id}, 200) }
CreateResponse : API handler for POST-ing new response
var DeleteForm = func(w http.ResponseWriter, r *http.Request) { cid := mux.Vars(r)["id"] rno := GetRollNo(w, r, false) form := &models.Form{} collection := u.Collection(r.Context(), "forms") objID, _ := primitive.ObjectIDFromHex(cid) err := collection.FindOne(r.Context(), bson.M{"_id": objID}).Decode(&form) if err != nil { u.Respond(w, u.Message(false, err.Error()), 400) return } if rno != form.Creator { u.Respond(w, u.Message(false, "Only form creator can delete form. Unauthorized access"), 403) return } _, err = collection.DeleteOne(r.Context(), bson.M{"_id": objID}) if err != nil { log.Printf("remove fail %v\n", err) } _, err = u.Collection(r.Context(), "responses").DeleteMany(r.Context(), bson.M{"formid": cid}) if err != nil { log.Printf("remove fail %v\n", err) } log.Println("Form", cid, "and its responses deleted") u.Respond(w, u.Message(false, "Form deleted"), 200) }
DeleteForm : API handler for deleting a form
var GetAllForms = func(w http.ResponseWriter, r *http.Request) { rno := GetRollNo(w, r, false) // To extrach data out of collection.Find() type formDB struct { ID primitive.ObjectID `bson:"_id"` Name string `bson:"name"` Token string `bson:"responsetoken"` } // To send data to frontend type formDetails struct { ID string Name string Token string } var forms []formDetails collection := u.Collection(r.Context(), "forms") count, err := collection.CountDocuments(r.Context(), bson.M{"creator": rno}) if count == 0 { u.Respond(w, make([]formDetails, 0), 200) return } // To Set which fields are required in the output type fields struct { ID int `bson:"_id"` Name int `bson:"name"` Token int `bson:"responsetoken"` } projection := fields{ID: 1, Name: 1, Token: 1} opt := &options.FindOptions{} opt.SetSort(bson.D{{"timestamp", -1}}) opt.SetProjection(projection) values, err := collection.Find(r.Context(), bson.M{"creator": rno}, opt) if err != nil { u.Respond(w, u.Message(false, err.Error()), 400) return } for values.Next(context.TODO()) { var elem formDB err := values.Decode(&elem) if err != nil { log.Println(err) } forms = append(forms, formDetails{ID: (&elem).ID.Hex(), Name: (&elem).Name, Token: (&elem).Token}) } log.Println("all forms created by", rno, "sent") u.Respond(w, forms, 200) }
GetAllForms : API handler for getting all forms of the logged in user
var GetForm = func(w http.ResponseWriter, r *http.Request) { id := mux.Vars(r)["id"] form := &models.Form{} collection := u.Collection(r.Context(), "forms") objID, _ := primitive.ObjectIDFromHex(id) err := collection.FindOne(r.Context(), bson.M{"_id": objID}).Decode(&form) if err != nil { u.Respond(w, u.Message(false, err.Error()), 400) return } rno := GetRollNo(w, r, false) if rno != "" { form.CanEdit = rno == form.Creator } if !form.CanEdit && form.SingleResponse && HasFilledAnon(r.Context(), id, rno) { u.Respond(w, u.Message(false, "User has already filled this form"), 403) return } if form.RequireLogin && rno == "" { u.Respond(w, u.Message(false, "Unauthorized: Please login to continue"), 401) return } year2000 := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC) if time.Now().UTC().After(form.CloseOn) && year2000.Before(form.CloseOn) { form.IsClosed = true } u.Respond(w, form, 200) }
GetForm : API handler for getting one form
var GetResponses = func(w http.ResponseWriter, r *http.Request) { rno := GetRollNo(w, r, true) if rno == "" { return } id := mux.Vars(r)["formid"] data := strings.Split(id, "-") formid := data[0] token := data[1] form := &models.Form{} collection := u.Collection(r.Context(), "forms") objID, _ := primitive.ObjectIDFromHex(formid) filt := bson.M{"$and": bson.A{ bson.M{"_id": objID}, bson.M{"responsetoken": token}}} err := collection.FindOne(r.Context(), filt).Decode(&form) if err != nil { u.Respond(w, u.Message(false, err.Error()), 400) return } responses := []*models.FormResponse{} collection = u.Collection(r.Context(), "responses") cur, err := collection.Find(r.Context(), bson.M{"formid": formid}) if err != nil { u.Respond(w, u.Message(false, err.Error()), 400) return } for cur.Next(context.TODO()) { var elem models.FormResponse err := cur.Decode(&elem) if err != nil { log.Println(err) } responses = append(responses, &elem) } rq := &ResponsesRequest{} json.NewDecoder(r.Body).Decode(rq) if rq.Type == "array" { u.Respond(w, arrayResponse(form, responses), 200) return } u.Respond(w, responses, 200) }
GetResponses : API handler for getting JSON responses (for CSV)
var GetRollNo = func(w http.ResponseWriter, r *http.Request, throw bool) string { c, err := r.Cookie("token") if err != nil { if err == http.ErrNoCookie { if throw { w.WriteHeader(http.StatusUnauthorized) } return "" } if throw { w.WriteHeader(http.StatusBadRequest) } return "" } tknStr := c.Value claims := &Claims{} tkn, err := jwt.ParseWithClaims(tknStr, claims, func(token *jwt.Token) (interface{}, error) { return jwtKey, nil }) if !tkn.Valid { if throw { w.WriteHeader(http.StatusUnauthorized) } return "" } if err != nil { if err == jwt.ErrSignatureInvalid { if throw { w.WriteHeader(http.StatusUnauthorized) } return "" } if throw { w.WriteHeader(http.StatusBadRequest) } return "" } return claims.RollNumber }
GetRollNo : helper function to get claimed roll number from JWT
var Login = func(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { rno := GetRollNo(w, r, true) if rno == "" { return } collection := u.Collection(r.Context(), "users") user := &ProfileResponse{} err := collection.FindOne(r.Context(), bson.M{"rollnumber": rno}).Decode(user) if err != nil { u.Respond(w, u.Message(false, err.Error()), 500) return } u.Respond(w, user, 200) return } code := &AuthCode{} err := json.NewDecoder(r.Body).Decode(code) if err != nil { u.Respond(w, u.Message(false, err.Error()), 400) return } url := os.Getenv("OAUTH_URL") authToken := os.Getenv("AUTH_TOKEN") authTemplate := "code=%s&redirect_uri=%s&grant_type=authorization_code" var jsonStr = []byte(fmt.Sprintf(authTemplate, code.Code, code.RedirectURI)) req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr)) req.Header.Set("Authorization", fmt.Sprintf("Basic %s", authToken)) req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") client := &http.Client{} resp, err := client.Do(req) if err != nil { log.Println(err) u.Respond(w, u.Message(false, err.Error()), 401) return } defer resp.Body.Close() if resp.StatusCode != 200 { u.Respond(w, u.Message(false, "Error"), resp.StatusCode) return } accessTokenResponse := &AccessTokenResponse{} err = json.NewDecoder(resp.Body).Decode(accessTokenResponse) if err != nil { log.Println(err) u.Respond(w, u.Message(false, err.Error()), 500) return } profileURL := os.Getenv("OAUTH_PROFILE") req, err = http.NewRequest("GET", profileURL, nil) req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessTokenResponse.AccessToken)) resp, err = client.Do(req) if err != nil { log.Println(err) u.Respond(w, u.Message(false, err.Error()), 500) return } defer resp.Body.Close() profileResponse := &ProfileResponse{} err = json.NewDecoder(resp.Body).Decode(profileResponse) if err != nil { log.Println(err) u.Respond(w, u.Message(false, err.Error()), 500) return } rno := profileResponse.RollNumber collection := u.Collection(r.Context(), "users") // Allow creation var ropts options.ReplaceOptions ropts.SetUpsert(true) _, err = collection.ReplaceOne( r.Context(), bson.M{"rollnumber": rno}, profileResponse, &ropts) SetCookie(w, rno) u.Respond(w, profileResponse, 200) }
Login : API handler for logging in with SSO auth code
var Logout = func(w http.ResponseWriter, r *http.Request) { http.SetCookie(w, &http.Cookie{ Name: "token", Value: "", Expires: time.Unix(0, 0), }) u.Respond(w, "", 204) }
Logout : API handler for logging out
var SetCookie = func(w http.ResponseWriter, rno string) { expirationTime := time.Now().Add(24 * time.Hour) claims := &Claims{ RollNumber: rno, StandardClaims: jwt.StandardClaims{ ExpiresAt: expirationTime.Unix(), }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) tokenString, err := token.SignedString(jwtKey) if err != nil { w.WriteHeader(http.StatusInternalServerError) return } http.SetCookie(w, &http.Cookie{ Name: "token", Value: tokenString, Expires: expirationTime, }) }
SetCookie : helper function to set JWT cookie
Functions ¶
Types ¶
type AccessTokenResponse ¶
type AccessTokenResponse struct { AccessToken string `json:"access_token"` TokenType string `json:"token_type"` ExpiresIn int `json:"expires_in"` RefreshToken string `json:"refresh_token"` Scope string `json:"scope"` }
AccessTokenResponse : access token received from SSO
type Claims ¶
type Claims struct { RollNumber string `json:"roll_number"` jwt.StandardClaims }
Claims : JWT claims stored on client side
type ProfileResponse ¶
type ProfileResponse struct { ID int `json:"id"` FirstName string `json:"first_name"` LastName string `json:"last_name"` RollNumber string `json:"roll_number"` ProfilePicture string `json:"profile_picture"` Email string `json:"email"` }
ProfileResponse : Profile as received from SSO
type ResponsesRequest ¶
type ResponsesRequest struct {
Type string `json:"type"`
}
ResponsesRequest : helper for post processing