|
|
|
package controllers
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
"tugas1/initializers"
|
|
|
|
"tugas1/models"
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/golang-jwt/jwt/v4"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
)
|
|
|
|
|
|
|
|
func PostsCreate(c *gin.Context) {
|
|
|
|
// Get dataoff req body
|
|
|
|
var body struct {
|
|
|
|
Name string
|
|
|
|
Email string
|
|
|
|
Password string
|
|
|
|
Gender string
|
|
|
|
Address string
|
|
|
|
Tempat string
|
|
|
|
TLahir string
|
|
|
|
}
|
|
|
|
|
|
|
|
c.Bind((&body))
|
|
|
|
|
|
|
|
// Create a post
|
|
|
|
post := models.Post{Name: body.Name, Email: body.Email, Password: body.Password, Gender: body.Gender,
|
|
|
|
Address: body.Address, Tempat: body.Tempat, TLahir: body.TLahir}
|
|
|
|
|
|
|
|
result := initializers.DB.Create(&post)
|
|
|
|
|
|
|
|
if result.Error != nil {
|
|
|
|
c.Status(400)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return it
|
|
|
|
c.JSON(200, gin.H{
|
|
|
|
"post": post,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func PostsIndex(c *gin.Context) {
|
|
|
|
// Get the posts
|
|
|
|
var posts []models.Post
|
|
|
|
initializers.DB.Find(&posts)
|
|
|
|
|
|
|
|
// Respond with them
|
|
|
|
c.JSON(200, gin.H{
|
|
|
|
"posts": posts,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func PostsShow(c *gin.Context) {
|
|
|
|
// Get id off url
|
|
|
|
id := c.Param("id")
|
|
|
|
|
|
|
|
// Get the posts
|
|
|
|
var post models.Post
|
|
|
|
initializers.DB.First(&post, id)
|
|
|
|
|
|
|
|
// Respond with them
|
|
|
|
c.JSON(200, gin.H{
|
|
|
|
"post": post,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func PostsUpdate(c *gin.Context) {
|
|
|
|
// Get the id off the url
|
|
|
|
id := c.Param("id")
|
|
|
|
|
|
|
|
// Get the data off req body
|
|
|
|
var body struct {
|
|
|
|
Name string
|
|
|
|
Email string
|
|
|
|
Password string
|
|
|
|
Gender string
|
|
|
|
Address string
|
|
|
|
Tempat string
|
|
|
|
TLahir string
|
|
|
|
}
|
|
|
|
|
|
|
|
c.Bind(&body)
|
|
|
|
|
|
|
|
// Find the post were updating
|
|
|
|
var post models.Post
|
|
|
|
initializers.DB.First(&post, id)
|
|
|
|
|
|
|
|
// Updated it
|
|
|
|
initializers.DB.Model(&post).Updates(models.Post{
|
|
|
|
Name: body.Name,
|
|
|
|
Email: body.Email,
|
|
|
|
Password: body.Password,
|
|
|
|
Gender: body.Gender,
|
|
|
|
Address: body.Address,
|
|
|
|
Tempat: body.Tempat,
|
|
|
|
TLahir: body.TLahir,
|
|
|
|
})
|
|
|
|
|
|
|
|
// Respond with it
|
|
|
|
c.JSON(200, gin.H{
|
|
|
|
"post": post,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func PostsDelete(c *gin.Context) {
|
|
|
|
// Get the id off the url
|
|
|
|
id := c.Param("id")
|
|
|
|
|
|
|
|
// Delete the posts
|
|
|
|
initializers.DB.Delete(&models.Post{}, id)
|
|
|
|
|
|
|
|
// Respond
|
|
|
|
c.Status(200)
|
|
|
|
}
|
|
|
|
func SignUp(c *gin.Context) {
|
|
|
|
var body struct {
|
|
|
|
Email string
|
|
|
|
Password string
|
|
|
|
Nik string
|
|
|
|
Name string
|
|
|
|
Photo string
|
|
|
|
Birthdate time.Time
|
|
|
|
JobTitle string
|
|
|
|
CreatedBy string
|
|
|
|
UpdatedBy string
|
|
|
|
DeletedBy string
|
|
|
|
}
|
|
|
|
if err := c.ShouldBindJSON(&body); err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
|
|
"error": "Failed to read body",
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(body.Password), 10)
|
|
|
|
if err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
|
|
"error": "Failed to generate password hash",
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
user := models.Post{
|
|
|
|
Email: body.Email,
|
|
|
|
Password: string(hash),
|
|
|
|
Nik: body.Nik,
|
|
|
|
Name: body.Name,
|
|
|
|
Photo: body.Photo,
|
|
|
|
Birthdate: body.Birthdate,
|
|
|
|
JobTitle: body.JobTitle,
|
|
|
|
LastLoginAt: time.Now(),
|
|
|
|
CreatedBy: body.Nik,
|
|
|
|
UpdatedBy: body.Nik,
|
|
|
|
DeletedBy: body.Nik,
|
|
|
|
Token: "",
|
|
|
|
}
|
|
|
|
result := initializers.DB.Create(&user)
|
|
|
|
if result.Error != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
|
|
"error": "Failed to create user",
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
updateLoginRecord(c, user.ID, time.Now())
|
|
|
|
c.JSON(http.StatusOK, gin.H{})
|
|
|
|
}
|
|
|
|
|
|
|
|
var totalRecord int64 // variabel global untuk menyimpan total record
|
|
|
|
|
|
|
|
func LogIn(c *gin.Context) {
|
|
|
|
var body struct {
|
|
|
|
Email string
|
|
|
|
Password string
|
|
|
|
}
|
|
|
|
if err := c.ShouldBindJSON(&body); err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
|
|
"code": http.StatusBadRequest,
|
|
|
|
"data": nil,
|
|
|
|
"message": "Failed to read body",
|
|
|
|
"status": false,
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var user models.Post
|
|
|
|
result := initializers.DB.First(&user, "email = ?", body.Email)
|
|
|
|
if result.Error != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
|
|
"code": http.StatusBadRequest,
|
|
|
|
"data": nil,
|
|
|
|
"message": "Invalid email or password",
|
|
|
|
"status": false,
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(body.Password))
|
|
|
|
if err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
|
|
"code": http.StatusBadRequest,
|
|
|
|
"data": nil,
|
|
|
|
"message": "Invalid email or password",
|
|
|
|
"status": false,
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
user.LastLoginAt = time.Now()
|
|
|
|
result = initializers.DB.Save(&user)
|
|
|
|
if result.Error != nil {
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
|
|
"code": http.StatusInternalServerError,
|
|
|
|
"data": nil,
|
|
|
|
"message": "Failed to update user data",
|
|
|
|
"status": false,
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
updateLoginRecord(c, user.ID, time.Now())
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
|
|
|
"sub": user.ID,
|
|
|
|
"exp": time.Now().Add(time.Hour * 24 * 30).Unix(),
|
|
|
|
})
|
|
|
|
tokenString, err := token.SignedString([]byte(os.Getenv("SECRET")))
|
|
|
|
if err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
|
|
"code": http.StatusBadRequest,
|
|
|
|
"data": nil,
|
|
|
|
"message": "Failed to create token",
|
|
|
|
"status": false,
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
c.SetSameSite(http.SameSiteLaxMode)
|
|
|
|
c.SetCookie("Authorization", tokenString, 3600*24*30, "", "", false, true)
|
|
|
|
|
|
|
|
// Menghitung total record setelah operasi save
|
|
|
|
totalRecord++
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
|
|
"code": http.StatusOK,
|
|
|
|
"data": user,
|
|
|
|
"message": "OK",
|
|
|
|
"status": true,
|
|
|
|
"totalRecord": totalRecord,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func LogOut(c *gin.Context) {
|
|
|
|
c.SetCookie("Authorization", "", -1, "/", "", false, true)
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
|
|
"message": "Logout successful",
|
|
|
|
})
|
|
|
|
}
|
|
|
|
func Validate(c *gin.Context) {
|
|
|
|
user, _ := c.Get("user")
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
|
|
"message": user,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
func updateLoginRecord(c *gin.Context, userID uint, date time.Time) {
|
|
|
|
// Cari data rekap login berdasarkan tanggal
|
|
|
|
var loginRecord models.LoginRecord
|
|
|
|
result := initializers.DB.Where("login_date = ?", date.Format("2006-01-02")).First(&loginRecord)
|
|
|
|
if result.Error != nil && result.Error != gorm.ErrRecordNotFound {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if result.Error == gorm.ErrRecordNotFound {
|
|
|
|
// Jika belum ada data rekap untuk hari ini, buat data baru
|
|
|
|
loginRecord = models.LoginRecord{
|
|
|
|
LoginDate: date,
|
|
|
|
UserIDs: fmt.Sprintf("%d", userID),
|
|
|
|
}
|
|
|
|
initializers.DB.Create(&loginRecord)
|
|
|
|
} else {
|
|
|
|
// Jika sudah ada data rekap, cek apakah user sudah login pada hari ini
|
|
|
|
if !containsInt(loginRecord.UserIDs, userID) {
|
|
|
|
// Jika user belum login hari ini, tambahkan ID pengguna ke dalam array user_ids
|
|
|
|
|
|
|
|
loginRecord.UserIDs = fmt.Sprintf("%s,%d", loginRecord.UserIDs, userID)
|
|
|
|
initializers.DB.Save(&loginRecord)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Ambil data pengguna yang login pada hari ini
|
|
|
|
var users []models.Post
|
|
|
|
initializers.DB.Find(&users, "id IN (?)", parseUserIDs(loginRecord.UserIDs))
|
|
|
|
// Update login record dengan pengguna yang login pada hari ini
|
|
|
|
loginRecord.Users = users
|
|
|
|
// Update jumlah pengguna (TotalUsers) saat pengguna baru melakukan login
|
|
|
|
|
|
|
|
initializers.DB.Save(&loginRecord)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper function to check if an int is present in a slice
|
|
|
|
func containsInt(slice string, val uint) bool {
|
|
|
|
ids := parseUserIDs(slice)
|
|
|
|
for _, item := range ids {
|
|
|
|
if item == val {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper function to parse user IDs from a string
|
|
|
|
func parseUserIDs(idsStr string) []uint {
|
|
|
|
ids := strings.Split(idsStr, ",")
|
|
|
|
var userIDs []uint
|
|
|
|
for _, idStr := range ids {
|
|
|
|
id, err := strconv.ParseUint(idStr, 10, 32)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
userIDs = append(userIDs, uint(id))
|
|
|
|
}
|
|
|
|
return userIDs
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetLoginRecords(c *gin.Context) {
|
|
|
|
var loginRecords []models.LoginRecord
|
|
|
|
result := initializers.DB.Find(&loginRecords)
|
|
|
|
if result.Error != nil {
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
|
|
"error": "Failed to fetch login records",
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Retrieve user details for each login record
|
|
|
|
for i := range loginRecords {
|
|
|
|
var users []models.Post
|
|
|
|
initializers.DB.Find(&users, "id IN (?)", parseUserIDs(loginRecords[i].UserIDs))
|
|
|
|
loginRecords[i].Users = users
|
|
|
|
}
|
|
|
|
// Create JSON response
|
|
|
|
var response struct {
|
|
|
|
Records []models.LoginRecord `json:"records"`
|
|
|
|
}
|
|
|
|
response.Records = loginRecords
|
|
|
|
c.JSON(http.StatusOK, response)
|
|
|
|
}
|