From 0a678badb3804b57c31889762cfb97d98528eec9 Mon Sep 17 00:00:00 2001 From: Braeden57 Date: Tue, 5 Oct 2021 21:23:36 -0700 Subject: [PATCH] Enroll Student and Register Teacher api done --- controllers/authController.go | 160 ++++++++++++++++++++++++++++++---- main.go | 3 +- models/contactModel.go | 24 ++--- models/studentModel.go | 118 +++++++++++++++++++------ models/teacherModel.go | 121 +++++++++++++++++++++---- routes/routes.go | 21 ++++- 6 files changed, 375 insertions(+), 72 deletions(-) diff --git a/controllers/authController.go b/controllers/authController.go index 644249c..60e3cd8 100644 --- a/controllers/authController.go +++ b/controllers/authController.go @@ -1,21 +1,23 @@ package controllers import ( + "school-management/database" "school-management/models" + "time" "strconv" "github.com/gofiber/fiber/v2" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" ) -type Test struct { - a string - b int +type ErrorStruct struct { + Error string } -func (t *Test) getA() string { - return t.a -} +var teacherCollection *mongo.Collection = database.OpenCollection(database.Client, "teachers") +var studentCollection *mongo.Collection = database.OpenCollection(database.Client, "students") func Enroll(c *fiber.Ctx) error { var data map[string]string @@ -24,19 +26,145 @@ func Enroll(c *fiber.Ctx) error { return err } + // Check minimum enroll field requirements are met + if data["firstname"] == "" || data["lastname"] == "" || data["age"] == "" || data["gradelevel"] == "" || data["dob"] == "" || data["email"] == "" { + return c.Status(400).JSON(ErrorStruct{Error: "missing required fields"}) + } + // Get age and grade level and convert to int intAge, _ := strconv.Atoi(data["age"]) intGradeLevel, _ := strconv.Atoi(data["gradelevel"]) - student := models.Student{ - FirstName: data["firstname"], - LastName: data["lastname"], - Age: intAge, - GradeLevel: intGradeLevel, - DOB: data["dob"], - } - student.Password = student.HashPassword(data["password"]) - student.Email = student.GenerateSchoolEmail() + student := models.Student{} + student.FirstName = data["firstname"] + student.MiddleName = data["middlename"] + student.LastName = data["lastname"] + student.Age = intAge + student.GradeLevel = intGradeLevel + student.DOB = data["dob"] + student.Email = data["email"] + student.Province = data["province"] + student.City = data["city"] + student.Address = data["address"] + student.Postal = data["postal"] - return c.JSON(student) + student.YOG = ((12 - student.GradeLevel) + time.Now().Year()) + 1 + + student.SchoolEmail = student.GenerateSchoolEmail() + + tempPass := student.GeneratePassword(12, 1, 1, 1) + student.Password = student.HashPassword(tempPass) + student.TempPassword = true + // Send student personal email temp password + + student.Created_at, _ = time.Parse(time.RFC3339, time.Now().Format(time.RFC3339)) + student.Updated_at, _ = time.Parse(time.RFC3339, time.Now().Format(time.RFC3339)) + student.ID = primitive.NewObjectID() + + result, insertErr := studentCollection.InsertOne(c.Context(), student) + if insertErr != nil { + return c.Status(500).JSON(ErrorStruct{Error: "the student could not be inserted"}) + } + + return c.Status(201).JSON(result) +} + +func RegisterTeacher(c *fiber.Ctx) error { + var data map[string]string + + if err := c.BodyParser(&data); err != nil { + return err + } + + // Check minimum register teacher field requirements are met + if data["firstname"] == "" || data["lastname"] == "" || data["dob"] == "" || data["email"] == "" { + return c.Status(400).JSON(ErrorStruct{Error: "missing required fields"}) + } + + teacher := models.Teacher{} + teacher.FirstName = data["firstname"] + teacher.LastName = data["lastname"] + teacher.Email = data["email"] + + teacher.SchoolEmail = teacher.GenerateSchoolEmail() + + tempPass := teacher.GeneratePassword(12, 1, 1, 1) + teacher.Password = teacher.HashPassword(tempPass) + teacher.TempPassword = true + // Send teacher personal email temp password + + teacher.Created_at, _ = time.Parse(time.RFC3339, time.Now().Format(time.RFC3339)) + teacher.Updated_at, _ = time.Parse(time.RFC3339, time.Now().Format(time.RFC3339)) + teacher.ID = primitive.NewObjectID() + + result, insertErr := teacherCollection.InsertOne(c.Context(), teacher) + if insertErr != nil { + return c.Status(500).JSON(ErrorStruct{Error: "the teacher could not be inserted"}) + } + + return c.Status(201).JSON(result) +} + +func UpdateStudentName(c *fiber.Ctx) error { + return c.JSON("status:ok") +} + +func UpdateStudentGradeLevel(c *fiber.Ctx) error { + return c.JSON("status:ok") +} + +func UpdateStudentHomeroom(c *fiber.Ctx) error { + return c.JSON("status:ok") +} + +func UpdateStudentPassword(c *fiber.Ctx) error { + return c.JSON("status:ok") +} + +func UpdateStudentLocker(c *fiber.Ctx) error { + return c.JSON("status:ok") +} + +func UpdateStudentAddress(c *fiber.Ctx) error { + return c.JSON("status:ok") +} + +func UpdateStudentYOG(c *fiber.Ctx) error { + return c.JSON("status:ok") +} + +func UpdateStudentContacts(c *fiber.Ctx) error { + return c.JSON("status:ok") +} + +func UpdateStudentPhoto(c *fiber.Ctx) error { + return c.JSON("status:ok") +} + +func UpdateStudentEmail(c *fiber.Ctx) error { + return c.JSON("status:ok") +} + +func UpdateTeacherHomeroom(c *fiber.Ctx) error { + return c.JSON("status:ok") +} + +func UpdateTeacherPassword(c *fiber.Ctx) error { + return c.JSON("status:ok") +} + +func UpdateTeacherAddress(c *fiber.Ctx) error { + return c.JSON("status:ok") +} + +func UpdateTeacherPhoto(c *fiber.Ctx) error { + return c.JSON("status:ok") +} + +func UpdateTeacherEmail(c *fiber.Ctx) error { + return c.JSON("status:ok") +} + +func UpdateTeacherName(c *fiber.Ctx) error { + return c.JSON("status:ok") } diff --git a/main.go b/main.go index 7a0bbfb..43671eb 100644 --- a/main.go +++ b/main.go @@ -9,8 +9,7 @@ import ( "go.mongodb.org/mongo-driver/mongo" ) -var client *mongo.Client = database.DBinstance() -var studentCollection *mongo.Collection = database.OpenCollection(client, "students") +var studentCollection *mongo.Collection = database.OpenCollection(database.Client, "students") func main() { app := fiber.New() diff --git a/models/contactModel.go b/models/contactModel.go index 55136fe..71fccb9 100644 --- a/models/contactModel.go +++ b/models/contactModel.go @@ -7,16 +7,16 @@ import ( ) type Contact struct { - ID primitive.ObjectID `bson:"_id"` - FirstName string `json:"firstname" validate:"required"` - MiddleName string `json:"middlename"` - LastName string `json:"lastname" validate:"required"` - Address string `json:"address" validate:"required"` - Phone string `json:"phone" validate:"required"` - SecondaryPhone string `json:"secondaryphone"` - Email string `json:"email" validate:"required"` - Relation string `json:"relation" validate:"required"` - PrimaryContact bool `json:"primaraycontact" validate:"required"` - Created_at time.Time `json:"created_at"` - Updated_at time.Time `json:"updated_at"` + ID primitive.ObjectID `bson:"_id"` + FirstName string `json:"firstname" validate:"required"` + MiddleName string `json:"middlename"` + LastName string `json:"lastname" validate:"required"` + Address string `json:"address" validate:"required"` + HomePhone string `json:"homephone" validate:"required"` + WorkPhone string `json:"workphone"` + Email string `json:"email" validate:"required"` + Relation string `json:"relation" validate:"required"` + Priotrity int `json:"priority" validate:"required"` + Created_at time.Time `json:"created_at"` + Updated_at time.Time `json:"updated_at"` } diff --git a/models/studentModel.go b/models/studentModel.go index dc184ae..27c03e5 100644 --- a/models/studentModel.go +++ b/models/studentModel.go @@ -1,8 +1,10 @@ package models import ( + "math/rand" "strings" "time" + "unicode" "golang.org/x/crypto/bcrypt" @@ -10,33 +12,35 @@ import ( ) type Student struct { - ID primitive.ObjectID `bson:"_id"` - FirstName string `json:"firstname" validate:"required"` - MiddleName string `json:"middlename"` - LastName string `json:"lastname" validate:"required"` - Age int `json:"age" validate:"required"` - GradeLevel int `json:"gradelevel" validate:"required"` - Email string `json:"email" validate:"required"` - Password []byte `json:"password" validate:"required,min=8,max=32"` - SID string `json:"sid"` // Student ID - PED string `json:"ped"` // Personal Education Number - Homeroom string `json:"homeroom"` - Locker string `json:"locker"` - YOG string `json:"yog"` // Year of Graduation - Address string `json:"address"` - City string `json:"city"` - Province string `json:"province"` - PC string `json:"pc"` // Postal Code - DOB string `json:"dob" validate:"required"` - Photo string `json:"photo"` - Contacts []Contact `json:"contacts"` - Created_at time.Time `json:"created_at"` - Updated_at time.Time `json:"updated_at"` + ID primitive.ObjectID `bson:"_id"` + FirstName string `json:"firstname" validate:"required"` + MiddleName string `json:"middlename"` + LastName string `json:"lastname" validate:"required"` + Age int `json:"age" validate:"required"` + GradeLevel int `json:"gradelevel" validate:"required"` + Email string `json:"email" validate:"required"` + SchoolEmail string `json:"schoolemail"` + Password string `json:"password" validate:"min=10,max=32"` + TempPassword bool `json:"temppassword"` + SID string `json:"sid"` // Student ID + PEN string `json:"ped"` // Personal Education Number + Homeroom string `json:"homeroom"` + Locker string `json:"locker"` + YOG int `json:"yog"` // Year of Graduation + Address string `json:"address"` + City string `json:"city"` + Province string `json:"province"` + Postal string `json:"pc"` // Postal Code + DOB string `json:"dob" validate:"required"` + Photo string `json:"photo"` + Contacts []Contact `json:"contacts"` + Created_at time.Time `json:"created_at"` + Updated_at time.Time `json:"updated_at"` } -func (s *Student) HashPassword(password string) []byte { - hashPass, _ := bcrypt.GenerateFromPassword([]byte(password), 14) - return hashPass +func (s *Student) HashPassword(password string) string { + hash, _ := bcrypt.GenerateFromPassword([]byte(password), 14) + return string(hash) } func (s *Student) GenerateSchoolEmail() string { @@ -44,3 +48,67 @@ func (s *Student) GenerateSchoolEmail() string { // Add check to see if email already exists return email } + +func (s *Student) ComparePasswords(password string) bool { + err := bcrypt.CompareHashAndPassword([]byte(s.Password), []byte(password)) + if err != nil { + return false + } + return true +} + +func (s *Student) CheckPasswordStrength(password string) bool { + + var hasUpper bool = true + for _, r := range password { + if !unicode.IsUpper(r) && unicode.IsLetter(r) { + hasUpper = false + } + } + + var hasLower bool = true + for _, r := range password { + if !unicode.IsLower(r) && unicode.IsLetter(r) { + hasLower = false + } + } + + if strings.ContainsAny(password, specialCharSet) && hasLower && hasUpper { + return true + } else { + return false + } +} + +func (s *Student) GeneratePassword(passwordLength, minSpecialChar, minNum, minUpperCase int) string { + var password strings.Builder + + //Set special character + for i := 0; i < minSpecialChar; i++ { + random := rand.Intn(len(specialCharSet)) + password.WriteString(string(specialCharSet[random])) + } + + //Set numeric + for i := 0; i < minNum; i++ { + random := rand.Intn(len(numberSet)) + password.WriteString(string(numberSet[random])) + } + + //Set uppercase + for i := 0; i < minUpperCase; i++ { + random := rand.Intn(len(upperCharSet)) + password.WriteString(string(upperCharSet[random])) + } + + remainingLength := passwordLength - minSpecialChar - minNum - minUpperCase + for i := 0; i < remainingLength; i++ { + random := rand.Intn(len(allCharSet)) + password.WriteString(string(allCharSet[random])) + } + inRune := []rune(password.String()) + rand.Shuffle(len(inRune), func(i, j int) { + inRune[i], inRune[j] = inRune[j], inRune[i] + }) + return string(inRune) +} diff --git a/models/teacherModel.go b/models/teacherModel.go index c82228c..921e152 100644 --- a/models/teacherModel.go +++ b/models/teacherModel.go @@ -1,26 +1,115 @@ package models import ( + "math/rand" + "strings" "time" + "unicode" "go.mongodb.org/mongo-driver/bson/primitive" + "golang.org/x/crypto/bcrypt" +) + +var ( + lowerCharSet = "abcdedfghijklmnopqrst" + upperCharSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + specialCharSet = "!@#$%&*?,.`~" + numberSet = "0123456789" + allCharSet = lowerCharSet + upperCharSet + specialCharSet + numberSet ) type Teacher struct { - ID primitive.ObjectID `bson:"_id"` - FirstName string `json:"firstname" validate:"required"` - MiddleName string `json:"middlename"` - LastName string `json:"lastname" validate:"required"` - Email string `json:"email" validate:"required"` - Password string `json:"password" validate:"required"` - TID string `json:"tid"` // Teacher ID - Homeroom string `json:"homeroom"` - Address string `json:"address"` - City string `json:"city"` - Province string `json:"province"` - PC string `json:"pc"` // Postal Code - DOB string `json:"dob" validate:"required"` - Photo string `json:"string"` - Created_at time.Time `json:"created_at"` - Updated_at time.Time `json:"updated_at"` + ID primitive.ObjectID `bson:"_id"` + FirstName string `json:"firstname" validate:"required"` + MiddleName string `json:"middlename"` + LastName string `json:"lastname" validate:"required"` + Email string `json:"email" validate:"required"` + SchoolEmail string `json:"schoolemail"` + Password string `json:"password" validate:"min=10,max=32"` + TempPassword bool `json:"temppassword"` + TID string `json:"tid"` // Teacher ID + Homeroom string `json:"homeroom"` + Address string `json:"address"` + City string `json:"city"` + Province string `json:"province"` + Postal string `json:"pc"` // Postal Code + DOB string `json:"dob" validate:"required"` + Photo string `json:"string"` + Created_at time.Time `json:"created_at"` + Updated_at time.Time `json:"updated_at"` +} + +func (t *Teacher) HashPassword(password string) string { + hash, _ := bcrypt.GenerateFromPassword([]byte(password), 14) + return string(hash) +} + +func (t *Teacher) GenerateSchoolEmail() string { + var email string = strings.ToLower(string(t.FirstName[0])) + "_" + strings.ToLower(t.LastName) + "@surreyschools.ca" + // Add check to see if email already exists + return email +} + +func (t *Teacher) ComparePasswords(password string) bool { + err := bcrypt.CompareHashAndPassword([]byte(t.Password), []byte(password)) + if err != nil { + return false + } + return true +} + +func (t *Teacher) CheckPasswordStrength(password string) bool { + + var hasUpper bool = true + for _, r := range password { + if !unicode.IsUpper(r) && unicode.IsLetter(r) { + hasUpper = false + } + } + + var hasLower bool = true + for _, r := range password { + if !unicode.IsLower(r) && unicode.IsLetter(r) { + hasLower = false + } + } + + if strings.ContainsAny(password, specialCharSet) && hasLower && hasUpper { + return true + } else { + return false + } +} + +func (t *Teacher) GeneratePassword(passwordLength, minSpecialChar, minNum, minUpperCase int) string { + var password strings.Builder + + //Set special character + for i := 0; i < minSpecialChar; i++ { + random := rand.Intn(len(specialCharSet)) + password.WriteString(string(specialCharSet[random])) + } + + //Set numeric + for i := 0; i < minNum; i++ { + random := rand.Intn(len(numberSet)) + password.WriteString(string(numberSet[random])) + } + + //Set uppercase + for i := 0; i < minUpperCase; i++ { + random := rand.Intn(len(upperCharSet)) + password.WriteString(string(upperCharSet[random])) + } + + remainingLength := passwordLength - minSpecialChar - minNum - minUpperCase + for i := 0; i < remainingLength; i++ { + random := rand.Intn(len(allCharSet)) + password.WriteString(string(allCharSet[random])) + } + inRune := []rune(password.String()) + rand.Shuffle(len(inRune), func(i, j int) { + inRune[i], inRune[j] = inRune[j], inRune[i] + }) + return string(inRune) } diff --git a/routes/routes.go b/routes/routes.go index 651d5f2..3e8ad43 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -12,5 +12,24 @@ type Person struct { } func Setup(app *fiber.App) { - app.Post("/api/enroll", controllers.Enroll) + // API Handling + app.Post("/api/student/enroll", controllers.Enroll) + app.Post("/api/student/updateName", controllers.UpdateStudentName) + app.Post("/api/student/updateGradeLevel", controllers.UpdateStudentGradeLevel) + app.Post("/api/student/updateHomeroom", controllers.UpdateStudentHomeroom) + app.Post("/api/student/updateLocker", controllers.UpdateStudentLocker) + app.Post("/api/studnet/updateYOG", controllers.UpdateStudentYOG) + app.Post("/api/studnet/updateContacts", controllers.UpdateStudentContacts) + app.Post("/api/student/updatePassword", controllers.UpdateStudentPassword) + app.Post("/api/student/updateAddress", controllers.UpdateStudentAddress) + app.Post("/api/student/updatePhoto", controllers.UpdateStudentPhoto) + app.Post("/api/student/updateEmail", controllers.UpdateStudentEmail) + + app.Post("/api/teacher/register", controllers.RegisterTeacher) + app.Post("/api/teacher/updatePassword", controllers.UpdateTeacherPassword) + app.Post("/api/teacher/updateAddress", controllers.UpdateTeacherAddress) + app.Post("/api/teacher/updatePhoto", controllers.UpdateTeacherPhoto) + app.Post("/api/teacher/updateName", controllers.UpdateTeacherName) + app.Post("/api/teacher/updateHomeroom", controllers.UpdateTeacherHomeroom) + app.Post("/api/teacher/updateEmail", controllers.UpdateTeacherEmail) }