fix: auth and permission chmod and regist flow
This commit is contained in:
parent
e06b6033b5
commit
c26eee0ab9
|
@ -1,66 +0,0 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RequestAboutDTO struct {
|
||||
Title string `json:"title"`
|
||||
CoverImage string `json:"cover_image"`
|
||||
}
|
||||
|
||||
func (r *RequestAboutDTO) ValidateAbout() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.Title) == "" {
|
||||
errors["title"] = append(errors["title"], "Title is required")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
||||
|
||||
type ResponseAboutDTO struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
CoverImage string `json:"cover_image"`
|
||||
AboutDetail *[]ResponseAboutDetailDTO `json:"about_detail"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
type RequestAboutDetailDTO struct {
|
||||
AboutId string `json:"about_id"`
|
||||
ImageDetail string `json:"image_detail"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func (r *RequestAboutDetailDTO) ValidateAboutDetail() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.AboutId) == "" {
|
||||
errors["about_id"] = append(errors["about_id"], "about_id is required")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Description) == "" {
|
||||
errors["description"] = append(errors["description"], "Description is required")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
||||
|
||||
type ResponseAboutDetailDTO struct {
|
||||
ID string `json:"id"`
|
||||
AboutID string `json:"about_id"`
|
||||
ImageDetail string `json:"image_detail"`
|
||||
Description string `json:"description"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
package dto
|
||||
|
||||
import "strings"
|
||||
|
||||
type AddressResponseDTO struct {
|
||||
UserID string `json:"user_id,omitempty"`
|
||||
ID string `json:"address_id,omitempty"`
|
||||
Province string `json:"province,omitempty"`
|
||||
Regency string `json:"regency,omitempty"`
|
||||
District string `json:"district,omitempty"`
|
||||
Village string `json:"village,omitempty"`
|
||||
PostalCode string `json:"postalCode,omitempty"`
|
||||
Detail string `json:"detail,omitempty"`
|
||||
Latitude float64 `json:"latitude,omitempty"`
|
||||
Longitude float64 `json:"longitude,omitempty"`
|
||||
CreatedAt string `json:"createdAt,omitempty"`
|
||||
UpdatedAt string `json:"updatedAt,omitempty"`
|
||||
}
|
||||
|
||||
type CreateAddressDTO struct {
|
||||
Province string `json:"province_id"`
|
||||
Regency string `json:"regency_id"`
|
||||
District string `json:"district_id"`
|
||||
Village string `json:"village_id"`
|
||||
PostalCode string `json:"postalCode"`
|
||||
Detail string `json:"detail"`
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
}
|
||||
|
||||
func (r *CreateAddressDTO) ValidateAddress() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.Province) == "" {
|
||||
errors["province_id"] = append(errors["province_id"], "Province ID is required")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Regency) == "" {
|
||||
errors["regency_id"] = append(errors["regency_id"], "Regency ID is required")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.District) == "" {
|
||||
errors["district_id"] = append(errors["district_id"], "District ID is required")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Village) == "" {
|
||||
errors["village_id"] = append(errors["village_id"], "Village ID is required")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.PostalCode) == "" {
|
||||
errors["postalCode"] = append(errors["postalCode"], "PostalCode is required")
|
||||
} else if len(r.PostalCode) < 5 {
|
||||
errors["postalCode"] = append(errors["postalCode"], "PostalCode must be at least 5 characters")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Detail) == "" {
|
||||
errors["detail"] = append(errors["detail"], "Detail address is required")
|
||||
}
|
||||
|
||||
if r.Latitude == 0 {
|
||||
errors["latitude"] = append(errors["latitude"], "Latitude is required")
|
||||
}
|
||||
|
||||
if r.Longitude == 0 {
|
||||
errors["longitude"] = append(errors["longitude"], "Longitude is required")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ArticleResponseDTO struct {
|
||||
ID string `json:"article_id"`
|
||||
Title string `json:"title"`
|
||||
CoverImage string `json:"coverImage"`
|
||||
Author string `json:"author"`
|
||||
Heading string `json:"heading"`
|
||||
Content string `json:"content"`
|
||||
PublishedAt string `json:"publishedAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type RequestArticleDTO struct {
|
||||
Title string `json:"title"`
|
||||
CoverImage string `json:"coverImage"`
|
||||
Author string `json:"author"`
|
||||
Heading string `json:"heading"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
func (r *RequestArticleDTO) Validate() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.Title) == "" {
|
||||
errors["title"] = append(errors["title"], "Title is required")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Author) == "" {
|
||||
errors["author"] = append(errors["author"], "Author is required")
|
||||
}
|
||||
if strings.TrimSpace(r.Heading) == "" {
|
||||
errors["heading"] = append(errors["heading"], "Heading is required")
|
||||
}
|
||||
if strings.TrimSpace(r.Content) == "" {
|
||||
errors["content"] = append(errors["content"], "Content is required")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type LoginAdminRequest struct {
|
||||
Deviceid string `json:"device_id"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type LoginResponse struct {
|
||||
UserID string `json:"user_id"`
|
||||
Role string `json:"role"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
type RegisterAdminRequest struct {
|
||||
Name string `json:"name"`
|
||||
Gender string `json:"gender"`
|
||||
Dateofbirth string `json:"dateofbirth"`
|
||||
Placeofbirth string `json:"placeofbirth"`
|
||||
Phone string `json:"phone"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
PasswordConfirm string `json:"password_confirm"`
|
||||
}
|
||||
|
||||
type UserAdminDataResponse struct {
|
||||
UserID string `json:"user_id"`
|
||||
Name string `json:"name"`
|
||||
Gender string `json:"gender"`
|
||||
Dateofbirth string `json:"dateofbirth"`
|
||||
Placeofbirth string `json:"placeofbirth"`
|
||||
Phone string `json:"phone"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
Role string `json:"role"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (r *RegisterAdminRequest) Validate() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.Name) == "" {
|
||||
errors["name"] = append(errors["name"], "Name is required")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Gender) == "" {
|
||||
errors["gender"] = append(errors["gender"], "Gender is required")
|
||||
} else if r.Gender != "male" && r.Gender != "female" {
|
||||
errors["gender"] = append(errors["gender"], "Gender must be either 'male' or 'female'")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Dateofbirth) == "" {
|
||||
errors["dateofbirth"] = append(errors["dateofbirth"], "Date of birth is required")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Placeofbirth) == "" {
|
||||
errors["placeofbirth"] = append(errors["placeofbirth"], "Place of birth is required")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Phone) == "" {
|
||||
errors["phone"] = append(errors["phone"], "Phone is required")
|
||||
} else if !IsValidPhoneNumber(r.Phone) {
|
||||
errors["phone"] = append(errors["phone"], "Invalid phone number format. Use 62 followed by 9-13 digits")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Email) == "" {
|
||||
errors["email"] = append(errors["email"], "Email is required")
|
||||
} else if !IsValidEmail(r.Email) {
|
||||
errors["email"] = append(errors["email"], "Invalid email format")
|
||||
}
|
||||
|
||||
if len(r.Password) < 6 {
|
||||
errors["password"] = append(errors["password"], "Password must be at least 6 characters")
|
||||
} else if !IsValidPassword(r.Password) {
|
||||
errors["password"] = append(errors["password"], "Password must contain at least one uppercase letter, one number, and one special character")
|
||||
}
|
||||
|
||||
if r.Password != r.PasswordConfirm {
|
||||
errors["password_confirm"] = append(errors["password_confirm"], "Password and confirmation do not match")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
return nil, true
|
||||
}
|
||||
|
||||
func IsValidPhoneNumber(phone string) bool {
|
||||
re := regexp.MustCompile(`^62\d{9,13}$`)
|
||||
return re.MatchString(phone)
|
||||
}
|
||||
|
||||
func IsValidEmail(email string) bool {
|
||||
re := regexp.MustCompile(`^[a-z0-9]+@[a-z0-9]+\.[a-z]{2,}$`)
|
||||
return re.MatchString(email)
|
||||
}
|
||||
|
||||
func IsValidPassword(password string) bool {
|
||||
|
||||
if len(password) < 6 {
|
||||
return false
|
||||
}
|
||||
|
||||
hasUpper := false
|
||||
hasDigit := false
|
||||
hasSpecial := false
|
||||
|
||||
for _, char := range password {
|
||||
if char >= 'A' && char <= 'Z' {
|
||||
hasUpper = true
|
||||
} else if char >= '0' && char <= '9' {
|
||||
hasDigit = true
|
||||
} else if isSpecialCharacter(char) {
|
||||
hasSpecial = true
|
||||
}
|
||||
}
|
||||
|
||||
return hasUpper && hasDigit && hasSpecial
|
||||
}
|
||||
|
||||
func isSpecialCharacter(char rune) bool {
|
||||
specialChars := "!@#$%^&*()-_=+[]{}|;:'\",.<>?/`~"
|
||||
return strings.ContainsRune(specialChars, char)
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
package dto
|
|
@ -1,133 +0,0 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"rijig/utils"
|
||||
)
|
||||
|
||||
type LoginPengelolaRequest struct {
|
||||
Phone string `json:"phone"`
|
||||
}
|
||||
|
||||
func (r *LoginPengelolaRequest) ValidateLogin() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if r.Phone == "" {
|
||||
errors["phone"] = append(errors["phone"], "Phone number is required")
|
||||
} else if !utils.IsValidPhoneNumber(r.Phone) {
|
||||
errors["phone"] = append(errors["phone"], "Phone number is not valid")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
return nil, true
|
||||
}
|
||||
|
||||
type VerifLoginPengelolaRequest struct {
|
||||
Phone string `json:"phone"`
|
||||
Otp string `json:"verif_otp"`
|
||||
}
|
||||
|
||||
func (r *VerifLoginPengelolaRequest) ValidateVerifLogin() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if r.Phone == "" {
|
||||
errors["phone"] = append(errors["phone"], "Phone number is required")
|
||||
} else if !utils.IsValidPhoneNumber(r.Phone) {
|
||||
errors["phone"] = append(errors["phone"], "Phone number is not valid")
|
||||
}
|
||||
|
||||
if r.Otp == "" {
|
||||
errors["otp"] = append(errors["otp"], "OTP is required")
|
||||
} else if len(r.Otp) != 6 {
|
||||
errors["otp"] = append(errors["otp"], "OTP must be 6 digits")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
return nil, true
|
||||
}
|
||||
|
||||
type LoginPengelolaResponse struct {
|
||||
UserID string `json:"user_id"`
|
||||
Role string `json:"role"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
type PengelolaIdentityCard struct {
|
||||
Cardphoto string `json:"cardphoto"`
|
||||
Identificationumber string `json:"identificationumber"`
|
||||
Placeofbirth string `json:"placeofbirth"`
|
||||
Dateofbirth string `json:"dateofbirth"`
|
||||
Gender string `json:"gender"`
|
||||
BloodType string `json:"bloodtype"`
|
||||
District string `json:"district"`
|
||||
Village string `json:"village"`
|
||||
Neighbourhood string `json:"neighbourhood"`
|
||||
Religion string `json:"religion"`
|
||||
Maritalstatus string `json:"maritalstatus"`
|
||||
Job string `json:"job"`
|
||||
Citizenship string `json:"citizenship"`
|
||||
Validuntil string `json:"validuntil"`
|
||||
}
|
||||
|
||||
func (r *PengelolaIdentityCard) ValidateIDcard() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if r.Cardphoto == "" {
|
||||
errors["cardphoto"] = append(errors["cardphoto"], "Card photo is required")
|
||||
}
|
||||
|
||||
if r.Identificationumber == "" {
|
||||
errors["identificationumber"] = append(errors["identificationumber"], "Identification number is required")
|
||||
}
|
||||
|
||||
if r.Dateofbirth == "" {
|
||||
errors["dateofbirth"] = append(errors["dateofbirth"], "Date of birth is required")
|
||||
} else if !isValidDate(r.Dateofbirth) {
|
||||
errors["dateofbirth"] = append(errors["dateofbirth"], "Date of birth must be in DD-MM-YYYY format")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
return nil, true
|
||||
}
|
||||
|
||||
type PengelolaCompanyProfile struct {
|
||||
CompanyName string `json:"company_name"`
|
||||
CompanyPhone string `json:"company_phone"`
|
||||
CompanyEmail string `json:"company_email"`
|
||||
}
|
||||
|
||||
func (r *PengelolaCompanyProfile) ValidateCompany() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if r.CompanyName == "" {
|
||||
errors["company_name"] = append(errors["company_name"], "Company name is required")
|
||||
}
|
||||
|
||||
if r.CompanyPhone == "" {
|
||||
errors["company_phone"] = append(errors["company_phone"], "Company phone is required")
|
||||
} else if !utils.IsValidPhoneNumber(r.CompanyPhone) {
|
||||
errors["company_phone"] = append(errors["company_phone"], "Invalid phone number format")
|
||||
}
|
||||
|
||||
if r.CompanyEmail == "" {
|
||||
errors["company_email"] = append(errors["company_email"], "Company email is required")
|
||||
} else if !utils.IsValidEmail(r.CompanyEmail) {
|
||||
errors["company_email"] = append(errors["company_email"], "Invalid email format")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
return nil, true
|
||||
}
|
||||
|
||||
func isValidDate(date string) bool {
|
||||
re := regexp.MustCompile(`^\d{2}-\d{2}-\d{4}$`)
|
||||
return re.MatchString(date)
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
package dto
|
|
@ -1,42 +0,0 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RegisterRequest struct {
|
||||
Phone string `json:"phone"`
|
||||
}
|
||||
|
||||
type VerifyOTPRequest struct {
|
||||
Phone string `json:"phone"`
|
||||
OTP string `json:"otp"`
|
||||
DeviceID string `json:"device_id"`
|
||||
}
|
||||
|
||||
type UserDataResponse struct {
|
||||
UserID string `json:"user_id"`
|
||||
UserRole string `json:"user_role"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func (r *RegisterRequest) Validate() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.Phone) == "" {
|
||||
errors["phone"] = append(errors["phone"], "Phone is required")
|
||||
} else if !IsValidPhoneNumber(r.Phone) {
|
||||
errors["phone"] = append(errors["phone"], "Invalid phone number format. Use 62 followed by 9-13 digits")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
return nil, true
|
||||
}
|
||||
|
||||
func IsValidPhoneNumber(phone string) bool {
|
||||
re := regexp.MustCompile(`^62\d{9,13}$`)
|
||||
return re.MatchString(phone)
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package dto
|
||||
|
||||
import "strings"
|
||||
|
||||
type ResponseBannerDTO struct {
|
||||
ID string `json:"id"`
|
||||
BannerName string `json:"bannername"`
|
||||
BannerImage string `json:"bannerimage"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type RequestBannerDTO struct {
|
||||
BannerName string `json:"bannername"`
|
||||
BannerImage string `json:"bannerimage"`
|
||||
}
|
||||
|
||||
func (r *RequestBannerDTO) ValidateBannerInput() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.BannerName) == "" {
|
||||
errors["bannername"] = append(errors["bannername"], "nama banner harus diisi")
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type NearbyCollectorDTO struct {
|
||||
CollectorID string `json:"collector_id"`
|
||||
Name string `json:"name"`
|
||||
Phone string `json:"phone"`
|
||||
Rating float32 `json:"rating"`
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
DistanceKm float64 `json:"distance_km"`
|
||||
MatchedTrash []string `json:"matched_trash_ids"`
|
||||
}
|
||||
|
||||
type RequestCollectorDTO struct {
|
||||
AddressId string `json:"address_id"`
|
||||
AvaibleTrashbyCollector []RequestAvaibleTrashbyCollector `json:"avaible_trash"`
|
||||
}
|
||||
|
||||
type RequestAvaibleTrashbyCollector struct {
|
||||
TrashId string `json:"trash_id"`
|
||||
TrashPrice float32 `json:"trash_price"`
|
||||
}
|
||||
|
||||
type RequestAddAvaibleTrash struct {
|
||||
AvaibleTrash []RequestAvaibleTrashbyCollector `json:"avaible_trash"`
|
||||
}
|
||||
|
||||
type SelectCollectorRequest struct {
|
||||
Collector_id string `json:"collector_id"`
|
||||
}
|
||||
|
||||
func (r *SelectCollectorRequest) ValidateSelectCollectorRequest() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.Collector_id) == "" {
|
||||
errors["collector_id"] = append(errors["collector_id"], "collector_id harus diisi")
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
||||
|
||||
func (r *RequestAddAvaibleTrash) ValidateRequestAddAvaibleTrash() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if len(r.AvaibleTrash) == 0 {
|
||||
errors["avaible_trash"] = append(errors["avaible_trash"], "tidak boleh kosong")
|
||||
}
|
||||
|
||||
for i, trash := range r.AvaibleTrash {
|
||||
if strings.TrimSpace(trash.TrashId) == "" {
|
||||
errors[fmt.Sprintf("avaible_trash[%d].trash_id", i)] = append(errors[fmt.Sprintf("avaible_trash[%d].trash_id", i)], "trash_id tidak boleh kosong")
|
||||
}
|
||||
if trash.TrashPrice <= 0 {
|
||||
errors[fmt.Sprintf("avaible_trash[%d].trash_price", i)] = append(errors[fmt.Sprintf("avaible_trash[%d].trash_price", i)], "trash_price harus lebih dari 0")
|
||||
}
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
return nil, true
|
||||
}
|
||||
|
||||
type ResponseCollectorDTO struct {
|
||||
ID string `json:"collector_id"`
|
||||
UserId string `json:"user_id"`
|
||||
User *UserResponseDTO `json:"user,omitempty"`
|
||||
AddressId string `json:"address_id"`
|
||||
Address *AddressResponseDTO `json:"address,omitempty"`
|
||||
JobStatus *string `json:"job_status,omitempty"`
|
||||
Rating float32 `json:"rating"`
|
||||
AvaibleTrashbyCollector []ResponseAvaibleTrashByCollector `json:"avaible_trash"`
|
||||
}
|
||||
|
||||
type ResponseAvaibleTrashByCollector struct {
|
||||
ID string `json:"id"`
|
||||
TrashId string `json:"trash_id"`
|
||||
TrashName string `json:"trash_name"`
|
||||
TrashIcon string `json:"trash_icon"`
|
||||
TrashPrice float32 `json:"trash_price"`
|
||||
}
|
||||
|
||||
func (r *RequestCollectorDTO) ValidateRequestCollector() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.AddressId) == "" {
|
||||
errors["address_id"] = append(errors["address_id"], "address_id harus diisi")
|
||||
}
|
||||
|
||||
for i, trash := range r.AvaibleTrashbyCollector {
|
||||
if strings.TrimSpace(trash.TrashId) == "" {
|
||||
errors[fmt.Sprintf("avaible_trash[%d].trash_id", i)] = append(errors[fmt.Sprintf("avaible_trash[%d].trash_id", i)], "trash_id tidak boleh kosong")
|
||||
}
|
||||
if trash.TrashPrice <= 0 {
|
||||
errors[fmt.Sprintf("avaible_trash[%d].trash_price", i)] = append(errors[fmt.Sprintf("avaible_trash[%d].trash_price", i)], "trash_price harus lebih dari 0")
|
||||
}
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
return nil, true
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"rijig/utils"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ResponseCompanyProfileDTO struct {
|
||||
ID string `json:"id"`
|
||||
UserID string `json:"userId"`
|
||||
CompanyName string `json:"company_name"`
|
||||
CompanyAddress string `json:"company_address"`
|
||||
CompanyPhone string `json:"company_phone"`
|
||||
CompanyEmail string `json:"company_email"`
|
||||
CompanyLogo string `json:"company_logo,omitempty"`
|
||||
CompanyWebsite string `json:"company_website,omitempty"`
|
||||
TaxID string `json:"taxId,omitempty"`
|
||||
FoundedDate string `json:"founded_date,omitempty"`
|
||||
CompanyType string `json:"company_type,omitempty"`
|
||||
CompanyDescription string `json:"company_description"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type RequestCompanyProfileDTO struct {
|
||||
CompanyName string `json:"company_name"`
|
||||
CompanyAddress string `json:"company_address"`
|
||||
CompanyPhone string `json:"company_phone"`
|
||||
CompanyEmail string `json:"company_email"`
|
||||
CompanyLogo string `json:"company_logo,omitempty"`
|
||||
CompanyWebsite string `json:"company_website,omitempty"`
|
||||
TaxID string `json:"taxId,omitempty"`
|
||||
FoundedDate string `json:"founded_date,omitempty"`
|
||||
CompanyType string `json:"company_type,omitempty"`
|
||||
CompanyDescription string `json:"company_description"`
|
||||
}
|
||||
|
||||
func (r *RequestCompanyProfileDTO) ValidateCompanyProfileInput() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.CompanyName) == "" {
|
||||
errors["company_Name"] = append(errors["company_name"], "Company name is required")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.CompanyAddress) == "" {
|
||||
errors["company_Address"] = append(errors["company_address"], "Company address is required")
|
||||
}
|
||||
|
||||
if !utils.IsValidPhoneNumber(r.CompanyPhone) {
|
||||
errors["company_Phone"] = append(errors["company_phone"], "nomor harus dimulai 62.. dan 8-14 digit")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.CompanyDescription) == "" {
|
||||
errors["company_Description"] = append(errors["company_description"], "Company description is required")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package dto
|
||||
|
||||
import "strings"
|
||||
|
||||
type RequestCoverageArea struct {
|
||||
Province string `json:"province"`
|
||||
Regency string `json:"regency"`
|
||||
}
|
||||
|
||||
type ResponseCoverageArea struct {
|
||||
ID string `json:"id"`
|
||||
Province string `json:"province"`
|
||||
Regency string `json:"regency"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (r *RequestCoverageArea) ValidateCoverageArea() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.Province) == "" {
|
||||
errors["province"] = append(errors["province"], "nama provinsi harus diisi")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Regency) == "" {
|
||||
errors["regency"] = append(errors["regency"], "nama regency harus diisi")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ResponseIdentityCardDTO struct {
|
||||
ID string `json:"id"`
|
||||
UserID string `json:"userId"`
|
||||
Identificationumber string `json:"identificationumber"`
|
||||
Placeofbirth string `json:"placeofbirth"`
|
||||
Dateofbirth string `json:"dateofbirth"`
|
||||
Gender string `json:"gender"`
|
||||
BloodType string `json:"bloodtype"`
|
||||
District string `json:"district"`
|
||||
Village string `json:"village"`
|
||||
Neighbourhood string `json:"neighbourhood"`
|
||||
Religion string `json:"religion"`
|
||||
Maritalstatus string `json:"maritalstatus"`
|
||||
Job string `json:"job"`
|
||||
Citizenship string `json:"citizenship"`
|
||||
Validuntil string `json:"validuntil"`
|
||||
Cardphoto string `json:"cardphoto"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type RequestIdentityCardDTO struct {
|
||||
UserID string `json:"userId"`
|
||||
Identificationumber string `json:"identificationumber"`
|
||||
Placeofbirth string `json:"placeofbirth"`
|
||||
Dateofbirth string `json:"dateofbirth"`
|
||||
Gender string `json:"gender"`
|
||||
BloodType string `json:"bloodtype"`
|
||||
District string `json:"district"`
|
||||
Village string `json:"village"`
|
||||
Neighbourhood string `json:"neighbourhood"`
|
||||
Religion string `json:"religion"`
|
||||
Maritalstatus string `json:"maritalstatus"`
|
||||
Job string `json:"job"`
|
||||
Citizenship string `json:"citizenship"`
|
||||
Validuntil string `json:"validuntil"`
|
||||
Cardphoto string `json:"cardphoto"`
|
||||
}
|
||||
|
||||
func (r *RequestIdentityCardDTO) ValidateIdentityCardInput() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
isValid := true
|
||||
|
||||
if strings.TrimSpace(r.Identificationumber) == "" {
|
||||
errors["identificationumber"] = append(errors["identificationumber"], "Nomor identifikasi harus diisi")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Placeofbirth) == "" {
|
||||
errors["placeofbirth"] = append(errors["placeofbirth"], "Tempat lahir harus diisi")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Dateofbirth) == "" {
|
||||
errors["dateofbirth"] = append(errors["dateofbirth"], "Tanggal lahir harus diisi")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Gender) == "" {
|
||||
errors["gender"] = append(errors["gender"], "Jenis kelamin harus diisi")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.BloodType) == "" {
|
||||
errors["bloodtype"] = append(errors["bloodtype"], "Golongan darah harus diisi")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.District) == "" {
|
||||
errors["district"] = append(errors["district"], "Kecamatan harus diisi")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Village) == "" {
|
||||
errors["village"] = append(errors["village"], "Desa harus diisi")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Neighbourhood) == "" {
|
||||
errors["neighbourhood"] = append(errors["neighbourhood"], "RT/RW harus diisi")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Religion) == "" {
|
||||
errors["religion"] = append(errors["religion"], "Agama harus diisi")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Maritalstatus) == "" {
|
||||
errors["maritalstatus"] = append(errors["maritalstatus"], "Status pernikahan harus diisi")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Job) == "" {
|
||||
errors["job"] = append(errors["job"], "Pekerjaan harus diisi")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Citizenship) == "" {
|
||||
errors["citizenship"] = append(errors["citizenship"], "Kewarganegaraan harus diisi")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Validuntil) == "" {
|
||||
errors["validuntil"] = append(errors["validuntil"], "Masa berlaku harus diisi")
|
||||
isValid = false
|
||||
}
|
||||
|
||||
return errors, isValid
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package dto
|
||||
|
||||
import "strings"
|
||||
|
||||
type ReponseInitialCointDTO struct {
|
||||
ID string `json:"coin_id"`
|
||||
CoinName string `json:"coin_name"`
|
||||
ValuePerUnit float64 `json:"value_perunit"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type RequestInitialCointDTO struct {
|
||||
CoinName string `json:"coin_name"`
|
||||
ValuePerUnit float64 `json:"value_perunit"`
|
||||
}
|
||||
|
||||
func (r *RequestInitialCointDTO) ValidateCointInput() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.CoinName) == "" {
|
||||
errors["coin_name"] = append(errors["coin_name"], "nama coin harus diisi")
|
||||
}
|
||||
|
||||
if r.ValuePerUnit <= 0 {
|
||||
errors["value_perunit"] = append(errors["value_perunit"], "value per unit harus lebih besar dari 0")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"mime/multipart"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ResponseProductImageDTO struct {
|
||||
ID string `json:"id"`
|
||||
ProductID string `json:"productId"`
|
||||
ImageURL string `json:"imageURL"`
|
||||
}
|
||||
|
||||
type ResponseProductDTO struct {
|
||||
ID string `json:"id"`
|
||||
StoreID string `json:"storeId"`
|
||||
ProductName string `json:"productName"`
|
||||
Quantity int `json:"quantity"`
|
||||
Saled int `json:"saled"`
|
||||
ProductImages []ResponseProductImageDTO `json:"productImages,omitempty"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type RequestProductDTO struct {
|
||||
ProductName string `json:"product_name"`
|
||||
Quantity int `json:"quantity"`
|
||||
ProductImages []*multipart.FileHeader `json:"product_images,omitempty"`
|
||||
}
|
||||
|
||||
func (r *RequestProductDTO) ValidateProductInput() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.ProductName) == "" {
|
||||
errors["product_name"] = append(errors["product_name"], "Product name is required")
|
||||
} else if len(r.ProductName) < 3 {
|
||||
errors["product_name"] = append(errors["product_name"], "Product name must be at least 3 characters long")
|
||||
} else {
|
||||
validNameRegex := `^[a-zA-Z0-9\s_.-]+$`
|
||||
if matched, _ := regexp.MatchString(validNameRegex, r.ProductName); !matched {
|
||||
errors["product_name"] = append(errors["product_name"], "Product name can only contain letters, numbers, spaces, underscores, and dashes")
|
||||
}
|
||||
}
|
||||
|
||||
if r.Quantity < 1 {
|
||||
errors["quantity"] = append(errors["quantity"], "Quantity must be at least 1")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package dto
|
||||
|
||||
import "strings"
|
||||
|
||||
type CreatePickupRatingDTO struct {
|
||||
Rating float32 `json:"rating"`
|
||||
Feedback string `json:"feedback"`
|
||||
}
|
||||
|
||||
func (r *CreatePickupRatingDTO) ValidateCreatePickupRatingDTO() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if r.Rating < 1.0 || r.Rating > 5.0 {
|
||||
errors["rating"] = append(errors["rating"], "Rating harus antara 1.0 sampai 5.0")
|
||||
}
|
||||
|
||||
if len(strings.TrimSpace(r.Feedback)) > 255 {
|
||||
errors["feedback"] = append(errors["feedback"], "Feedback tidak boleh lebih dari 255 karakter")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
return nil, true
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type SelectCollectorDTO struct {
|
||||
CollectorID string `json:"collector_id"`
|
||||
}
|
||||
|
||||
type UpdateRequestPickupItemDTO struct {
|
||||
ItemID string `json:"item_id"`
|
||||
Amount float64 `json:"actual_amount"`
|
||||
}
|
||||
|
||||
type UpdatePickupItemsRequest struct {
|
||||
Items []UpdateRequestPickupItemDTO `json:"items"`
|
||||
}
|
||||
|
||||
func (r *SelectCollectorDTO) Validate() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.CollectorID) == "" {
|
||||
errors["collector_id"] = append(errors["collector_id"], "collector_id tidak boleh kosong")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
return nil, true
|
||||
}
|
||||
|
||||
type AssignedPickupDTO struct {
|
||||
PickupID string `json:"pickup_id"`
|
||||
UserID string `json:"user_id"`
|
||||
UserName string `json:"user_name"`
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
Notes string `json:"notes"`
|
||||
MatchedTrash []string `json:"matched_trash"`
|
||||
}
|
||||
|
||||
type PickupRequestForCollectorDTO struct {
|
||||
PickupID string `json:"pickup_id"`
|
||||
UserID string `json:"user_id"`
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
DistanceKm float64 `json:"distance_km"`
|
||||
MatchedTrash []string `json:"matched_trash"`
|
||||
}
|
||||
|
||||
type RequestPickupDTO struct {
|
||||
AddressID string `json:"address_id"`
|
||||
RequestMethod string `json:"request_method"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
}
|
||||
|
||||
func (r *RequestPickupDTO) Validate() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.AddressID) == "" {
|
||||
errors["address_id"] = append(errors["address_id"], "alamat harus dipilih")
|
||||
}
|
||||
|
||||
method := strings.ToLower(strings.TrimSpace(r.RequestMethod))
|
||||
if method != "manual" && method != "otomatis" {
|
||||
errors["request_method"] = append(errors["request_method"], "harus manual atau otomatis")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
return nil, true
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RequestPickup struct {
|
||||
AddressID string `json:"address_id"`
|
||||
RequestMethod string `json:"request_method"`
|
||||
EvidenceImage string `json:"evidence_image"`
|
||||
Notes string `json:"notes"`
|
||||
RequestItems []RequestPickupItem `json:"request_items"`
|
||||
}
|
||||
|
||||
type RequestPickupItem struct {
|
||||
TrashCategoryID string `json:"trash_category_id"`
|
||||
EstimatedAmount float64 `json:"estimated_amount"`
|
||||
}
|
||||
|
||||
type ResponseRequestPickup struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
UserId string `json:"user_id,omitempty"`
|
||||
User []UserResponseDTO `json:"user,omitempty"`
|
||||
AddressID string `json:"address_id,omitempty"`
|
||||
Address []AddressResponseDTO `json:"address,omitempty"`
|
||||
EvidenceImage string `json:"evidence_image,omitempty"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
StatusPickup string `json:"status_pickup,omitempty"`
|
||||
CollectorID string `json:"collectorid,omitempty"`
|
||||
Collector []ResponseCollectorDTO `json:"collector,omitempty"`
|
||||
ConfirmedByCollectorAt string `json:"confirmedat,omitempty"`
|
||||
CreatedAt string `json:"created_at,omitempty"`
|
||||
UpdatedAt string `json:"updated_at,omitempty"`
|
||||
RequestItems []ResponseRequestPickupItem `json:"request_items,omitempty"`
|
||||
}
|
||||
|
||||
type ResponseRequestPickupItem struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
TrashCategoryID string `json:"trash_category_id,omitempty"`
|
||||
// TrashCategory []ResponseTrashCategoryDTO `json:"trash_category,omitempty"`
|
||||
EstimatedAmount float64 `json:"estimated_amount,omitempty"`
|
||||
}
|
||||
|
||||
func (r *RequestPickup) ValidateRequestPickup() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if len(r.RequestItems) == 0 {
|
||||
errors["request_items"] = append(errors["request_items"], "At least one item must be provided")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.AddressID) == "" {
|
||||
errors["address_id"] = append(errors["address_id"], "Address ID must be provided")
|
||||
}
|
||||
|
||||
for i, item := range r.RequestItems {
|
||||
itemErrors, valid := item.ValidateRequestPickupItem(i)
|
||||
if !valid {
|
||||
for field, msgs := range itemErrors {
|
||||
errors[field] = append(errors[field], msgs...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
||||
|
||||
func (r *RequestPickupItem) ValidateRequestPickupItem(index int) (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.TrashCategoryID) == "" {
|
||||
errors["trash_category_id"] = append(errors["trash_category_id"], fmt.Sprintf("Trash category ID cannot be empty (Item %d)", index+1))
|
||||
}
|
||||
|
||||
if r.EstimatedAmount < 2 {
|
||||
errors["estimated_amount"] = append(errors["estimated_amount"], fmt.Sprintf("Estimated amount must be >= 2.0 kg (Item %d)", index+1))
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package dto
|
||||
|
||||
type RoleResponseDTO struct {
|
||||
ID string `json:"role_id"`
|
||||
RoleName string `json:"role_name"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ResponseStoreDTO struct {
|
||||
ID string `json:"id"`
|
||||
UserID string `json:"userId"`
|
||||
StoreName string `json:"storeName"`
|
||||
StoreLogo string `json:"storeLogo"`
|
||||
StoreBanner string `json:"storeBanner"`
|
||||
StoreInfo string `json:"storeInfo"`
|
||||
StoreAddressID string `json:"storeAddressId"`
|
||||
TotalProduct int `json:"TotalProduct"`
|
||||
Followers int `json:"followers"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type RequestStoreDTO struct {
|
||||
StoreName string `json:"store_name"`
|
||||
StoreLogo string `json:"store_logo"`
|
||||
StoreBanner string `json:"store_banner"`
|
||||
StoreInfo string `json:"store_info"`
|
||||
StoreAddressID string `json:"store_address_id"`
|
||||
}
|
||||
|
||||
func (r *RequestStoreDTO) ValidateStoreInput() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.StoreName) == "" {
|
||||
errors["store_name"] = append(errors["store_name"], "Store name is required")
|
||||
} else if len(r.StoreName) < 3 {
|
||||
errors["store_name"] = append(errors["store_name"], "Store name must be at least 3 characters long")
|
||||
} else {
|
||||
validNameRegex := `^[a-zA-Z0-9_.\s]+$`
|
||||
if matched, _ := regexp.MatchString(validNameRegex, r.StoreName); !matched {
|
||||
errors["store_name"] = append(errors["store_name"], "Store name can only contain letters, numbers, underscores, and periods")
|
||||
}
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.StoreLogo) == "" {
|
||||
errors["store_logo"] = append(errors["store_logo"], "Store logo is required")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.StoreBanner) == "" {
|
||||
errors["store_banner"] = append(errors["store_banner"], "Store banner is required")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.StoreInfo) == "" {
|
||||
errors["store_info"] = append(errors["store_info"], "Store info is required")
|
||||
}
|
||||
|
||||
uuidRegex := `^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$`
|
||||
if r.StoreAddressID == "" {
|
||||
errors["store_address_id"] = append(errors["store_address_id"], "Store address ID is required")
|
||||
} else if matched, _ := regexp.MatchString(uuidRegex, r.StoreAddressID); !matched {
|
||||
errors["store_address_id"] = append(errors["store_address_id"], "Invalid Store Address ID format")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
package dto
|
||||
/*
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RequestTrashCategoryDTO struct {
|
||||
Name string `json:"name"`
|
||||
EstimatedPrice string `json:"estimatedprice"`
|
||||
Icon string `json:"icon"`
|
||||
}
|
||||
|
||||
type ResponseTrashCategoryDTO struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Icon string `json:"icon,omitempty"`
|
||||
EstimatedPrice float64 `json:"estimatedprice"`
|
||||
CreatedAt string `json:"createdAt,omitempty"`
|
||||
UpdatedAt string `json:"updatedAt,omitempty"`
|
||||
Details []ResponseTrashDetailDTO `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
type ResponseTrashDetailDTO struct {
|
||||
ID string `json:"id"`
|
||||
CategoryID string `json:"category_id"`
|
||||
Description string `json:"description"`
|
||||
Price float64 `json:"price"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type RequestTrashDetailDTO struct {
|
||||
CategoryID string `json:"category_id"`
|
||||
Description string `json:"description"`
|
||||
Price float64 `json:"price"`
|
||||
}
|
||||
|
||||
func (r *RequestTrashCategoryDTO) ValidateTrashCategoryInput() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.Name) == "" {
|
||||
errors["name"] = append(errors["name"], "name is required")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
||||
|
||||
func (r *RequestTrashDetailDTO) ValidateTrashDetailInput() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.Description) == "" {
|
||||
errors["description"] = append(errors["description"], "description is required")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
||||
*/
|
|
@ -1,49 +0,0 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RequestCartItemDTO struct {
|
||||
TrashID string `json:"trash_id"`
|
||||
Amount float64 `json:"amount"`
|
||||
}
|
||||
|
||||
type RequestCartDTO struct {
|
||||
CartItems []RequestCartItemDTO `json:"cart_items"`
|
||||
}
|
||||
|
||||
type ResponseCartDTO struct {
|
||||
ID string `json:"id"`
|
||||
UserID string `json:"user_id"`
|
||||
TotalAmount float64 `json:"total_amount"`
|
||||
EstimatedTotalPrice float64 `json:"estimated_total_price"`
|
||||
CartItems []ResponseCartItemDTO `json:"cart_items"`
|
||||
}
|
||||
|
||||
type ResponseCartItemDTO struct {
|
||||
ID string `json:"id"`
|
||||
TrashID string `json:"trash_id"`
|
||||
TrashName string `json:"trash_name"`
|
||||
TrashIcon string `json:"trash_icon"`
|
||||
TrashPrice float64 `json:"trash_price"`
|
||||
Amount float64 `json:"amount"`
|
||||
SubTotalEstimatedPrice float64 `json:"subtotal_estimated_price"`
|
||||
}
|
||||
|
||||
func (r *RequestCartDTO) ValidateRequestCartDTO() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
for i, item := range r.CartItems {
|
||||
if strings.TrimSpace(item.TrashID) == "" {
|
||||
errors[fmt.Sprintf("cart_items[%d].trash_id", i)] = append(errors[fmt.Sprintf("cart_items[%d].trash_id", i)], "trash_id tidak boleh kosong")
|
||||
}
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"rijig/utils"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type UserResponseDTO struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Avatar *string `json:"photoprofile,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Phone string `json:"phone,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
EmailVerified bool `json:"emailVerified,omitempty"`
|
||||
RoleName string `json:"role,omitempty"`
|
||||
CreatedAt string `json:"createdAt,omitempty"`
|
||||
UpdatedAt string `json:"updatedAt,omitempty"`
|
||||
}
|
||||
|
||||
type RequestUserDTO struct {
|
||||
Name string `json:"name"`
|
||||
Phone string `json:"phone"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
func (r *RequestUserDTO) Validate() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.Name) == "" {
|
||||
errors["name"] = append(errors["name"], "Name is required")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Phone) == "" {
|
||||
errors["phone"] = append(errors["phone"], "Phone number is required")
|
||||
} else if !utils.IsValidPhoneNumber(r.Phone) {
|
||||
errors["phone"] = append(errors["phone"], "Invalid phone number format. Use +62 followed by 9-13 digits")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(r.Email) != "" && !utils.IsValidEmail(r.Email) {
|
||||
errors["email"] = append(errors["email"], "Invalid email format")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
||||
|
||||
type UpdatePasswordDTO struct {
|
||||
OldPassword string `json:"old_password"`
|
||||
NewPassword string `json:"new_password"`
|
||||
ConfirmNewPassword string `json:"confirm_new_password"`
|
||||
}
|
||||
|
||||
func (u *UpdatePasswordDTO) Validate() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if u.OldPassword == "" {
|
||||
errors["old_password"] = append(errors["old_password"], "Old password is required")
|
||||
}
|
||||
|
||||
if u.NewPassword == "" {
|
||||
errors["new_password"] = append(errors["new_password"], "New password is required")
|
||||
} else if !utils.IsValidPassword(u.NewPassword) {
|
||||
errors["new_password"] = append(errors["new_password"], "Password must contain at least one uppercase letter, one digit, and one special character")
|
||||
}
|
||||
|
||||
if u.ConfirmNewPassword == "" {
|
||||
errors["confirm_new_password"] = append(errors["confirm_new_password"], "Confirm new password is required")
|
||||
} else if u.NewPassword != u.ConfirmNewPassword {
|
||||
errors["confirm_new_password"] = append(errors["confirm_new_password"], "Passwords do not match")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RequestUserPinDTO struct {
|
||||
Pin string `json:"userpin"`
|
||||
}
|
||||
|
||||
func (r *RequestUserPinDTO) Validate() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(r.Pin) == "" {
|
||||
errors["pin"] = append(errors["pin"], "Pin is required")
|
||||
}
|
||||
|
||||
if err := validatePin(r.Pin); err != nil {
|
||||
errors["pin"] = append(errors["pin"], err.Error())
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
||||
|
||||
type UpdateUserPinDTO struct {
|
||||
OldPin string `json:"old_pin"`
|
||||
NewPin string `json:"new_pin"`
|
||||
}
|
||||
|
||||
func (u *UpdateUserPinDTO) Validate() (map[string][]string, bool) {
|
||||
errors := make(map[string][]string)
|
||||
|
||||
if strings.TrimSpace(u.OldPin) == "" {
|
||||
errors["old_pin"] = append(errors["old_pin"], "Old pin is required")
|
||||
}
|
||||
|
||||
if err := validatePin(u.NewPin); err != nil {
|
||||
errors["new_pin"] = append(errors["new_pin"], err.Error())
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors, false
|
||||
}
|
||||
|
||||
return nil, true
|
||||
}
|
||||
|
||||
func isNumeric(s string) bool {
|
||||
re := regexp.MustCompile(`^[0-9]+$`)
|
||||
return re.MatchString(s)
|
||||
}
|
||||
|
||||
func validatePin(pin string) error {
|
||||
if len(pin) != 6 {
|
||||
return fmt.Errorf("pin harus terdiri dari 6 digit")
|
||||
} else if !isNumeric(pin) {
|
||||
return fmt.Errorf("pin harus berupa angka")
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package dto
|
||||
|
||||
type ProvinceResponseDTO struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Regencies []RegencyResponseDTO `json:"regencies,omitempty"`
|
||||
}
|
||||
|
||||
type RegencyResponseDTO struct {
|
||||
ID string `json:"id"`
|
||||
ProvinceID string `json:"province_id"`
|
||||
Name string `json:"name"`
|
||||
Districts []DistrictResponseDTO `json:"districts,omitempty"`
|
||||
}
|
||||
|
||||
type DistrictResponseDTO struct {
|
||||
ID string `json:"id"`
|
||||
RegencyID string `json:"regency_id"`
|
||||
Name string `json:"name"`
|
||||
Villages []VillageResponseDTO `json:"villages,omitempty"`
|
||||
}
|
||||
|
||||
type VillageResponseDTO struct {
|
||||
ID string `json:"id"`
|
||||
DistrictID string `json:"district_id"`
|
||||
Name string `json:"name"`
|
||||
}
|
|
@ -3,7 +3,6 @@ package about
|
|||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"rijig/dto"
|
||||
"rijig/utils"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
@ -20,7 +19,7 @@ func NewAboutHandler(aboutService AboutService) *AboutHandler {
|
|||
}
|
||||
|
||||
func (h *AboutHandler) CreateAbout(c *fiber.Ctx) error {
|
||||
var request dto.RequestAboutDTO
|
||||
var request RequestAboutDTO
|
||||
if err := c.BodyParser(&request); err != nil {
|
||||
return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Invalid request body", map[string][]string{"body": {"Invalid body"}})
|
||||
}
|
||||
|
@ -47,7 +46,7 @@ func (h *AboutHandler) CreateAbout(c *fiber.Ctx) error {
|
|||
func (h *AboutHandler) UpdateAbout(c *fiber.Ctx) error {
|
||||
id := c.Params("id")
|
||||
|
||||
var request dto.RequestAboutDTO
|
||||
var request RequestAboutDTO
|
||||
if err := c.BodyParser(&request); err != nil {
|
||||
log.Printf("Error parsing request body: %v", err)
|
||||
return utils.BadRequest(c, "Invalid input data")
|
||||
|
@ -114,7 +113,7 @@ func (h *AboutHandler) DeleteAbout(c *fiber.Ctx) error {
|
|||
}
|
||||
|
||||
func (h *AboutHandler) CreateAboutDetail(c *fiber.Ctx) error {
|
||||
var request dto.RequestAboutDetailDTO
|
||||
var request RequestAboutDetailDTO
|
||||
if err := c.BodyParser(&request); err != nil {
|
||||
log.Printf("Error parsing request body: %v", err)
|
||||
return utils.BadRequest(c, "Invalid input data")
|
||||
|
@ -143,7 +142,7 @@ func (h *AboutHandler) CreateAboutDetail(c *fiber.Ctx) error {
|
|||
func (h *AboutHandler) UpdateAboutDetail(c *fiber.Ctx) error {
|
||||
id := c.Params("id")
|
||||
|
||||
var request dto.RequestAboutDetailDTO
|
||||
var request RequestAboutDetailDTO
|
||||
if err := c.BodyParser(&request); err != nil {
|
||||
log.Printf("Error parsing request body: %v", err)
|
||||
return utils.BadRequest(c, "Invalid input data")
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"mime/multipart"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"rijig/dto"
|
||||
"rijig/model"
|
||||
"rijig/utils"
|
||||
"time"
|
||||
|
@ -24,15 +23,15 @@ const (
|
|||
)
|
||||
|
||||
type AboutService interface {
|
||||
CreateAbout(ctx context.Context, request dto.RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*dto.ResponseAboutDTO, error)
|
||||
UpdateAbout(ctx context.Context, id string, request dto.RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*dto.ResponseAboutDTO, error)
|
||||
GetAllAbout(ctx context.Context) ([]dto.ResponseAboutDTO, error)
|
||||
GetAboutByID(ctx context.Context, id string) (*dto.ResponseAboutDTO, error)
|
||||
GetAboutDetailById(ctx context.Context, id string) (*dto.ResponseAboutDetailDTO, error)
|
||||
CreateAbout(ctx context.Context, request RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*ResponseAboutDTO, error)
|
||||
UpdateAbout(ctx context.Context, id string, request RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*ResponseAboutDTO, error)
|
||||
GetAllAbout(ctx context.Context) ([]ResponseAboutDTO, error)
|
||||
GetAboutByID(ctx context.Context, id string) (*ResponseAboutDTO, error)
|
||||
GetAboutDetailById(ctx context.Context, id string) (*ResponseAboutDetailDTO, error)
|
||||
DeleteAbout(ctx context.Context, id string) error
|
||||
|
||||
CreateAboutDetail(ctx context.Context, request dto.RequestAboutDetailDTO, coverImageAboutDetail *multipart.FileHeader) (*dto.ResponseAboutDetailDTO, error)
|
||||
UpdateAboutDetail(ctx context.Context, id string, request dto.RequestAboutDetailDTO, imageDetail *multipart.FileHeader) (*dto.ResponseAboutDetailDTO, error)
|
||||
CreateAboutDetail(ctx context.Context, request RequestAboutDetailDTO, coverImageAboutDetail *multipart.FileHeader) (*ResponseAboutDetailDTO, error)
|
||||
UpdateAboutDetail(ctx context.Context, id string, request RequestAboutDetailDTO, imageDetail *multipart.FileHeader) (*ResponseAboutDetailDTO, error)
|
||||
DeleteAboutDetail(ctx context.Context, id string) error
|
||||
}
|
||||
|
||||
|
@ -66,11 +65,11 @@ func (s *aboutService) invalidateAboutDetailCaches(aboutDetailID, aboutID string
|
|||
s.invalidateAboutCaches(aboutID)
|
||||
}
|
||||
|
||||
func formatResponseAboutDetailDTO(about *model.AboutDetail) (*dto.ResponseAboutDetailDTO, error) {
|
||||
func formatResponseAboutDetailDTO(about *model.AboutDetail) (*ResponseAboutDetailDTO, error) {
|
||||
createdAt, _ := utils.FormatDateToIndonesianFormat(about.CreatedAt)
|
||||
updatedAt, _ := utils.FormatDateToIndonesianFormat(about.UpdatedAt)
|
||||
|
||||
response := &dto.ResponseAboutDetailDTO{
|
||||
response := &ResponseAboutDetailDTO{
|
||||
ID: about.ID,
|
||||
AboutID: about.AboutID,
|
||||
ImageDetail: about.ImageDetail,
|
||||
|
@ -82,11 +81,11 @@ func formatResponseAboutDetailDTO(about *model.AboutDetail) (*dto.ResponseAboutD
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func formatResponseAboutDTO(about *model.About) (*dto.ResponseAboutDTO, error) {
|
||||
func formatResponseAboutDTO(about *model.About) (*ResponseAboutDTO, error) {
|
||||
createdAt, _ := utils.FormatDateToIndonesianFormat(about.CreatedAt)
|
||||
updatedAt, _ := utils.FormatDateToIndonesianFormat(about.UpdatedAt)
|
||||
|
||||
response := &dto.ResponseAboutDTO{
|
||||
response := &ResponseAboutDTO{
|
||||
ID: about.ID,
|
||||
Title: about.Title,
|
||||
CoverImage: about.CoverImage,
|
||||
|
@ -194,7 +193,7 @@ func deleteCoverImageAbout(coverimageAboutPath string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *aboutService) CreateAbout(ctx context.Context, request dto.RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*dto.ResponseAboutDTO, error) {
|
||||
func (s *aboutService) CreateAbout(ctx context.Context, request RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*ResponseAboutDTO, error) {
|
||||
errors, valid := request.ValidateAbout()
|
||||
if !valid {
|
||||
return nil, fmt.Errorf("validation error: %v", errors)
|
||||
|
@ -224,7 +223,7 @@ func (s *aboutService) CreateAbout(ctx context.Context, request dto.RequestAbout
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (s *aboutService) UpdateAbout(ctx context.Context, id string, request dto.RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*dto.ResponseAboutDTO, error) {
|
||||
func (s *aboutService) UpdateAbout(ctx context.Context, id string, request RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*ResponseAboutDTO, error) {
|
||||
errors, valid := request.ValidateAbout()
|
||||
if !valid {
|
||||
return nil, fmt.Errorf("validation error: %v", errors)
|
||||
|
@ -271,9 +270,9 @@ func (s *aboutService) UpdateAbout(ctx context.Context, id string, request dto.R
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (s *aboutService) GetAllAbout(ctx context.Context) ([]dto.ResponseAboutDTO, error) {
|
||||
func (s *aboutService) GetAllAbout(ctx context.Context) ([]ResponseAboutDTO, error) {
|
||||
|
||||
var cachedAbouts []dto.ResponseAboutDTO
|
||||
var cachedAbouts []ResponseAboutDTO
|
||||
if err := utils.GetCache(cacheKeyAllAbout, &cachedAbouts); err == nil {
|
||||
return cachedAbouts, nil
|
||||
}
|
||||
|
@ -283,7 +282,7 @@ func (s *aboutService) GetAllAbout(ctx context.Context) ([]dto.ResponseAboutDTO,
|
|||
return nil, fmt.Errorf("failed to get About list: %v", err)
|
||||
}
|
||||
|
||||
var aboutDTOList []dto.ResponseAboutDTO
|
||||
var aboutDTOList []ResponseAboutDTO
|
||||
for _, about := range aboutList {
|
||||
response, err := formatResponseAboutDTO(&about)
|
||||
if err != nil {
|
||||
|
@ -300,10 +299,10 @@ func (s *aboutService) GetAllAbout(ctx context.Context) ([]dto.ResponseAboutDTO,
|
|||
return aboutDTOList, nil
|
||||
}
|
||||
|
||||
func (s *aboutService) GetAboutByID(ctx context.Context, id string) (*dto.ResponseAboutDTO, error) {
|
||||
func (s *aboutService) GetAboutByID(ctx context.Context, id string) (*ResponseAboutDTO, error) {
|
||||
cacheKey := fmt.Sprintf(cacheKeyAboutByID, id)
|
||||
|
||||
var cachedAbout dto.ResponseAboutDTO
|
||||
var cachedAbout ResponseAboutDTO
|
||||
if err := utils.GetCache(cacheKey, &cachedAbout); err == nil {
|
||||
return &cachedAbout, nil
|
||||
}
|
||||
|
@ -318,7 +317,7 @@ func (s *aboutService) GetAboutByID(ctx context.Context, id string) (*dto.Respon
|
|||
return nil, fmt.Errorf("error formatting About response: %v", err)
|
||||
}
|
||||
|
||||
var responseDetails []dto.ResponseAboutDetailDTO
|
||||
var responseDetails []ResponseAboutDetailDTO
|
||||
for _, detail := range about.AboutDetail {
|
||||
formattedDetail, err := formatResponseAboutDetailDTO(&detail)
|
||||
if err != nil {
|
||||
|
@ -336,10 +335,10 @@ func (s *aboutService) GetAboutByID(ctx context.Context, id string) (*dto.Respon
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (s *aboutService) GetAboutDetailById(ctx context.Context, id string) (*dto.ResponseAboutDetailDTO, error) {
|
||||
func (s *aboutService) GetAboutDetailById(ctx context.Context, id string) (*ResponseAboutDetailDTO, error) {
|
||||
cacheKey := fmt.Sprintf(cacheKeyAboutDetail, id)
|
||||
|
||||
var cachedDetail dto.ResponseAboutDetailDTO
|
||||
var cachedDetail ResponseAboutDetailDTO
|
||||
if err := utils.GetCache(cacheKey, &cachedDetail); err == nil {
|
||||
return &cachedDetail, nil
|
||||
}
|
||||
|
@ -390,7 +389,7 @@ func (s *aboutService) DeleteAbout(ctx context.Context, id string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *aboutService) CreateAboutDetail(ctx context.Context, request dto.RequestAboutDetailDTO, coverImageAboutDetail *multipart.FileHeader) (*dto.ResponseAboutDetailDTO, error) {
|
||||
func (s *aboutService) CreateAboutDetail(ctx context.Context, request RequestAboutDetailDTO, coverImageAboutDetail *multipart.FileHeader) (*ResponseAboutDetailDTO, error) {
|
||||
errors, valid := request.ValidateAboutDetail()
|
||||
if !valid {
|
||||
return nil, fmt.Errorf("validation error: %v", errors)
|
||||
|
@ -426,7 +425,7 @@ func (s *aboutService) CreateAboutDetail(ctx context.Context, request dto.Reques
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (s *aboutService) UpdateAboutDetail(ctx context.Context, id string, request dto.RequestAboutDetailDTO, imageDetail *multipart.FileHeader) (*dto.ResponseAboutDetailDTO, error) {
|
||||
func (s *aboutService) UpdateAboutDetail(ctx context.Context, id string, request RequestAboutDetailDTO, imageDetail *multipart.FileHeader) (*ResponseAboutDetailDTO, error) {
|
||||
errors, valid := request.ValidateAboutDetail()
|
||||
if !valid {
|
||||
return nil, fmt.Errorf("validation error: %v", errors)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package address
|
||||
|
||||
import (
|
||||
"rijig/dto"
|
||||
"rijig/middleware"
|
||||
"rijig/utils"
|
||||
|
||||
|
@ -17,7 +16,7 @@ func NewAddressHandler(addressService AddressService) *AddressHandler {
|
|||
}
|
||||
|
||||
func (h *AddressHandler) CreateAddress(c *fiber.Ctx) error {
|
||||
var request dto.CreateAddressDTO
|
||||
var request CreateAddressDTO
|
||||
claims, err := middleware.GetUserFromContext(c)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -74,7 +73,7 @@ func (h *AddressHandler) UpdateAddress(c *fiber.Ctx) error {
|
|||
|
||||
addressID := c.Params("address_id")
|
||||
|
||||
var request dto.CreateAddressDTO
|
||||
var request CreateAddressDTO
|
||||
claims, err := middleware.GetUserFromContext(c)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"rijig/dto"
|
||||
"rijig/internal/wilayahindo"
|
||||
"rijig/model"
|
||||
"rijig/utils"
|
||||
|
@ -20,10 +19,10 @@ const (
|
|||
)
|
||||
|
||||
type AddressService interface {
|
||||
CreateAddress(ctx context.Context, userID string, request dto.CreateAddressDTO) (*dto.AddressResponseDTO, error)
|
||||
GetAddressByUserID(ctx context.Context, userID string) ([]dto.AddressResponseDTO, error)
|
||||
GetAddressByID(ctx context.Context, userID, id string) (*dto.AddressResponseDTO, error)
|
||||
UpdateAddress(ctx context.Context, userID, id string, addressDTO dto.CreateAddressDTO) (*dto.AddressResponseDTO, error)
|
||||
CreateAddress(ctx context.Context, userID string, request CreateAddressDTO) (*AddressResponseDTO, error)
|
||||
GetAddressByUserID(ctx context.Context, userID string) ([]AddressResponseDTO, error)
|
||||
GetAddressByID(ctx context.Context, userID, id string) (*AddressResponseDTO, error)
|
||||
UpdateAddress(ctx context.Context, userID, id string, addressDTO CreateAddressDTO) (*AddressResponseDTO, error)
|
||||
DeleteAddress(ctx context.Context, userID, id string) error
|
||||
}
|
||||
|
||||
|
@ -39,7 +38,7 @@ func NewAddressService(addressRepo AddressRepository, wilayahRepo wilayahindo.Wi
|
|||
}
|
||||
}
|
||||
|
||||
func (s *addressService) validateWilayahIDs(ctx context.Context, addressDTO dto.CreateAddressDTO) (string, string, string, string, error) {
|
||||
func (s *addressService) validateWilayahIDs(ctx context.Context, addressDTO CreateAddressDTO) (string, string, string, string, error) {
|
||||
|
||||
province, _, err := s.wilayahRepo.FindProvinceByID(ctx, addressDTO.Province, 0, 0)
|
||||
if err != nil {
|
||||
|
@ -64,11 +63,11 @@ func (s *addressService) validateWilayahIDs(ctx context.Context, addressDTO dto.
|
|||
return province.Name, regency.Name, district.Name, village.Name, nil
|
||||
}
|
||||
|
||||
func (s *addressService) mapToResponseDTO(address *model.Address) *dto.AddressResponseDTO {
|
||||
func (s *addressService) mapToResponseDTO(address *model.Address) *AddressResponseDTO {
|
||||
createdAt, _ := utils.FormatDateToIndonesianFormat(address.CreatedAt)
|
||||
updatedAt, _ := utils.FormatDateToIndonesianFormat(address.UpdatedAt)
|
||||
|
||||
return &dto.AddressResponseDTO{
|
||||
return &AddressResponseDTO{
|
||||
UserID: address.UserID,
|
||||
ID: address.ID,
|
||||
Province: address.Province,
|
||||
|
@ -98,20 +97,20 @@ func (s *addressService) invalidateAddressCaches(userID, addressID string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *addressService) cacheAddress(addressDTO *dto.AddressResponseDTO) {
|
||||
func (s *addressService) cacheAddress(addressDTO *AddressResponseDTO) {
|
||||
cacheKey := fmt.Sprintf(addressCacheKeyPattern, addressDTO.ID)
|
||||
if err := utils.SetCache(cacheKey, addressDTO, cacheTTL); err != nil {
|
||||
fmt.Printf("Error caching address to Redis: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *addressService) cacheUserAddresses(ctx context.Context, userID string) ([]dto.AddressResponseDTO, error) {
|
||||
func (s *addressService) cacheUserAddresses(ctx context.Context, userID string) ([]AddressResponseDTO, error) {
|
||||
addresses, err := s.addressRepo.FindAddressByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch addresses: %w", err)
|
||||
}
|
||||
|
||||
var addressDTOs []dto.AddressResponseDTO
|
||||
var addressDTOs []AddressResponseDTO
|
||||
for _, address := range addresses {
|
||||
addressDTOs = append(addressDTOs, *s.mapToResponseDTO(&address))
|
||||
}
|
||||
|
@ -137,7 +136,7 @@ func (s *addressService) checkAddressOwnership(ctx context.Context, userID, addr
|
|||
return address, nil
|
||||
}
|
||||
|
||||
func (s *addressService) CreateAddress(ctx context.Context, userID string, addressDTO dto.CreateAddressDTO) (*dto.AddressResponseDTO, error) {
|
||||
func (s *addressService) CreateAddress(ctx context.Context, userID string, addressDTO CreateAddressDTO) (*AddressResponseDTO, error) {
|
||||
|
||||
provinceName, regencyName, districtName, villageName, err := s.validateWilayahIDs(ctx, addressDTO)
|
||||
if err != nil {
|
||||
|
@ -168,10 +167,10 @@ func (s *addressService) CreateAddress(ctx context.Context, userID string, addre
|
|||
return responseDTO, nil
|
||||
}
|
||||
|
||||
func (s *addressService) GetAddressByUserID(ctx context.Context, userID string) ([]dto.AddressResponseDTO, error) {
|
||||
func (s *addressService) GetAddressByUserID(ctx context.Context, userID string) ([]AddressResponseDTO, error) {
|
||||
|
||||
cacheKey := fmt.Sprintf(userAddressesCacheKeyPattern, userID)
|
||||
var cachedAddresses []dto.AddressResponseDTO
|
||||
var cachedAddresses []AddressResponseDTO
|
||||
|
||||
if err := utils.GetCache(cacheKey, &cachedAddresses); err == nil {
|
||||
return cachedAddresses, nil
|
||||
|
@ -180,7 +179,7 @@ func (s *addressService) GetAddressByUserID(ctx context.Context, userID string)
|
|||
return s.cacheUserAddresses(ctx, userID)
|
||||
}
|
||||
|
||||
func (s *addressService) GetAddressByID(ctx context.Context, userID, id string) (*dto.AddressResponseDTO, error) {
|
||||
func (s *addressService) GetAddressByID(ctx context.Context, userID, id string) (*AddressResponseDTO, error) {
|
||||
|
||||
address, err := s.checkAddressOwnership(ctx, userID, id)
|
||||
if err != nil {
|
||||
|
@ -188,7 +187,7 @@ func (s *addressService) GetAddressByID(ctx context.Context, userID, id string)
|
|||
}
|
||||
|
||||
cacheKey := fmt.Sprintf(addressCacheKeyPattern, id)
|
||||
var cachedAddress dto.AddressResponseDTO
|
||||
var cachedAddress AddressResponseDTO
|
||||
|
||||
if err := utils.GetCache(cacheKey, &cachedAddress); err == nil {
|
||||
return &cachedAddress, nil
|
||||
|
@ -200,7 +199,7 @@ func (s *addressService) GetAddressByID(ctx context.Context, userID, id string)
|
|||
return responseDTO, nil
|
||||
}
|
||||
|
||||
func (s *addressService) UpdateAddress(ctx context.Context, userID, id string, addressDTO dto.CreateAddressDTO) (*dto.AddressResponseDTO, error) {
|
||||
func (s *addressService) UpdateAddress(ctx context.Context, userID, id string, addressDTO CreateAddressDTO) (*AddressResponseDTO, error) {
|
||||
|
||||
address, err := s.checkAddressOwnership(ctx, userID, id)
|
||||
if err != nil {
|
||||
|
|
|
@ -2,6 +2,8 @@ package authentication
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"rijig/model"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
@ -15,6 +17,9 @@ type AuthenticationRepository interface {
|
|||
CreateUser(ctx context.Context, user *model.User) error
|
||||
UpdateUser(ctx context.Context, user *model.User) error
|
||||
PatchUser(ctx context.Context, userID string, updates map[string]interface{}) error
|
||||
|
||||
GetIdentityCardsByUserRegStatus(ctx context.Context, userRegStatus string) ([]model.IdentityCard, error)
|
||||
GetCompanyProfilesByUserRegStatus(ctx context.Context, userRegStatus string) ([]model.CompanyProfile, error)
|
||||
}
|
||||
|
||||
type authenticationRepository struct {
|
||||
|
@ -84,3 +89,37 @@ func (r *authenticationRepository) PatchUser(ctx context.Context, userID string,
|
|||
Where("id = ?", userID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
func (r *authenticationRepository) GetIdentityCardsByUserRegStatus(ctx context.Context, userRegStatus string) ([]model.IdentityCard, error) {
|
||||
var identityCards []model.IdentityCard
|
||||
|
||||
if err := r.db.WithContext(ctx).
|
||||
Joins("JOIN users ON identity_cards.user_id = users.id").
|
||||
Where("users.registration_status = ?", userRegStatus).
|
||||
Preload("User").
|
||||
Preload("User.Role").
|
||||
Find(&identityCards).Error; err != nil {
|
||||
log.Printf("Error fetching identity cards by user registration status: %v", err)
|
||||
return nil, fmt.Errorf("error fetching identity cards by user registration status: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("Found %d identity cards with registration status: %s", len(identityCards), userRegStatus)
|
||||
return identityCards, nil
|
||||
}
|
||||
|
||||
func (r *authenticationRepository) GetCompanyProfilesByUserRegStatus(ctx context.Context, userRegStatus string) ([]model.CompanyProfile, error) {
|
||||
var companyProfiles []model.CompanyProfile
|
||||
|
||||
if err := r.db.WithContext(ctx).
|
||||
Joins("JOIN users ON company_profiles.user_id = users.id").
|
||||
Where("users.registration_status = ?", userRegStatus).
|
||||
Preload("User").
|
||||
Preload("User.Role").
|
||||
Find(&companyProfiles).Error; err != nil {
|
||||
log.Printf("Error fetching company profiles by user registration status: %v", err)
|
||||
return nil, fmt.Errorf("error fetching company profiles by user registration status: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("Found %d company profiles with registration status: %s", len(companyProfiles), userRegStatus)
|
||||
return companyProfiles, nil
|
||||
}
|
||||
|
|
|
@ -315,7 +315,9 @@ func (s *authenticationService) VerifyLoginOTP(ctx context.Context, req *VerifyO
|
|||
return nil, fmt.Errorf("kode OTP salah")
|
||||
}
|
||||
|
||||
user, err := s.authRepo.FindUserByID(ctx, otpData.UserID)
|
||||
normalizedRole := strings.ToLower(req.RoleName)
|
||||
|
||||
user, err := s.authRepo.FindUserByPhoneAndRole(ctx, req.Phone, normalizedRole)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("user tidak ditemukan")
|
||||
}
|
||||
|
@ -324,24 +326,29 @@ func (s *authenticationService) VerifyLoginOTP(ctx context.Context, req *VerifyO
|
|||
|
||||
tokenResponse, err := utils.GenerateTokenPair(
|
||||
user.ID,
|
||||
user.Role.RoleName,
|
||||
normalizedRole,
|
||||
req.DeviceID,
|
||||
"pin_verification_required",
|
||||
user.RegistrationStatus,
|
||||
int(user.RegistrationProgress),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("gagal generate token: %v", err)
|
||||
}
|
||||
|
||||
nextStep := utils.GetNextRegistrationStep(
|
||||
normalizedRole,
|
||||
int(user.RegistrationProgress),
|
||||
user.RegistrationStatus,
|
||||
)
|
||||
|
||||
return &AuthResponse{
|
||||
Message: "OTP berhasil diverifikasi, silakan masukkan PIN",
|
||||
Message: "otp berhasil diverifikasi",
|
||||
AccessToken: tokenResponse.AccessToken,
|
||||
RefreshToken: tokenResponse.RefreshToken,
|
||||
TokenType: string(tokenResponse.TokenType),
|
||||
ExpiresIn: tokenResponse.ExpiresIn,
|
||||
User: convertUserToResponse(user),
|
||||
RegistrationStatus: user.RegistrationStatus,
|
||||
NextStep: "Masukkan PIN",
|
||||
NextStep: nextStep,
|
||||
SessionID: tokenResponse.SessionID,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package company
|
|||
|
||||
import (
|
||||
"rijig/config"
|
||||
"rijig/internal/authentication"
|
||||
"rijig/middleware"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
@ -9,7 +10,8 @@ import (
|
|||
|
||||
func CompanyRouter(api fiber.Router) {
|
||||
companyProfileRepo := NewCompanyProfileRepository(config.DB)
|
||||
companyProfileService := NewCompanyProfileService(companyProfileRepo)
|
||||
authRepo := authentication.NewAuthenticationRepository(config.DB)
|
||||
companyProfileService := NewCompanyProfileService(companyProfileRepo, authRepo)
|
||||
companyProfileHandler := NewCompanyProfileHandler(companyProfileService)
|
||||
|
||||
companyProfileAPI := api.Group("/companyprofile")
|
||||
|
|
|
@ -3,8 +3,13 @@ package company
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"rijig/internal/authentication"
|
||||
"rijig/internal/role"
|
||||
"rijig/internal/userprofile"
|
||||
"rijig/model"
|
||||
"rijig/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CompanyProfileService interface {
|
||||
|
@ -13,15 +18,19 @@ type CompanyProfileService interface {
|
|||
GetCompanyProfilesByUserID(ctx context.Context, userID string) ([]ResponseCompanyProfileDTO, error)
|
||||
UpdateCompanyProfile(ctx context.Context, userID string, request *RequestCompanyProfileDTO) (*ResponseCompanyProfileDTO, error)
|
||||
DeleteCompanyProfile(ctx context.Context, userID string) error
|
||||
|
||||
GetAllCompanyProfilesByRegStatus(ctx context.Context, userRegStatus string) ([]ResponseCompanyProfileDTO, error)
|
||||
UpdateUserRegistrationStatusByCompany(ctx context.Context, companyUserID string, newStatus string) error
|
||||
}
|
||||
|
||||
type companyProfileService struct {
|
||||
companyRepo CompanyProfileRepository
|
||||
authRepo authentication.AuthenticationRepository
|
||||
}
|
||||
|
||||
func NewCompanyProfileService(companyRepo CompanyProfileRepository) CompanyProfileService {
|
||||
func NewCompanyProfileService(companyRepo CompanyProfileRepository, authRepo authentication.AuthenticationRepository) CompanyProfileService {
|
||||
return &companyProfileService{
|
||||
companyRepo: companyRepo,
|
||||
companyRepo, authRepo,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,9 +57,9 @@ func FormatResponseCompanyProfile(companyProfile *model.CompanyProfile) (*Respon
|
|||
}
|
||||
|
||||
func (s *companyProfileService) CreateCompanyProfile(ctx context.Context, userID string, request *RequestCompanyProfileDTO) (*ResponseCompanyProfileDTO, error) {
|
||||
if errors, valid := request.ValidateCompanyProfileInput(); !valid {
|
||||
return nil, fmt.Errorf("validation failed: %v", errors)
|
||||
}
|
||||
// if errors, valid := request.ValidateCompanyProfileInput(); !valid {
|
||||
// return nil, fmt.Errorf("validation failed: %v", errors)
|
||||
// }
|
||||
|
||||
companyProfile := &model.CompanyProfile{
|
||||
UserID: userID,
|
||||
|
@ -134,3 +143,100 @@ func (s *companyProfileService) UpdateCompanyProfile(ctx context.Context, userID
|
|||
func (s *companyProfileService) DeleteCompanyProfile(ctx context.Context, userID string) error {
|
||||
return s.companyRepo.DeleteCompanyProfileByUserID(ctx, userID)
|
||||
}
|
||||
|
||||
func (s *companyProfileService) GetAllCompanyProfilesByRegStatus(ctx context.Context, userRegStatus string) ([]ResponseCompanyProfileDTO, error) {
|
||||
companyProfiles, err := s.authRepo.GetCompanyProfilesByUserRegStatus(ctx, userRegStatus)
|
||||
if err != nil {
|
||||
log.Printf("Error getting company profiles by registration status: %v", err)
|
||||
return nil, fmt.Errorf("failed to get company profiles: %w", err)
|
||||
}
|
||||
|
||||
var response []ResponseCompanyProfileDTO
|
||||
for _, profile := range companyProfiles {
|
||||
dto := ResponseCompanyProfileDTO{
|
||||
ID: profile.ID,
|
||||
UserID: profile.UserID,
|
||||
CompanyName: profile.CompanyName,
|
||||
CompanyAddress: profile.CompanyAddress,
|
||||
CompanyPhone: profile.CompanyPhone,
|
||||
CompanyEmail: profile.CompanyEmail,
|
||||
CompanyLogo: profile.CompanyLogo,
|
||||
CompanyWebsite: profile.CompanyWebsite,
|
||||
TaxID: profile.TaxID,
|
||||
FoundedDate: profile.FoundedDate,
|
||||
CompanyType: profile.CompanyType,
|
||||
CompanyDescription: profile.CompanyDescription,
|
||||
CreatedAt: profile.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
||||
UpdatedAt: profile.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
||||
}
|
||||
response = append(response, dto)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *companyProfileService) UpdateUserRegistrationStatusByCompany(ctx context.Context, companyUserID string, newStatus string) error {
|
||||
|
||||
user, err := s.authRepo.FindUserByID(ctx, companyUserID)
|
||||
if err != nil {
|
||||
log.Printf("Error finding user by ID %s: %v", companyUserID, err)
|
||||
return fmt.Errorf("user not found: %w", err)
|
||||
}
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"registration_status": newStatus,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
switch newStatus {
|
||||
case utils.RegStatusConfirmed:
|
||||
updates["registration_progress"] = utils.ProgressDataSubmitted
|
||||
case utils.RegStatusRejected:
|
||||
updates["registration_progress"] = utils.ProgressOTPVerified
|
||||
}
|
||||
|
||||
err = s.authRepo.PatchUser(ctx, user.ID, updates)
|
||||
if err != nil {
|
||||
log.Printf("Error updating user registration status for user ID %s: %v", user.ID, err)
|
||||
return fmt.Errorf("failed to update user registration status: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("Successfully updated registration status for user ID %s to %s", user.ID, newStatus)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *companyProfileService) GetUserProfile(ctx context.Context, userID string) (*userprofile.UserProfileResponseDTO, error) {
|
||||
user, err := s.authRepo.FindUserByID(ctx, userID)
|
||||
if err != nil {
|
||||
log.Printf("Error getting user profile for ID %s: %v", userID, err)
|
||||
return nil, fmt.Errorf("failed to get user profile: %w", err)
|
||||
}
|
||||
|
||||
response := &userprofile.UserProfileResponseDTO{
|
||||
ID: user.ID,
|
||||
Name: user.Name,
|
||||
Gender: user.Gender,
|
||||
Dateofbirth: user.Dateofbirth,
|
||||
Placeofbirth: user.Placeofbirth,
|
||||
Phone: user.Phone,
|
||||
Email: user.Email,
|
||||
PhoneVerified: user.PhoneVerified,
|
||||
CreatedAt: user.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
||||
UpdatedAt: user.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
||||
}
|
||||
|
||||
if user.Avatar != nil {
|
||||
response.Avatar = *user.Avatar
|
||||
}
|
||||
|
||||
if user.Role != nil {
|
||||
response.Role = role.RoleResponseDTO{
|
||||
ID: user.Role.ID,
|
||||
RoleName: user.Role.RoleName,
|
||||
CreatedAt: user.Role.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
||||
UpdatedAt: user.Role.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
||||
}
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ type ResponseIdentityCardDTO struct {
|
|||
ID string `json:"id"`
|
||||
UserID string `json:"userId"`
|
||||
Identificationumber string `json:"identificationumber"`
|
||||
Fullname string `json:"fullname"`
|
||||
Placeofbirth string `json:"placeofbirth"`
|
||||
Dateofbirth string `json:"dateofbirth"`
|
||||
Gender string `json:"gender"`
|
||||
|
@ -31,9 +32,10 @@ type ResponseIdentityCardDTO struct {
|
|||
}
|
||||
|
||||
type RequestIdentityCardDTO struct {
|
||||
DeviceID string `json:"device_id"`
|
||||
// DeviceID string `json:"device_id"`
|
||||
UserID string `json:"userId"`
|
||||
Identificationumber string `json:"identificationumber"`
|
||||
Fullname string `json:"fullname"`
|
||||
Placeofbirth string `json:"placeofbirth"`
|
||||
Dateofbirth string `json:"dateofbirth"`
|
||||
Gender string `json:"gender"`
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package identitycart
|
||||
|
||||
import (
|
||||
"log"
|
||||
"rijig/middleware"
|
||||
"rijig/utils"
|
||||
"strings"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
@ -18,27 +20,33 @@ func NewIdentityCardHandler(service IdentityCardService) *IdentityCardHandler {
|
|||
func (h *IdentityCardHandler) CreateIdentityCardHandler(c *fiber.Ctx) error {
|
||||
claims, err := middleware.GetUserFromContext(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cardPhoto, err := c.FormFile("cardphoto")
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, "KTP photo is required")
|
||||
log.Printf("Error getting user from context: %v", err)
|
||||
return utils.Unauthorized(c, "unauthorized access")
|
||||
}
|
||||
|
||||
var input RequestIdentityCardDTO
|
||||
if err := c.BodyParser(&input); err != nil {
|
||||
log.Printf("Error parsing body: %v", err)
|
||||
return utils.BadRequest(c, "Invalid input format")
|
||||
}
|
||||
|
||||
|
||||
if errs, valid := input.ValidateIdentityCardInput(); !valid {
|
||||
return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Input validation failed", errs)
|
||||
}
|
||||
|
||||
response, err := h.service.CreateIdentityCard(c.Context(), claims.UserID, &input, cardPhoto)
|
||||
cardPhoto, err := c.FormFile("cardphoto")
|
||||
if err != nil {
|
||||
return utils.InternalServerError(c, err.Error())
|
||||
log.Printf("Error getting card photo: %v", err)
|
||||
return utils.BadRequest(c, "KTP photo is required")
|
||||
}
|
||||
|
||||
response, err := h.service.CreateIdentityCard(c.Context(), claims.UserID, claims.DeviceID, &input, cardPhoto)
|
||||
if err != nil {
|
||||
log.Printf("Error creating identity card: %v", err)
|
||||
if strings.Contains(err.Error(), "invalid file type") {
|
||||
return utils.BadRequest(c, err.Error())
|
||||
}
|
||||
return utils.InternalServerError(c, "Failed to create identity card")
|
||||
}
|
||||
|
||||
return utils.SuccessWithData(c, "KTP successfully submitted", response)
|
||||
|
@ -47,27 +55,158 @@ func (h *IdentityCardHandler) CreateIdentityCardHandler(c *fiber.Ctx) error {
|
|||
func (h *IdentityCardHandler) GetIdentityByID(c *fiber.Ctx) error {
|
||||
id := c.Params("id")
|
||||
if id == "" {
|
||||
return utils.BadRequest(c, "id is required")
|
||||
return utils.BadRequest(c, "ID is required")
|
||||
}
|
||||
|
||||
result, err := h.service.GetIdentityCardByID(c.Context(), id)
|
||||
if err != nil {
|
||||
return utils.NotFound(c, "data not found")
|
||||
log.Printf("Error getting identity card by ID %s: %v", id, err)
|
||||
return utils.NotFound(c, "Identity card not found")
|
||||
}
|
||||
|
||||
return utils.SuccessWithData(c, "success retrieve identity card", result)
|
||||
return utils.SuccessWithData(c, "Successfully retrieved identity card", result)
|
||||
}
|
||||
|
||||
func (h *IdentityCardHandler) GetIdentityByUserId(c *fiber.Ctx) error {
|
||||
claims, err := middleware.GetUserFromContext(c)
|
||||
if err != nil {
|
||||
return err
|
||||
log.Printf("Error getting user from context: %v", err)
|
||||
return utils.Unauthorized(c, "Unauthorized access")
|
||||
}
|
||||
|
||||
result, err := h.service.GetIdentityCardsByUserID(c.Context(), claims.UserID)
|
||||
if err != nil {
|
||||
return utils.InternalServerError(c, "failed to fetch your identity card data")
|
||||
log.Printf("Error getting identity cards for user %s: %v", claims.UserID, err)
|
||||
return utils.InternalServerError(c, "Failed to fetch your identity card data")
|
||||
}
|
||||
|
||||
return utils.SuccessWithData(c, "success retrieve your identity card", result)
|
||||
return utils.SuccessWithData(c, "Successfully retrieved your identity cards", result)
|
||||
}
|
||||
|
||||
func (h *IdentityCardHandler) UpdateIdentityCardHandler(c *fiber.Ctx) error {
|
||||
claims, err := middleware.GetUserFromContext(c)
|
||||
if err != nil {
|
||||
log.Printf("Error getting user from context: %v", err)
|
||||
return utils.Unauthorized(c, "Unauthorized access")
|
||||
}
|
||||
|
||||
id := c.Params("id")
|
||||
if id == "" {
|
||||
return utils.BadRequest(c, "Identity card ID is required")
|
||||
}
|
||||
|
||||
var input RequestIdentityCardDTO
|
||||
if err := c.BodyParser(&input); err != nil {
|
||||
log.Printf("Error parsing body: %v", err)
|
||||
return utils.BadRequest(c, "Invalid input format")
|
||||
}
|
||||
|
||||
if errs, valid := input.ValidateIdentityCardInput(); !valid {
|
||||
return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Input validation failed", errs)
|
||||
}
|
||||
|
||||
cardPhoto, err := c.FormFile("cardphoto")
|
||||
if err != nil && err.Error() != "there is no uploaded file associated with the given key" {
|
||||
log.Printf("Error getting card photo: %v", err)
|
||||
return utils.BadRequest(c, "Invalid card photo")
|
||||
}
|
||||
|
||||
if cardPhoto != nil && cardPhoto.Size > 5*1024*1024 {
|
||||
return utils.BadRequest(c, "File size must be less than 5MB")
|
||||
}
|
||||
|
||||
response, err := h.service.UpdateIdentityCard(c.Context(), claims.UserID, id, &input, cardPhoto)
|
||||
if err != nil {
|
||||
log.Printf("Error updating identity card: %v", err)
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
return utils.NotFound(c, "Identity card not found")
|
||||
}
|
||||
if strings.Contains(err.Error(), "invalid file type") {
|
||||
return utils.BadRequest(c, err.Error())
|
||||
}
|
||||
return utils.InternalServerError(c, "Failed to update identity card")
|
||||
}
|
||||
|
||||
return utils.SuccessWithData(c, "Identity card successfully updated", response)
|
||||
}
|
||||
|
||||
func (h *IdentityCardHandler) GetAllIdentityCardsByRegStatus(c *fiber.Ctx) error {
|
||||
_, err := middleware.GetUserFromContext(c)
|
||||
if err != nil {
|
||||
log.Printf("Error getting user from context: %v", err)
|
||||
return utils.Unauthorized(c, "Unauthorized access")
|
||||
}
|
||||
|
||||
// if claims.Role != "admin" {
|
||||
// return utils.Forbidden(c, "Access denied: admin role required")
|
||||
// }
|
||||
|
||||
status := c.Query("status", utils.RegStatusPending)
|
||||
|
||||
validStatuses := map[string]bool{
|
||||
utils.RegStatusPending: true,
|
||||
"confirmed": true,
|
||||
"rejected": true,
|
||||
}
|
||||
|
||||
if !validStatuses[status] {
|
||||
return utils.BadRequest(c, "Invalid status. Valid values: pending, confirmed, rejected")
|
||||
}
|
||||
|
||||
result, err := h.service.GetAllIdentityCardsByRegStatus(c.Context(), status)
|
||||
if err != nil {
|
||||
log.Printf("Error getting identity cards by status %s: %v", status, err)
|
||||
return utils.InternalServerError(c, "Failed to fetch identity cards")
|
||||
}
|
||||
|
||||
return utils.SuccessWithData(c, "Successfully retrieved identity cards", result)
|
||||
}
|
||||
|
||||
func (h *IdentityCardHandler) UpdateUserRegistrationStatusByIdentityCard(c *fiber.Ctx) error {
|
||||
_, err := middleware.GetUserFromContext(c)
|
||||
if err != nil {
|
||||
log.Printf("Error getting user from context: %v", err)
|
||||
return utils.Unauthorized(c, "Unauthorized access")
|
||||
}
|
||||
|
||||
userID := c.Params("userId")
|
||||
if userID == "" {
|
||||
return utils.BadRequest(c, "User ID is required")
|
||||
}
|
||||
|
||||
type StatusUpdateRequest struct {
|
||||
Status string `json:"status" validate:"required,oneof=confirmed rejected"`
|
||||
}
|
||||
|
||||
var input StatusUpdateRequest
|
||||
if err := c.BodyParser(&input); err != nil {
|
||||
log.Printf("Error parsing body: %v", err)
|
||||
return utils.BadRequest(c, "Invalid input format")
|
||||
}
|
||||
|
||||
if input.Status != "confirmed" && input.Status != "rejected" {
|
||||
return utils.BadRequest(c, "Invalid status. Valid values: confirmed, rejected")
|
||||
}
|
||||
|
||||
err = h.service.UpdateUserRegistrationStatusByIdentityCard(c.Context(), userID, input.Status)
|
||||
if err != nil {
|
||||
log.Printf("Error updating user registration status: %v", err)
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
return utils.NotFound(c, "User not found")
|
||||
}
|
||||
return utils.InternalServerError(c, "Failed to update registration status")
|
||||
}
|
||||
|
||||
message := "User registration status successfully updated to " + input.Status
|
||||
return utils.Success(c, message)
|
||||
}
|
||||
|
||||
func (h *IdentityCardHandler) DeleteIdentityCardHandler(c *fiber.Ctx) error {
|
||||
|
||||
id := c.Params("id")
|
||||
if id == "" {
|
||||
return utils.BadRequest(c, "Identity card ID is required")
|
||||
}
|
||||
|
||||
return utils.Success(c, "Identity card successfully deleted")
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@ package identitycart
|
|||
import (
|
||||
"rijig/config"
|
||||
"rijig/internal/authentication"
|
||||
"rijig/internal/userprofile"
|
||||
"rijig/middleware"
|
||||
"rijig/utils"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
@ -11,25 +13,34 @@ import (
|
|||
func UserIdentityCardRoute(api fiber.Router) {
|
||||
identityRepo := NewIdentityCardRepository(config.DB)
|
||||
authRepo := authentication.NewAuthenticationRepository(config.DB)
|
||||
identityService := NewIdentityCardService(identityRepo, authRepo)
|
||||
userRepo := userprofile.NewUserProfileRepository(config.DB)
|
||||
identityService := NewIdentityCardService(identityRepo, authRepo, userRepo)
|
||||
identityHandler := NewIdentityCardHandler(identityService)
|
||||
|
||||
identity := api.Group("/identity")
|
||||
|
||||
identity.Post("/create",
|
||||
middleware.AuthMiddleware(),
|
||||
middleware.RequireRoles("pengelola", "pengepul"),
|
||||
middleware.RequireRoles(utils.RolePengepul),
|
||||
identityHandler.CreateIdentityCardHandler,
|
||||
)
|
||||
identity.Get("/:id",
|
||||
middleware.AuthMiddleware(),
|
||||
middleware.RequireRoles("pengelola", "pengepul"),
|
||||
identityHandler.GetIdentityByID,
|
||||
)
|
||||
identity.Get("/s",
|
||||
middleware.AuthMiddleware(),
|
||||
identityHandler.GetIdentityByUserId,
|
||||
)
|
||||
identity.Get("/",
|
||||
middleware.AuthMiddleware(),
|
||||
middleware.RequireRoles("pengelola", "pengepul"),
|
||||
identityHandler.GetIdentityByUserId,
|
||||
middleware.RequireRoles(utils.RoleAdministrator),
|
||||
identityHandler.GetAllIdentityCardsByRegStatus,
|
||||
)
|
||||
identity.Patch("/:userId/status",
|
||||
middleware.AuthMiddleware(),
|
||||
middleware.RequireRoles(utils.RoleAdministrator),
|
||||
identityHandler.UpdateUserRegistrationStatusByIdentityCard,
|
||||
)
|
||||
|
||||
}
|
||||
|
|
|
@ -2,36 +2,49 @@ package identitycart
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"rijig/internal/authentication"
|
||||
"rijig/internal/role"
|
||||
"rijig/internal/userprofile"
|
||||
"rijig/model"
|
||||
"rijig/utils"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type IdentityCardService interface {
|
||||
CreateIdentityCard(ctx context.Context, userID string, request *RequestIdentityCardDTO, cardPhoto *multipart.FileHeader) (*authentication.AuthResponse, error)
|
||||
CreateIdentityCard(ctx context.Context, userID, deviceID string, request *RequestIdentityCardDTO, cardPhoto *multipart.FileHeader) (*authentication.AuthResponse, error)
|
||||
GetIdentityCardByID(ctx context.Context, id string) (*ResponseIdentityCardDTO, error)
|
||||
GetIdentityCardsByUserID(ctx context.Context, userID string) ([]ResponseIdentityCardDTO, error)
|
||||
UpdateIdentityCard(ctx context.Context, userID string, id string, request *RequestIdentityCardDTO, cardPhoto *multipart.FileHeader) (*ResponseIdentityCardDTO, error)
|
||||
|
||||
GetAllIdentityCardsByRegStatus(ctx context.Context, userRegStatus string) ([]ResponseIdentityCardDTO, error)
|
||||
UpdateUserRegistrationStatusByIdentityCard(ctx context.Context, identityCardUserID string, newStatus string) error
|
||||
}
|
||||
|
||||
type identityCardService struct {
|
||||
identityRepo IdentityCardRepository
|
||||
authRepo authentication.AuthenticationRepository
|
||||
userRepo userprofile.UserProfileRepository
|
||||
}
|
||||
|
||||
func NewIdentityCardService(identityRepo IdentityCardRepository, authRepo authentication.AuthenticationRepository) IdentityCardService {
|
||||
func NewIdentityCardService(identityRepo IdentityCardRepository, authRepo authentication.AuthenticationRepository, userRepo userprofile.UserProfileRepository) IdentityCardService {
|
||||
return &identityCardService{
|
||||
identityRepo: identityRepo,
|
||||
authRepo: authRepo,
|
||||
identityRepo,
|
||||
authRepo, userRepo,
|
||||
}
|
||||
}
|
||||
|
||||
type IdentityCardWithUserDTO struct {
|
||||
IdentityCard ResponseIdentityCardDTO `json:"identity_card"`
|
||||
User userprofile.UserProfileResponseDTO `json:"user"`
|
||||
}
|
||||
|
||||
func FormatResponseIdentityCard(identityCard *model.IdentityCard) (*ResponseIdentityCardDTO, error) {
|
||||
createdAt, _ := utils.FormatDateToIndonesianFormat(identityCard.CreatedAt)
|
||||
updatedAt, _ := utils.FormatDateToIndonesianFormat(identityCard.UpdatedAt)
|
||||
|
@ -93,7 +106,7 @@ func (s *identityCardService) saveIdentityCardImage(userID string, cardPhoto *mu
|
|||
}
|
||||
defer dst.Close()
|
||||
|
||||
if _, err := dst.ReadFrom(src); err != nil {
|
||||
if _, err := io.Copy(dst, src); err != nil {
|
||||
return "", fmt.Errorf("failed to save card photo: %v", err)
|
||||
}
|
||||
|
||||
|
@ -123,16 +136,7 @@ func deleteIdentityCardImage(imagePath string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *identityCardService) CreateIdentityCard(ctx context.Context, userID string, request *RequestIdentityCardDTO, cardPhoto *multipart.FileHeader) (*authentication.AuthResponse, error) {
|
||||
|
||||
// Validate essential parameters
|
||||
if userID == "" {
|
||||
return nil, fmt.Errorf("userID cannot be empty")
|
||||
}
|
||||
|
||||
if request.DeviceID == "" {
|
||||
return nil, fmt.Errorf("deviceID cannot be empty")
|
||||
}
|
||||
func (s *identityCardService) CreateIdentityCard(ctx context.Context, userID, deviceID string, request *RequestIdentityCardDTO, cardPhoto *multipart.FileHeader) (*authentication.AuthResponse, error) {
|
||||
|
||||
cardPhotoPath, err := s.saveIdentityCardImage(userID, cardPhoto)
|
||||
if err != nil {
|
||||
|
@ -172,33 +176,13 @@ func (s *identityCardService) CreateIdentityCard(ctx context.Context, userID str
|
|||
return nil, fmt.Errorf("failed to find user: %v", err)
|
||||
}
|
||||
|
||||
// Validate user data
|
||||
if user.Role.RoleName == "" {
|
||||
return nil, fmt.Errorf("user role not found")
|
||||
}
|
||||
|
||||
roleName := strings.ToLower(user.Role.RoleName)
|
||||
|
||||
// Determine new registration status and progress
|
||||
var newRegistrationStatus string
|
||||
var newRegistrationProgress int
|
||||
|
||||
switch roleName {
|
||||
case "pengepul":
|
||||
newRegistrationProgress = 2
|
||||
newRegistrationStatus = utils.RegStatusPending
|
||||
case "pengelola":
|
||||
newRegistrationProgress = 2
|
||||
newRegistrationStatus = user.RegistrationStatus
|
||||
default:
|
||||
newRegistrationProgress = int(user.RegistrationProgress)
|
||||
newRegistrationStatus = user.RegistrationStatus
|
||||
}
|
||||
|
||||
// Update user registration progress and status
|
||||
updates := map[string]interface{}{
|
||||
"registration_progress": newRegistrationProgress,
|
||||
"registration_status": newRegistrationStatus,
|
||||
"registration_progress": utils.ProgressDataSubmitted,
|
||||
"registration_status": utils.RegStatusPending,
|
||||
}
|
||||
|
||||
err = s.authRepo.PatchUser(ctx, userID, updates)
|
||||
|
@ -206,34 +190,46 @@ func (s *identityCardService) CreateIdentityCard(ctx context.Context, userID str
|
|||
return nil, fmt.Errorf("failed to update user: %v", err)
|
||||
}
|
||||
|
||||
// Debug logging before token generation
|
||||
updated, err := s.userRepo.GetByID(ctx, userID)
|
||||
if err != nil {
|
||||
if errors.Is(err, userprofile.ErrUserNotFound) {
|
||||
return nil, fmt.Errorf("user not found")
|
||||
}
|
||||
return nil, fmt.Errorf("failed to get updated user: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("Token Generation Parameters:")
|
||||
log.Printf("- UserID: '%s'", user.ID)
|
||||
log.Printf("- Role: '%s'", user.Role.RoleName)
|
||||
log.Printf("- DeviceID: '%s'", request.DeviceID)
|
||||
log.Printf("- Registration Status: '%s'", newRegistrationStatus)
|
||||
log.Printf("- DeviceID: '%s'", deviceID)
|
||||
log.Printf("- Registration Status: '%s'", utils.RegStatusPending)
|
||||
|
||||
// Generate token pair with updated status
|
||||
tokenResponse, err := utils.GenerateTokenPair(
|
||||
user.ID,
|
||||
user.Role.RoleName,
|
||||
request.DeviceID,
|
||||
newRegistrationStatus,
|
||||
newRegistrationProgress,
|
||||
updated.ID,
|
||||
updated.Role.RoleName,
|
||||
deviceID,
|
||||
updated.RegistrationStatus,
|
||||
int(updated.RegistrationProgress),
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("GenerateTokenPair error: %v", err)
|
||||
return nil, fmt.Errorf("failed to generate token: %v", err)
|
||||
}
|
||||
|
||||
nextStep := utils.GetNextRegistrationStep(
|
||||
updated.Role.RoleName,
|
||||
int(updated.RegistrationProgress),
|
||||
updated.RegistrationStatus,
|
||||
)
|
||||
|
||||
return &authentication.AuthResponse{
|
||||
Message: "identity card berhasil diunggah, silakan tunggu konfirmasi dari admin dalam 1x24 jam",
|
||||
AccessToken: tokenResponse.AccessToken,
|
||||
RefreshToken: tokenResponse.RefreshToken,
|
||||
TokenType: string(tokenResponse.TokenType),
|
||||
ExpiresIn: tokenResponse.ExpiresIn,
|
||||
RegistrationStatus: newRegistrationStatus,
|
||||
NextStep: tokenResponse.NextStep,
|
||||
RegistrationStatus: updated.RegistrationStatus,
|
||||
NextStep: nextStep,
|
||||
SessionID: tokenResponse.SessionID,
|
||||
}, nil
|
||||
}
|
||||
|
@ -319,3 +315,164 @@ func (s *identityCardService) UpdateIdentityCard(ctx context.Context, userID str
|
|||
|
||||
return idcardResponseDTO, nil
|
||||
}
|
||||
|
||||
func (s *identityCardService) GetAllIdentityCardsByRegStatus(ctx context.Context, userRegStatus string) ([]ResponseIdentityCardDTO, error) {
|
||||
identityCards, err := s.authRepo.GetIdentityCardsByUserRegStatus(ctx, userRegStatus)
|
||||
if err != nil {
|
||||
log.Printf("Error getting identity cards by registration status: %v", err)
|
||||
return nil, fmt.Errorf("failed to get identity cards: %w", err)
|
||||
}
|
||||
|
||||
var response []ResponseIdentityCardDTO
|
||||
for _, card := range identityCards {
|
||||
createdAt, _ := utils.FormatDateToIndonesianFormat(card.CreatedAt)
|
||||
updatedAt, _ := utils.FormatDateToIndonesianFormat(card.UpdatedAt)
|
||||
dto := ResponseIdentityCardDTO{
|
||||
ID: card.ID,
|
||||
UserID: card.UserID,
|
||||
Identificationumber: card.Identificationumber,
|
||||
Placeofbirth: card.Placeofbirth,
|
||||
Dateofbirth: card.Dateofbirth,
|
||||
Gender: card.Gender,
|
||||
BloodType: card.BloodType,
|
||||
Province: card.Province,
|
||||
District: card.District,
|
||||
SubDistrict: card.SubDistrict,
|
||||
Hamlet: card.Hamlet,
|
||||
Village: card.Village,
|
||||
Neighbourhood: card.Neighbourhood,
|
||||
PostalCode: card.PostalCode,
|
||||
Religion: card.Religion,
|
||||
Maritalstatus: card.Maritalstatus,
|
||||
Job: card.Job,
|
||||
Citizenship: card.Citizenship,
|
||||
Validuntil: card.Validuntil,
|
||||
Cardphoto: card.Cardphoto,
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: updatedAt,
|
||||
}
|
||||
response = append(response, dto)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *identityCardService) UpdateUserRegistrationStatusByIdentityCard(ctx context.Context, identityCardUserID string, newStatus string) error {
|
||||
|
||||
user, err := s.authRepo.FindUserByID(ctx, identityCardUserID)
|
||||
if err != nil {
|
||||
log.Printf("Error finding user by ID %s: %v", identityCardUserID, err)
|
||||
return fmt.Errorf("user not found: %w", err)
|
||||
}
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"registration_status": newStatus,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
switch newStatus {
|
||||
case utils.RegStatusConfirmed:
|
||||
updates["registration_progress"] = utils.ProgressDataSubmitted
|
||||
|
||||
identityCards, err := s.GetIdentityCardsByUserID(ctx, identityCardUserID)
|
||||
if err != nil {
|
||||
log.Printf("Error fetching identity cards for user ID %s: %v", identityCardUserID, err)
|
||||
return fmt.Errorf("failed to fetch identity card data: %w", err)
|
||||
}
|
||||
|
||||
if len(identityCards) == 0 {
|
||||
log.Printf("No identity card found for user ID %s", identityCardUserID)
|
||||
return fmt.Errorf("no identity card found for user")
|
||||
}
|
||||
|
||||
identityCard := identityCards[0]
|
||||
|
||||
updates["name"] = identityCard.Fullname
|
||||
updates["gender"] = identityCard.Gender
|
||||
updates["dateofbirth"] = identityCard.Dateofbirth
|
||||
updates["placeofbirth"] = identityCard.District
|
||||
|
||||
log.Printf("Syncing user data for ID %s: name=%s, gender=%s, dob=%s, pob=%s",
|
||||
identityCardUserID, identityCard.Fullname, identityCard.Gender,
|
||||
identityCard.Dateofbirth, identityCard.District)
|
||||
|
||||
case utils.RegStatusRejected:
|
||||
updates["registration_progress"] = utils.ProgressOTPVerified
|
||||
|
||||
}
|
||||
|
||||
err = s.authRepo.PatchUser(ctx, user.ID, updates)
|
||||
if err != nil {
|
||||
log.Printf("Error updating user registration status for user ID %s: %v", user.ID, err)
|
||||
return fmt.Errorf("failed to update user registration status: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("Successfully updated registration status for user ID %s to %s", user.ID, newStatus)
|
||||
|
||||
if newStatus == utils.RegStatusConfirmed {
|
||||
log.Printf("User profile data synced successfully for user ID %s", user.ID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *identityCardService) mapIdentityCardToDTO(card model.IdentityCard) ResponseIdentityCardDTO {
|
||||
createdAt, _ := utils.FormatDateToIndonesianFormat(card.CreatedAt)
|
||||
updatedAt, _ := utils.FormatDateToIndonesianFormat(card.UpdatedAt)
|
||||
return ResponseIdentityCardDTO{
|
||||
ID: card.ID,
|
||||
UserID: card.UserID,
|
||||
Identificationumber: card.Identificationumber,
|
||||
Placeofbirth: card.Placeofbirth,
|
||||
Dateofbirth: card.Dateofbirth,
|
||||
Gender: card.Gender,
|
||||
BloodType: card.BloodType,
|
||||
Province: card.Province,
|
||||
District: card.District,
|
||||
SubDistrict: card.SubDistrict,
|
||||
Hamlet: card.Hamlet,
|
||||
Village: card.Village,
|
||||
Neighbourhood: card.Neighbourhood,
|
||||
PostalCode: card.PostalCode,
|
||||
Religion: card.Religion,
|
||||
Maritalstatus: card.Maritalstatus,
|
||||
Job: card.Job,
|
||||
Citizenship: card.Citizenship,
|
||||
Validuntil: card.Validuntil,
|
||||
Cardphoto: card.Cardphoto,
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: updatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *identityCardService) mapUserToDTO(user model.User) userprofile.UserProfileResponseDTO {
|
||||
avatar := ""
|
||||
if user.Avatar != nil {
|
||||
avatar = *user.Avatar
|
||||
}
|
||||
|
||||
var roleDTO role.RoleResponseDTO
|
||||
if user.Role != nil {
|
||||
roleDTO = role.RoleResponseDTO{
|
||||
ID: user.Role.ID,
|
||||
RoleName: user.Role.RoleName,
|
||||
}
|
||||
}
|
||||
|
||||
createdAt, _ := utils.FormatDateToIndonesianFormat(user.CreatedAt)
|
||||
updatedAt, _ := utils.FormatDateToIndonesianFormat(user.UpdatedAt)
|
||||
return userprofile.UserProfileResponseDTO{
|
||||
ID: user.ID,
|
||||
Avatar: avatar,
|
||||
Name: user.Name,
|
||||
Gender: user.Gender,
|
||||
Dateofbirth: user.Dateofbirth,
|
||||
Placeofbirth: user.Placeofbirth,
|
||||
Phone: user.Phone,
|
||||
Email: user.Email,
|
||||
PhoneVerified: user.PhoneVerified,
|
||||
Role: roleDTO,
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: updatedAt,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
)
|
||||
|
||||
type RequestPinDTO struct {
|
||||
DeviceId string `json:"device_id"`
|
||||
// DeviceId string `json:"device_id"`
|
||||
Pin string `json:"userpin"`
|
||||
}
|
||||
|
||||
|
|
|
@ -15,47 +15,39 @@ func NewUserPinHandler(service UserPinService) *UserPinHandler {
|
|||
return &UserPinHandler{service}
|
||||
}
|
||||
|
||||
// userID, ok := c.Locals("user_id").(string)
|
||||
//
|
||||
// if !ok || userID == "" {
|
||||
// return utils.Unauthorized(c, "user_id is missing or invalid")
|
||||
// }
|
||||
func (h *UserPinHandler) CreateUserPinHandler(c *fiber.Ctx) error {
|
||||
// Ambil klaim pengguna yang sudah diautentikasi
|
||||
|
||||
claims, err := middleware.GetUserFromContext(c)
|
||||
if err != nil {
|
||||
return err
|
||||
return utils.Unauthorized(c, "Authentication required")
|
||||
}
|
||||
|
||||
if claims.UserID == "" || claims.DeviceID == "" {
|
||||
return utils.BadRequest(c, "Invalid user claims")
|
||||
}
|
||||
|
||||
// Parsing body request untuk PIN
|
||||
var req RequestPinDTO
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return utils.BadRequest(c, "Invalid request body")
|
||||
}
|
||||
|
||||
// Validasi request PIN
|
||||
if errs, ok := req.ValidateRequestPinDTO(); !ok {
|
||||
return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Validation error", errs)
|
||||
}
|
||||
|
||||
// Panggil service untuk membuat PIN
|
||||
err = h.service.CreateUserPin(c.Context(), claims.UserID, &req)
|
||||
pintokenresponse, err := h.service.CreateUserPin(c.Context(), claims.UserID, claims.DeviceID, &req)
|
||||
if err != nil {
|
||||
if err.Error() == "PIN already created" {
|
||||
return utils.BadRequest(c, err.Error()) // Jika PIN sudah ada, kembalikan error 400
|
||||
if err.Error() == Pinhasbeencreated {
|
||||
return utils.BadRequest(c, err.Error())
|
||||
}
|
||||
return utils.InternalServerError(c, err.Error()) // Jika terjadi error lain, internal server error
|
||||
return utils.InternalServerError(c, err.Error())
|
||||
}
|
||||
|
||||
// Mengembalikan response sukses jika berhasil
|
||||
return utils.Success(c, "PIN created successfully")
|
||||
return utils.SuccessWithData(c, "PIN created successfully", pintokenresponse)
|
||||
}
|
||||
|
||||
func (h *UserPinHandler) VerifyPinHandler(c *fiber.Ctx) error {
|
||||
// userID, ok := c.Locals("user_id").(string)
|
||||
// if !ok || userID == "" {
|
||||
// return utils.Unauthorized(c, "user_id is missing or invalid")
|
||||
// }
|
||||
|
||||
claims, err := middleware.GetUserFromContext(c)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -66,12 +58,10 @@ func (h *UserPinHandler) VerifyPinHandler(c *fiber.Ctx) error {
|
|||
return utils.BadRequest(c, "Invalid request body")
|
||||
}
|
||||
|
||||
token, err := h.service.VerifyUserPin(c.Context(), claims.UserID, &req)
|
||||
token, err := h.service.VerifyUserPin(c.Context(), claims.UserID, claims.DeviceID, &req)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, err.Error())
|
||||
}
|
||||
|
||||
return utils.SuccessWithData(c, "PIN verified successfully", fiber.Map{
|
||||
"token": token,
|
||||
})
|
||||
return utils.SuccessWithData(c, "PIN verified successfully", token)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package userpin
|
|||
import (
|
||||
"rijig/config"
|
||||
"rijig/internal/authentication"
|
||||
"rijig/internal/userprofile"
|
||||
"rijig/middleware"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
@ -11,8 +12,9 @@ import (
|
|||
func UsersPinRoute(api fiber.Router) {
|
||||
userPinRepo := NewUserPinRepository(config.DB)
|
||||
authRepo := authentication.NewAuthenticationRepository(config.DB)
|
||||
userprofileRepo := userprofile.NewUserProfileRepository(config.DB)
|
||||
|
||||
userPinService := NewUserPinService(userPinRepo, authRepo)
|
||||
userPinService := NewUserPinService(userPinRepo, authRepo, userprofileRepo)
|
||||
|
||||
userPinHandler := NewUserPinHandler(userPinService)
|
||||
|
||||
|
|
|
@ -2,45 +2,51 @@ package userpin
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"rijig/internal/authentication"
|
||||
"rijig/internal/userprofile"
|
||||
"rijig/model"
|
||||
"rijig/utils"
|
||||
"strings"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type UserPinService interface {
|
||||
CreateUserPin(ctx context.Context, userID string, dto *RequestPinDTO) error
|
||||
VerifyUserPin(ctx context.Context, userID string, pin *RequestPinDTO) (*utils.TokenResponse, error)
|
||||
CreateUserPin(ctx context.Context, userID, deviceId string, dto *RequestPinDTO) (*authentication.AuthResponse, error)
|
||||
VerifyUserPin(ctx context.Context, userID, deviceID string, pin *RequestPinDTO) (*utils.TokenResponse, error)
|
||||
}
|
||||
|
||||
type userPinService struct {
|
||||
UserPinRepo UserPinRepository
|
||||
authRepo authentication.AuthenticationRepository
|
||||
userProfileRepo userprofile.UserProfileRepository
|
||||
}
|
||||
|
||||
func NewUserPinService(UserPinRepo UserPinRepository,
|
||||
authRepo authentication.AuthenticationRepository) UserPinService {
|
||||
return &userPinService{UserPinRepo, authRepo}
|
||||
authRepo authentication.AuthenticationRepository,
|
||||
userProfileRepo userprofile.UserProfileRepository) UserPinService {
|
||||
return &userPinService{UserPinRepo, authRepo, userProfileRepo}
|
||||
}
|
||||
|
||||
func (s *userPinService) CreateUserPin(ctx context.Context, userID string, dto *RequestPinDTO) error {
|
||||
var (
|
||||
Pinhasbeencreated = "PIN already created"
|
||||
)
|
||||
|
||||
if errs, ok := dto.ValidateRequestPinDTO(); !ok {
|
||||
return fmt.Errorf("validation error: %v", errs)
|
||||
}
|
||||
func (s *userPinService) CreateUserPin(ctx context.Context, userID, deviceId string, dto *RequestPinDTO) (*authentication.AuthResponse, error) {
|
||||
|
||||
existingPin, err := s.UserPinRepo.FindByUserID(ctx, userID)
|
||||
_, err := s.UserPinRepo.FindByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check existing PIN: %w", err)
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("user not found")
|
||||
}
|
||||
if existingPin != nil {
|
||||
return fmt.Errorf("PIN already created")
|
||||
return nil, fmt.Errorf("%v", Pinhasbeencreated)
|
||||
}
|
||||
|
||||
hashed, err := utils.HashingPlainText(dto.Pin)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to hash PIN: %w", err)
|
||||
return nil, fmt.Errorf("failed to hash PIN: %w", err)
|
||||
}
|
||||
|
||||
userPin := &model.UserPin{
|
||||
|
@ -49,35 +55,63 @@ func (s *userPinService) CreateUserPin(ctx context.Context, userID string, dto *
|
|||
}
|
||||
|
||||
if err := s.UserPinRepo.Create(ctx, userPin); err != nil {
|
||||
return fmt.Errorf("failed to create PIN: %w", err)
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("user not found")
|
||||
}
|
||||
return nil, fmt.Errorf("failed to create pin: %w", err)
|
||||
}
|
||||
|
||||
user, err := s.authRepo.FindUserByID(ctx, userID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("user not found")
|
||||
}
|
||||
|
||||
roleName := strings.ToLower(user.Role.RoleName)
|
||||
|
||||
progress := authentication.IsRegistrationComplete(roleName, int(user.RegistrationProgress))
|
||||
// progress := utils.GetNextRegistrationStep(roleName, int(user.RegistrationProgress))
|
||||
// progress := utils.GetNextRegistrationStep(roleName, user.RegistrationProgress)
|
||||
// progress := utils.GetNextRegistrationStep(roleName, user.RegistrationProgress)
|
||||
|
||||
if !progress {
|
||||
err = s.authRepo.PatchUser(ctx, userID, map[string]interface{}{
|
||||
"registration_progress": int(user.RegistrationProgress) + 1,
|
||||
updates := map[string]interface{}{
|
||||
"registration_progress": utils.ProgressComplete,
|
||||
"registration_status": utils.RegStatusComplete,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update user progress: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
if err = s.authRepo.PatchUser(ctx, userID, updates); err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("user not found")
|
||||
}
|
||||
return nil, fmt.Errorf("failed to update user profile: %w", err)
|
||||
}
|
||||
|
||||
updated, err := s.userProfileRepo.GetByID(ctx, userID)
|
||||
if err != nil {
|
||||
if errors.Is(err, userprofile.ErrUserNotFound) {
|
||||
return nil, fmt.Errorf("user not found")
|
||||
}
|
||||
return nil, fmt.Errorf("failed to get updated user: %w", err)
|
||||
}
|
||||
|
||||
tokenResponse, err := utils.GenerateTokenPair(
|
||||
updated.ID,
|
||||
updated.Role.RoleName,
|
||||
deviceId,
|
||||
updated.RegistrationStatus,
|
||||
int(updated.RegistrationProgress),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("gagal generate token: %v", err)
|
||||
}
|
||||
|
||||
nextStep := utils.GetNextRegistrationStep(
|
||||
updated.Role.RoleName,
|
||||
int(updated.RegistrationProgress),
|
||||
updated.RegistrationStatus,
|
||||
)
|
||||
|
||||
return &authentication.AuthResponse{
|
||||
Message: "Isi data diri berhasil",
|
||||
AccessToken: tokenResponse.AccessToken,
|
||||
RefreshToken: tokenResponse.RefreshToken,
|
||||
TokenType: string(tokenResponse.TokenType),
|
||||
ExpiresIn: tokenResponse.ExpiresIn,
|
||||
RegistrationStatus: updated.RegistrationStatus,
|
||||
NextStep: nextStep,
|
||||
SessionID: tokenResponse.SessionID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *userPinService) VerifyUserPin(ctx context.Context, userID string, pin *RequestPinDTO) (*utils.TokenResponse, error) {
|
||||
func (s *userPinService) VerifyUserPin(ctx context.Context, userID, deviceID string, pin *RequestPinDTO) (*utils.TokenResponse, error) {
|
||||
user, err := s.authRepo.FindUserByID(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("user not found")
|
||||
|
@ -93,5 +127,5 @@ func (s *userPinService) VerifyUserPin(ctx context.Context, userID string, pin *
|
|||
}
|
||||
|
||||
roleName := strings.ToLower(user.Role.RoleName)
|
||||
return utils.GenerateTokenPair(user.ID, roleName, pin.DeviceId, user.RegistrationStatus, int(user.RegistrationProgress))
|
||||
return utils.GenerateTokenPair(user.ID, roleName, deviceID, user.RegistrationStatus, int(user.RegistrationProgress))
|
||||
}
|
||||
|
|
|
@ -1 +1,76 @@
|
|||
package userprofile
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"rijig/middleware"
|
||||
"rijig/utils"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type UserProfileHandler struct {
|
||||
service UserProfileService
|
||||
}
|
||||
|
||||
func NewUserProfileHandler(service UserProfileService) *UserProfileHandler {
|
||||
return &UserProfileHandler{
|
||||
service: service,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *UserProfileHandler) GetUserProfile(c *fiber.Ctx) error {
|
||||
|
||||
claims, err := middleware.GetUserFromContext(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
userProfile, err := h.service.GetUserProfile(ctx, claims.UserID)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), ErrUserNotFound.Error()) {
|
||||
return utils.NotFound(c, "User profile not found")
|
||||
}
|
||||
|
||||
log.Printf("Error getting user profile: %v", err)
|
||||
return utils.InternalServerError(c, "Failed to retrieve user profile")
|
||||
}
|
||||
|
||||
return utils.SuccessWithData(c, "User profile retrieved successfully", userProfile)
|
||||
}
|
||||
|
||||
func (h *UserProfileHandler) UpdateUserProfile(c *fiber.Ctx) error {
|
||||
claims, err := middleware.GetUserFromContext(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var req RequestUserProfileDTO
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return utils.BadRequest(c, "Invalid request format")
|
||||
}
|
||||
|
||||
if validationErrors, isValid := req.ValidateRequestUserProfileDTO(); !isValid {
|
||||
return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Validation failed", validationErrors)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
|
||||
updatedProfile, err := h.service.UpdateRegistUserProfile(ctx, claims.UserID, claims.DeviceID, &req)
|
||||
if err != nil {
|
||||
|
||||
if strings.Contains(err.Error(), "user not found") {
|
||||
return utils.NotFound(c, "User not found")
|
||||
}
|
||||
|
||||
log.Printf("Error updating user profile: %v", err)
|
||||
return utils.InternalServerError(c, "Failed to update user profile")
|
||||
}
|
||||
|
||||
return utils.SuccessWithData(c, "User profile updated successfully", updatedProfile)
|
||||
}
|
||||
|
|
|
@ -2,34 +2,106 @@ package userprofile
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"rijig/model"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type AuthenticationRepository interface {
|
||||
UpdateUser(ctx context.Context, user *model.User) error
|
||||
PatchUser(ctx context.Context, userID string, updates map[string]interface{}) error
|
||||
type UserProfileRepository interface {
|
||||
GetByID(ctx context.Context, userID string) (*model.User, error)
|
||||
GetByRoleName(ctx context.Context, roleName string) ([]*model.User, error)
|
||||
// GetIdentityCardsByUserRegStatus(ctx context.Context, userRegStatus string) ([]model.IdentityCard, error)
|
||||
// GetCompanyProfileByUserRegStatus(ctx context.Context, userRegStatus string) ([]model.IdentityCard, error)
|
||||
Update(ctx context.Context, userID string, user *model.User) error
|
||||
}
|
||||
|
||||
type authenticationRepository struct {
|
||||
type userProfileRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewAuthenticationRepository(db *gorm.DB) AuthenticationRepository {
|
||||
return &authenticationRepository{db}
|
||||
func NewUserProfileRepository(db *gorm.DB) UserProfileRepository {
|
||||
return &userProfileRepository{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *authenticationRepository) UpdateUser(ctx context.Context, user *model.User) error {
|
||||
return r.db.WithContext(ctx).
|
||||
Model(&model.User{}).
|
||||
Where("id = ?", user.ID).
|
||||
Updates(user).Error
|
||||
func (r *userProfileRepository) GetByID(ctx context.Context, userID string) (*model.User, error) {
|
||||
var user model.User
|
||||
|
||||
err := r.db.WithContext(ctx).
|
||||
Preload("Role").
|
||||
Where("id = ?", userID).
|
||||
First(&user).Error
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrUserNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func (r *authenticationRepository) PatchUser(ctx context.Context, userID string, updates map[string]interface{}) error {
|
||||
return r.db.WithContext(ctx).
|
||||
func (r *userProfileRepository) GetByRoleName(ctx context.Context, roleName string) ([]*model.User, error) {
|
||||
var users []*model.User
|
||||
|
||||
err := r.db.WithContext(ctx).
|
||||
Preload("Role").
|
||||
Joins("JOIN roles ON users.role_id = roles.id").
|
||||
Where("roles.role_name = ?", roleName).
|
||||
Find(&users).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
/* func (r *userProfileRepository) GetIdentityCardsByUserRegStatus(ctx context.Context, userRegStatus string) ([]model.IdentityCard, error) {
|
||||
var identityCards []model.IdentityCard
|
||||
|
||||
if err := r.db.WithContext(ctx).
|
||||
Joins("JOIN users ON identity_cards.user_id = users.id").
|
||||
Where("users.registration_status = ?", userRegStatus).
|
||||
Preload("User").
|
||||
Find(&identityCards).Error; err != nil {
|
||||
log.Printf("Error fetching identity cards by user registration status: %v", err)
|
||||
return nil, fmt.Errorf("error fetching identity cards by user registration status: %w", err)
|
||||
}
|
||||
|
||||
return identityCards, nil
|
||||
}
|
||||
|
||||
func (r *userProfileRepository) GetCompanyProfileByUserRegStatus(ctx context.Context, userRegStatus string) ([]model.IdentityCard, error) {
|
||||
var identityCards []model.IdentityCard
|
||||
|
||||
if err := r.db.WithContext(ctx).
|
||||
Joins("JOIN users ON company_profiles.user_id = users.id").
|
||||
Where("users.registration_status = ?", userRegStatus).
|
||||
Preload("User").
|
||||
Find(&identityCards).Error; err != nil {
|
||||
log.Printf("Error fetching identity cards by user registration status: %v", err)
|
||||
return nil, fmt.Errorf("error fetching identity cards by user registration status: %w", err)
|
||||
}
|
||||
return identityCards, nil
|
||||
} */
|
||||
|
||||
func (r *userProfileRepository) Update(ctx context.Context, userID string, user *model.User) error {
|
||||
result := r.db.WithContext(ctx).
|
||||
Model(&model.User{}).
|
||||
Where("id = ?", userID).
|
||||
Updates(updates).Error
|
||||
Updates(user)
|
||||
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
return ErrUserNotFound
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1 +1,20 @@
|
|||
package userprofile
|
||||
|
||||
import (
|
||||
"rijig/config"
|
||||
"rijig/middleware"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func UserProfileRouter(api fiber.Router) {
|
||||
userProfileRepo := NewUserProfileRepository(config.DB)
|
||||
userProfileService := NewUserProfileService(userProfileRepo)
|
||||
userProfileHandler := NewUserProfileHandler(userProfileService)
|
||||
|
||||
userRoute := api.Group("/userprofile")
|
||||
userRoute.Use(middleware.AuthMiddleware())
|
||||
|
||||
userRoute.Get("/", userProfileHandler.GetUserProfile)
|
||||
userRoute.Put("/update", userProfileHandler.UpdateUserProfile)
|
||||
}
|
|
@ -1 +1,160 @@
|
|||
package userprofile
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"rijig/internal/authentication"
|
||||
"rijig/internal/role"
|
||||
"rijig/model"
|
||||
"rijig/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUserNotFound = errors.New("user tidak ditemukan")
|
||||
)
|
||||
|
||||
type UserProfileService interface {
|
||||
GetUserProfile(ctx context.Context, userID string) (*UserProfileResponseDTO, error)
|
||||
UpdateRegistUserProfile(ctx context.Context, userID, deviceId string, req *RequestUserProfileDTO) (*authentication.AuthResponse, error)
|
||||
}
|
||||
|
||||
type userProfileService struct {
|
||||
repo UserProfileRepository
|
||||
}
|
||||
|
||||
func NewUserProfileService(repo UserProfileRepository) UserProfileService {
|
||||
return &userProfileService{
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *userProfileService) GetUserProfile(ctx context.Context, userID string) (*UserProfileResponseDTO, error) {
|
||||
user, err := s.repo.GetByID(ctx, userID)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrUserNotFound) {
|
||||
return nil, fmt.Errorf("user not found")
|
||||
}
|
||||
return nil, fmt.Errorf("failed to get user profile: %w", err)
|
||||
}
|
||||
|
||||
return s.mapToResponseDTO(user), nil
|
||||
}
|
||||
|
||||
func (s *userProfileService) UpdateRegistUserProfile(ctx context.Context, userID, deviceId string, req *RequestUserProfileDTO) (*authentication.AuthResponse, error) {
|
||||
|
||||
_, err := s.repo.GetByID(ctx, userID)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrUserNotFound) {
|
||||
return nil, fmt.Errorf("user not found")
|
||||
}
|
||||
return nil, fmt.Errorf("failed to get user: %w", err)
|
||||
}
|
||||
|
||||
updateUser := &model.User{
|
||||
Name: req.Name,
|
||||
Gender: req.Gender,
|
||||
Dateofbirth: req.Dateofbirth,
|
||||
Placeofbirth: req.Placeofbirth,
|
||||
Phone: req.Phone,
|
||||
RegistrationProgress: utils.ProgressDataSubmitted,
|
||||
}
|
||||
|
||||
if err := s.repo.Update(ctx, userID, updateUser); err != nil {
|
||||
if errors.Is(err, ErrUserNotFound) {
|
||||
return nil, fmt.Errorf("user not found")
|
||||
}
|
||||
return nil, fmt.Errorf("failed to update user profile: %w", err)
|
||||
}
|
||||
|
||||
updatedUser, err := s.repo.GetByID(ctx, userID)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrUserNotFound) {
|
||||
return nil, fmt.Errorf("user not found")
|
||||
}
|
||||
return nil, fmt.Errorf("failed to get updated user: %w", err)
|
||||
}
|
||||
|
||||
tokenResponse, err := utils.GenerateTokenPair(
|
||||
updatedUser.ID,
|
||||
updatedUser.Role.RoleName,
|
||||
// req.DeviceID,
|
||||
deviceId,
|
||||
updatedUser.RegistrationStatus,
|
||||
int(updatedUser.RegistrationProgress),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("gagal generate token: %v", err)
|
||||
}
|
||||
|
||||
nextStep := utils.GetNextRegistrationStep(
|
||||
updatedUser.Role.RoleName,
|
||||
int(updatedUser.RegistrationProgress),
|
||||
updateUser.RegistrationStatus,
|
||||
)
|
||||
|
||||
return &authentication.AuthResponse{
|
||||
Message: "Isi data diri berhasil",
|
||||
AccessToken: tokenResponse.AccessToken,
|
||||
RefreshToken: tokenResponse.RefreshToken,
|
||||
TokenType: string(tokenResponse.TokenType),
|
||||
ExpiresIn: tokenResponse.ExpiresIn,
|
||||
RegistrationStatus: updateUser.RegistrationStatus,
|
||||
NextStep: nextStep,
|
||||
SessionID: tokenResponse.SessionID,
|
||||
}, nil
|
||||
|
||||
// return s.mapToResponseDTO(updatedUser), nil
|
||||
}
|
||||
|
||||
func (s *userProfileService) mapToResponseDTO(user *model.User) *UserProfileResponseDTO {
|
||||
|
||||
createdAt, err := utils.FormatDateToIndonesianFormat(user.CreatedAt)
|
||||
if err != nil {
|
||||
createdAt = user.CreatedAt.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
updatedAt, err := utils.FormatDateToIndonesianFormat(user.UpdatedAt)
|
||||
if err != nil {
|
||||
updatedAt = user.UpdatedAt.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
response := &UserProfileResponseDTO{
|
||||
ID: user.ID,
|
||||
Name: user.Name,
|
||||
Gender: user.Gender,
|
||||
Dateofbirth: user.Dateofbirth,
|
||||
Placeofbirth: user.Placeofbirth,
|
||||
Phone: user.Phone,
|
||||
PhoneVerified: user.PhoneVerified,
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: updatedAt,
|
||||
}
|
||||
|
||||
if user.Avatar != nil {
|
||||
response.Avatar = *user.Avatar
|
||||
}
|
||||
|
||||
if user.Role != nil {
|
||||
roleCreatedAt, err := utils.FormatDateToIndonesianFormat(user.Role.CreatedAt)
|
||||
if err != nil {
|
||||
roleCreatedAt = user.Role.CreatedAt.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
roleUpdatedAt, err := utils.FormatDateToIndonesianFormat(user.Role.UpdatedAt)
|
||||
if err != nil {
|
||||
roleUpdatedAt = user.Role.UpdatedAt.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
response.Role = role.RoleResponseDTO{
|
||||
ID: user.Role.ID,
|
||||
RoleName: user.Role.RoleName,
|
||||
CreatedAt: roleCreatedAt,
|
||||
UpdatedAt: roleUpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
|
|
@ -1 +1,272 @@
|
|||
package wilayahindo
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"rijig/utils"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type WilayahIndonesiaHandler struct {
|
||||
WilayahService WilayahIndonesiaService
|
||||
}
|
||||
|
||||
func NewWilayahIndonesiaHandler(wilayahService WilayahIndonesiaService) *WilayahIndonesiaHandler {
|
||||
return &WilayahIndonesiaHandler{
|
||||
WilayahService: wilayahService,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *WilayahIndonesiaHandler) ImportDataFromCSV(c *fiber.Ctx) error {
|
||||
ctx := c.Context()
|
||||
|
||||
if err := h.WilayahService.ImportDataFromCSV(ctx); err != nil {
|
||||
return utils.InternalServerError(c, "Failed to import data from CSV: "+err.Error())
|
||||
}
|
||||
|
||||
return utils.Success(c, "Data imported successfully from CSV")
|
||||
}
|
||||
|
||||
func (h *WilayahIndonesiaHandler) GetAllProvinces(c *fiber.Ctx) error {
|
||||
ctx := c.Context()
|
||||
|
||||
page, limit, err := h.parsePaginationParams(c)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, err.Error())
|
||||
}
|
||||
|
||||
provinces, total, err := h.WilayahService.GetAllProvinces(ctx, page, limit)
|
||||
if err != nil {
|
||||
return utils.InternalServerError(c, "Failed to fetch provinces: "+err.Error())
|
||||
}
|
||||
|
||||
response := map[string]interface{}{
|
||||
"provinces": provinces,
|
||||
"total": total,
|
||||
}
|
||||
|
||||
return utils.SuccessWithPagination(c, "Provinces retrieved successfully", response, page, limit)
|
||||
}
|
||||
|
||||
func (h *WilayahIndonesiaHandler) GetProvinceByID(c *fiber.Ctx) error {
|
||||
ctx := c.Context()
|
||||
|
||||
id := c.Params("id")
|
||||
if id == "" {
|
||||
return utils.BadRequest(c, "Province ID is required")
|
||||
}
|
||||
|
||||
page, limit, err := h.parsePaginationParams(c)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, err.Error())
|
||||
}
|
||||
|
||||
province, totalRegencies, err := h.WilayahService.GetProvinceByID(ctx, id, page, limit)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
return utils.NotFound(c, "Province not found")
|
||||
}
|
||||
return utils.InternalServerError(c, "Failed to fetch province: "+err.Error())
|
||||
}
|
||||
|
||||
response := map[string]interface{}{
|
||||
"province": province,
|
||||
"total_regencies": totalRegencies,
|
||||
}
|
||||
|
||||
return utils.SuccessWithPagination(c, "Province retrieved successfully", response, page, limit)
|
||||
}
|
||||
|
||||
func (h *WilayahIndonesiaHandler) GetAllRegencies(c *fiber.Ctx) error {
|
||||
ctx := c.Context()
|
||||
|
||||
page, limit, err := h.parsePaginationParams(c)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, err.Error())
|
||||
}
|
||||
|
||||
regencies, total, err := h.WilayahService.GetAllRegencies(ctx, page, limit)
|
||||
if err != nil {
|
||||
return utils.InternalServerError(c, "Failed to fetch regencies: "+err.Error())
|
||||
}
|
||||
|
||||
response := map[string]interface{}{
|
||||
"regencies": regencies,
|
||||
"total": total,
|
||||
}
|
||||
|
||||
return utils.SuccessWithPagination(c, "Regencies retrieved successfully", response, page, limit)
|
||||
}
|
||||
|
||||
func (h *WilayahIndonesiaHandler) GetRegencyByID(c *fiber.Ctx) error {
|
||||
ctx := c.Context()
|
||||
|
||||
id := c.Params("id")
|
||||
if id == "" {
|
||||
return utils.BadRequest(c, "Regency ID is required")
|
||||
}
|
||||
|
||||
page, limit, err := h.parsePaginationParams(c)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, err.Error())
|
||||
}
|
||||
|
||||
regency, totalDistricts, err := h.WilayahService.GetRegencyByID(ctx, id, page, limit)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
return utils.NotFound(c, "Regency not found")
|
||||
}
|
||||
return utils.InternalServerError(c, "Failed to fetch regency: "+err.Error())
|
||||
}
|
||||
|
||||
response := map[string]interface{}{
|
||||
"regency": regency,
|
||||
"total_districts": totalDistricts,
|
||||
}
|
||||
|
||||
return utils.SuccessWithPagination(c, "Regency retrieved successfully", response, page, limit)
|
||||
}
|
||||
|
||||
func (h *WilayahIndonesiaHandler) GetAllDistricts(c *fiber.Ctx) error {
|
||||
ctx := c.Context()
|
||||
|
||||
page, limit, err := h.parsePaginationParams(c)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, err.Error())
|
||||
}
|
||||
|
||||
districts, total, err := h.WilayahService.GetAllDistricts(ctx, page, limit)
|
||||
if err != nil {
|
||||
return utils.InternalServerError(c, "Failed to fetch districts: "+err.Error())
|
||||
}
|
||||
|
||||
response := map[string]interface{}{
|
||||
"districts": districts,
|
||||
"total": total,
|
||||
}
|
||||
|
||||
return utils.SuccessWithPagination(c, "Districts retrieved successfully", response, page, limit)
|
||||
}
|
||||
|
||||
func (h *WilayahIndonesiaHandler) GetDistrictByID(c *fiber.Ctx) error {
|
||||
ctx := c.Context()
|
||||
|
||||
id := c.Params("id")
|
||||
if id == "" {
|
||||
return utils.BadRequest(c, "District ID is required")
|
||||
}
|
||||
|
||||
page, limit, err := h.parsePaginationParams(c)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, err.Error())
|
||||
}
|
||||
|
||||
district, totalVillages, err := h.WilayahService.GetDistrictByID(ctx, id, page, limit)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
return utils.NotFound(c, "District not found")
|
||||
}
|
||||
return utils.InternalServerError(c, "Failed to fetch district: "+err.Error())
|
||||
}
|
||||
|
||||
response := map[string]interface{}{
|
||||
"district": district,
|
||||
"total_villages": totalVillages,
|
||||
}
|
||||
|
||||
return utils.SuccessWithPagination(c, "District retrieved successfully", response, page, limit)
|
||||
}
|
||||
|
||||
func (h *WilayahIndonesiaHandler) GetAllVillages(c *fiber.Ctx) error {
|
||||
ctx := c.Context()
|
||||
|
||||
page, limit, err := h.parsePaginationParams(c)
|
||||
if err != nil {
|
||||
return utils.BadRequest(c, err.Error())
|
||||
}
|
||||
|
||||
villages, total, err := h.WilayahService.GetAllVillages(ctx, page, limit)
|
||||
if err != nil {
|
||||
return utils.InternalServerError(c, "Failed to fetch villages: "+err.Error())
|
||||
}
|
||||
|
||||
response := map[string]interface{}{
|
||||
"villages": villages,
|
||||
"total": total,
|
||||
}
|
||||
|
||||
return utils.SuccessWithPagination(c, "Villages retrieved successfully", response, page, limit)
|
||||
}
|
||||
|
||||
func (h *WilayahIndonesiaHandler) GetVillageByID(c *fiber.Ctx) error {
|
||||
ctx := c.Context()
|
||||
|
||||
id := c.Params("id")
|
||||
if id == "" {
|
||||
return utils.BadRequest(c, "Village ID is required")
|
||||
}
|
||||
|
||||
village, err := h.WilayahService.GetVillageByID(ctx, id)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
return utils.NotFound(c, "Village not found")
|
||||
}
|
||||
return utils.InternalServerError(c, "Failed to fetch village: "+err.Error())
|
||||
}
|
||||
|
||||
return utils.SuccessWithData(c, "Village retrieved successfully", village)
|
||||
}
|
||||
|
||||
func (h *WilayahIndonesiaHandler) parsePaginationParams(c *fiber.Ctx) (int, int, error) {
|
||||
|
||||
page := 1
|
||||
limit := 10
|
||||
|
||||
if pageStr := c.Query("page"); pageStr != "" {
|
||||
parsedPage, err := strconv.Atoi(pageStr)
|
||||
if err != nil {
|
||||
return 0, 0, fiber.NewError(fiber.StatusBadRequest, "Invalid page parameter")
|
||||
}
|
||||
if parsedPage < 1 {
|
||||
return 0, 0, fiber.NewError(fiber.StatusBadRequest, "Page must be greater than 0")
|
||||
}
|
||||
page = parsedPage
|
||||
}
|
||||
|
||||
if limitStr := c.Query("limit"); limitStr != "" {
|
||||
parsedLimit, err := strconv.Atoi(limitStr)
|
||||
if err != nil {
|
||||
return 0, 0, fiber.NewError(fiber.StatusBadRequest, "Invalid limit parameter")
|
||||
}
|
||||
if parsedLimit < 1 {
|
||||
return 0, 0, fiber.NewError(fiber.StatusBadRequest, "Limit must be greater than 0")
|
||||
}
|
||||
if parsedLimit > 100 {
|
||||
return 0, 0, fiber.NewError(fiber.StatusBadRequest, "Limit cannot exceed 100")
|
||||
}
|
||||
limit = parsedLimit
|
||||
}
|
||||
|
||||
return page, limit, nil
|
||||
}
|
||||
|
||||
func (h *WilayahIndonesiaHandler) SetupRoutes(app *fiber.App) {
|
||||
|
||||
api := app.Group("/api/v1/wilayah")
|
||||
|
||||
api.Post("/import", h.ImportDataFromCSV)
|
||||
|
||||
api.Get("/provinces", h.GetAllProvinces)
|
||||
api.Get("/provinces/:id", h.GetProvinceByID)
|
||||
|
||||
api.Get("/regencies", h.GetAllRegencies)
|
||||
api.Get("/regencies/:id", h.GetRegencyByID)
|
||||
|
||||
api.Get("/districts", h.GetAllDistricts)
|
||||
api.Get("/districts/:id", h.GetDistrictByID)
|
||||
|
||||
api.Get("/villages", h.GetAllVillages)
|
||||
api.Get("/villages/:id", h.GetVillageByID)
|
||||
}
|
||||
|
|
|
@ -1 +1,32 @@
|
|||
package wilayahindo
|
||||
|
||||
import (
|
||||
"rijig/config"
|
||||
"rijig/middleware"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func WilayahRouter(api fiber.Router) {
|
||||
|
||||
wilayahRepo := NewWilayahIndonesiaRepository(config.DB)
|
||||
wilayahService := NewWilayahIndonesiaService(wilayahRepo)
|
||||
wilayahHandler := NewWilayahIndonesiaHandler(wilayahService)
|
||||
|
||||
api.Post("/import/data-wilayah-indonesia", middleware.RequireAdminRole(), wilayahHandler.ImportDataFromCSV)
|
||||
|
||||
wilayahAPI := api.Group("/wilayah-indonesia")
|
||||
|
||||
wilayahAPI.Get("/provinces", wilayahHandler.GetAllProvinces)
|
||||
wilayahAPI.Get("/provinces/:provinceid", wilayahHandler.GetProvinceByID)
|
||||
|
||||
wilayahAPI.Get("/regencies", wilayahHandler.GetAllRegencies)
|
||||
wilayahAPI.Get("/regencies/:regencyid", wilayahHandler.GetRegencyByID)
|
||||
|
||||
wilayahAPI.Get("/districts", wilayahHandler.GetAllDistricts)
|
||||
wilayahAPI.Get("/districts/:districtid", wilayahHandler.GetDistrictByID)
|
||||
|
||||
wilayahAPI.Get("/villages", wilayahHandler.GetAllVillages)
|
||||
wilayahAPI.Get("/villages/:villageid", wilayahHandler.GetVillageByID)
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"rijig/dto"
|
||||
"rijig/model"
|
||||
"rijig/utils"
|
||||
)
|
||||
|
@ -13,17 +12,17 @@ import (
|
|||
type WilayahIndonesiaService interface {
|
||||
ImportDataFromCSV(ctx context.Context) error
|
||||
|
||||
GetAllProvinces(ctx context.Context, page, limit int) ([]dto.ProvinceResponseDTO, int, error)
|
||||
GetProvinceByID(ctx context.Context, id string, page, limit int) (*dto.ProvinceResponseDTO, int, error)
|
||||
GetAllProvinces(ctx context.Context, page, limit int) ([]ProvinceResponseDTO, int, error)
|
||||
GetProvinceByID(ctx context.Context, id string, page, limit int) (*ProvinceResponseDTO, int, error)
|
||||
|
||||
GetAllRegencies(ctx context.Context, page, limit int) ([]dto.RegencyResponseDTO, int, error)
|
||||
GetRegencyByID(ctx context.Context, id string, page, limit int) (*dto.RegencyResponseDTO, int, error)
|
||||
GetAllRegencies(ctx context.Context, page, limit int) ([]RegencyResponseDTO, int, error)
|
||||
GetRegencyByID(ctx context.Context, id string, page, limit int) (*RegencyResponseDTO, int, error)
|
||||
|
||||
GetAllDistricts(ctx context.Context, page, limit int) ([]dto.DistrictResponseDTO, int, error)
|
||||
GetDistrictByID(ctx context.Context, id string, page, limit int) (*dto.DistrictResponseDTO, int, error)
|
||||
GetAllDistricts(ctx context.Context, page, limit int) ([]DistrictResponseDTO, int, error)
|
||||
GetDistrictByID(ctx context.Context, id string, page, limit int) (*DistrictResponseDTO, int, error)
|
||||
|
||||
GetAllVillages(ctx context.Context, page, limit int) ([]dto.VillageResponseDTO, int, error)
|
||||
GetVillageByID(ctx context.Context, id string) (*dto.VillageResponseDTO, error)
|
||||
GetAllVillages(ctx context.Context, page, limit int) ([]VillageResponseDTO, int, error)
|
||||
GetVillageByID(ctx context.Context, id string) (*VillageResponseDTO, error)
|
||||
}
|
||||
|
||||
type wilayahIndonesiaService struct {
|
||||
|
@ -122,11 +121,11 @@ func (s *wilayahIndonesiaService) ImportDataFromCSV(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *wilayahIndonesiaService) GetAllProvinces(ctx context.Context, page, limit int) ([]dto.ProvinceResponseDTO, int, error) {
|
||||
func (s *wilayahIndonesiaService) GetAllProvinces(ctx context.Context, page, limit int) ([]ProvinceResponseDTO, int, error) {
|
||||
cacheKey := fmt.Sprintf("provinces_page:%d_limit:%d", page, limit)
|
||||
|
||||
var cachedResponse struct {
|
||||
Data []dto.ProvinceResponseDTO `json:"data"`
|
||||
Data []ProvinceResponseDTO `json:"data"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
|
@ -139,16 +138,16 @@ func (s *wilayahIndonesiaService) GetAllProvinces(ctx context.Context, page, lim
|
|||
return nil, 0, fmt.Errorf("failed to fetch provinces: %w", err)
|
||||
}
|
||||
|
||||
provinceDTOs := make([]dto.ProvinceResponseDTO, len(provinces))
|
||||
provinceDTOs := make([]ProvinceResponseDTO, len(provinces))
|
||||
for i, province := range provinces {
|
||||
provinceDTOs[i] = dto.ProvinceResponseDTO{
|
||||
provinceDTOs[i] = ProvinceResponseDTO{
|
||||
ID: province.ID,
|
||||
Name: province.Name,
|
||||
}
|
||||
}
|
||||
|
||||
cacheData := struct {
|
||||
Data []dto.ProvinceResponseDTO `json:"data"`
|
||||
Data []ProvinceResponseDTO `json:"data"`
|
||||
Total int `json:"total"`
|
||||
}{
|
||||
Data: provinceDTOs,
|
||||
|
@ -162,11 +161,11 @@ func (s *wilayahIndonesiaService) GetAllProvinces(ctx context.Context, page, lim
|
|||
return provinceDTOs, total, nil
|
||||
}
|
||||
|
||||
func (s *wilayahIndonesiaService) GetProvinceByID(ctx context.Context, id string, page, limit int) (*dto.ProvinceResponseDTO, int, error) {
|
||||
func (s *wilayahIndonesiaService) GetProvinceByID(ctx context.Context, id string, page, limit int) (*ProvinceResponseDTO, int, error) {
|
||||
cacheKey := fmt.Sprintf("province:%s_page:%d_limit:%d", id, page, limit)
|
||||
|
||||
var cachedResponse struct {
|
||||
Data dto.ProvinceResponseDTO `json:"data"`
|
||||
Data ProvinceResponseDTO `json:"data"`
|
||||
TotalRegencies int `json:"total_regencies"`
|
||||
}
|
||||
|
||||
|
@ -179,14 +178,14 @@ func (s *wilayahIndonesiaService) GetProvinceByID(ctx context.Context, id string
|
|||
return nil, 0, err
|
||||
}
|
||||
|
||||
provinceDTO := dto.ProvinceResponseDTO{
|
||||
provinceDTO := ProvinceResponseDTO{
|
||||
ID: province.ID,
|
||||
Name: province.Name,
|
||||
}
|
||||
|
||||
regencyDTOs := make([]dto.RegencyResponseDTO, len(province.Regencies))
|
||||
regencyDTOs := make([]RegencyResponseDTO, len(province.Regencies))
|
||||
for i, regency := range province.Regencies {
|
||||
regencyDTOs[i] = dto.RegencyResponseDTO{
|
||||
regencyDTOs[i] = RegencyResponseDTO{
|
||||
ID: regency.ID,
|
||||
ProvinceID: regency.ProvinceID,
|
||||
Name: regency.Name,
|
||||
|
@ -195,7 +194,7 @@ func (s *wilayahIndonesiaService) GetProvinceByID(ctx context.Context, id string
|
|||
provinceDTO.Regencies = regencyDTOs
|
||||
|
||||
cacheData := struct {
|
||||
Data dto.ProvinceResponseDTO `json:"data"`
|
||||
Data ProvinceResponseDTO `json:"data"`
|
||||
TotalRegencies int `json:"total_regencies"`
|
||||
}{
|
||||
Data: provinceDTO,
|
||||
|
@ -209,11 +208,11 @@ func (s *wilayahIndonesiaService) GetProvinceByID(ctx context.Context, id string
|
|||
return &provinceDTO, totalRegencies, nil
|
||||
}
|
||||
|
||||
func (s *wilayahIndonesiaService) GetAllRegencies(ctx context.Context, page, limit int) ([]dto.RegencyResponseDTO, int, error) {
|
||||
func (s *wilayahIndonesiaService) GetAllRegencies(ctx context.Context, page, limit int) ([]RegencyResponseDTO, int, error) {
|
||||
cacheKey := fmt.Sprintf("regencies_page:%d_limit:%d", page, limit)
|
||||
|
||||
var cachedResponse struct {
|
||||
Data []dto.RegencyResponseDTO `json:"data"`
|
||||
Data []RegencyResponseDTO `json:"data"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
|
@ -226,9 +225,9 @@ func (s *wilayahIndonesiaService) GetAllRegencies(ctx context.Context, page, lim
|
|||
return nil, 0, fmt.Errorf("failed to fetch regencies: %w", err)
|
||||
}
|
||||
|
||||
regencyDTOs := make([]dto.RegencyResponseDTO, len(regencies))
|
||||
regencyDTOs := make([]RegencyResponseDTO, len(regencies))
|
||||
for i, regency := range regencies {
|
||||
regencyDTOs[i] = dto.RegencyResponseDTO{
|
||||
regencyDTOs[i] = RegencyResponseDTO{
|
||||
ID: regency.ID,
|
||||
ProvinceID: regency.ProvinceID,
|
||||
Name: regency.Name,
|
||||
|
@ -236,7 +235,7 @@ func (s *wilayahIndonesiaService) GetAllRegencies(ctx context.Context, page, lim
|
|||
}
|
||||
|
||||
cacheData := struct {
|
||||
Data []dto.RegencyResponseDTO `json:"data"`
|
||||
Data []RegencyResponseDTO `json:"data"`
|
||||
Total int `json:"total"`
|
||||
}{
|
||||
Data: regencyDTOs,
|
||||
|
@ -250,11 +249,11 @@ func (s *wilayahIndonesiaService) GetAllRegencies(ctx context.Context, page, lim
|
|||
return regencyDTOs, total, nil
|
||||
}
|
||||
|
||||
func (s *wilayahIndonesiaService) GetRegencyByID(ctx context.Context, id string, page, limit int) (*dto.RegencyResponseDTO, int, error) {
|
||||
func (s *wilayahIndonesiaService) GetRegencyByID(ctx context.Context, id string, page, limit int) (*RegencyResponseDTO, int, error) {
|
||||
cacheKey := fmt.Sprintf("regency:%s_page:%d_limit:%d", id, page, limit)
|
||||
|
||||
var cachedResponse struct {
|
||||
Data dto.RegencyResponseDTO `json:"data"`
|
||||
Data RegencyResponseDTO `json:"data"`
|
||||
TotalDistricts int `json:"total_districts"`
|
||||
}
|
||||
|
||||
|
@ -267,15 +266,15 @@ func (s *wilayahIndonesiaService) GetRegencyByID(ctx context.Context, id string,
|
|||
return nil, 0, err
|
||||
}
|
||||
|
||||
regencyDTO := dto.RegencyResponseDTO{
|
||||
regencyDTO := RegencyResponseDTO{
|
||||
ID: regency.ID,
|
||||
ProvinceID: regency.ProvinceID,
|
||||
Name: regency.Name,
|
||||
}
|
||||
|
||||
districtDTOs := make([]dto.DistrictResponseDTO, len(regency.Districts))
|
||||
districtDTOs := make([]DistrictResponseDTO, len(regency.Districts))
|
||||
for i, district := range regency.Districts {
|
||||
districtDTOs[i] = dto.DistrictResponseDTO{
|
||||
districtDTOs[i] = DistrictResponseDTO{
|
||||
ID: district.ID,
|
||||
RegencyID: district.RegencyID,
|
||||
Name: district.Name,
|
||||
|
@ -284,7 +283,7 @@ func (s *wilayahIndonesiaService) GetRegencyByID(ctx context.Context, id string,
|
|||
regencyDTO.Districts = districtDTOs
|
||||
|
||||
cacheData := struct {
|
||||
Data dto.RegencyResponseDTO `json:"data"`
|
||||
Data RegencyResponseDTO `json:"data"`
|
||||
TotalDistricts int `json:"total_districts"`
|
||||
}{
|
||||
Data: regencyDTO,
|
||||
|
@ -298,11 +297,11 @@ func (s *wilayahIndonesiaService) GetRegencyByID(ctx context.Context, id string,
|
|||
return ®encyDTO, totalDistricts, nil
|
||||
}
|
||||
|
||||
func (s *wilayahIndonesiaService) GetAllDistricts(ctx context.Context, page, limit int) ([]dto.DistrictResponseDTO, int, error) {
|
||||
func (s *wilayahIndonesiaService) GetAllDistricts(ctx context.Context, page, limit int) ([]DistrictResponseDTO, int, error) {
|
||||
cacheKey := fmt.Sprintf("districts_page:%d_limit:%d", page, limit)
|
||||
|
||||
var cachedResponse struct {
|
||||
Data []dto.DistrictResponseDTO `json:"data"`
|
||||
Data []DistrictResponseDTO `json:"data"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
|
@ -315,9 +314,9 @@ func (s *wilayahIndonesiaService) GetAllDistricts(ctx context.Context, page, lim
|
|||
return nil, 0, fmt.Errorf("failed to fetch districts: %w", err)
|
||||
}
|
||||
|
||||
districtDTOs := make([]dto.DistrictResponseDTO, len(districts))
|
||||
districtDTOs := make([]DistrictResponseDTO, len(districts))
|
||||
for i, district := range districts {
|
||||
districtDTOs[i] = dto.DistrictResponseDTO{
|
||||
districtDTOs[i] = DistrictResponseDTO{
|
||||
ID: district.ID,
|
||||
RegencyID: district.RegencyID,
|
||||
Name: district.Name,
|
||||
|
@ -325,7 +324,7 @@ func (s *wilayahIndonesiaService) GetAllDistricts(ctx context.Context, page, lim
|
|||
}
|
||||
|
||||
cacheData := struct {
|
||||
Data []dto.DistrictResponseDTO `json:"data"`
|
||||
Data []DistrictResponseDTO `json:"data"`
|
||||
Total int `json:"total"`
|
||||
}{
|
||||
Data: districtDTOs,
|
||||
|
@ -339,11 +338,11 @@ func (s *wilayahIndonesiaService) GetAllDistricts(ctx context.Context, page, lim
|
|||
return districtDTOs, total, nil
|
||||
}
|
||||
|
||||
func (s *wilayahIndonesiaService) GetDistrictByID(ctx context.Context, id string, page, limit int) (*dto.DistrictResponseDTO, int, error) {
|
||||
func (s *wilayahIndonesiaService) GetDistrictByID(ctx context.Context, id string, page, limit int) (*DistrictResponseDTO, int, error) {
|
||||
cacheKey := fmt.Sprintf("district:%s_page:%d_limit:%d", id, page, limit)
|
||||
|
||||
var cachedResponse struct {
|
||||
Data dto.DistrictResponseDTO `json:"data"`
|
||||
Data DistrictResponseDTO `json:"data"`
|
||||
TotalVillages int `json:"total_villages"`
|
||||
}
|
||||
|
||||
|
@ -356,15 +355,15 @@ func (s *wilayahIndonesiaService) GetDistrictByID(ctx context.Context, id string
|
|||
return nil, 0, err
|
||||
}
|
||||
|
||||
districtDTO := dto.DistrictResponseDTO{
|
||||
districtDTO := DistrictResponseDTO{
|
||||
ID: district.ID,
|
||||
RegencyID: district.RegencyID,
|
||||
Name: district.Name,
|
||||
}
|
||||
|
||||
villageDTOs := make([]dto.VillageResponseDTO, len(district.Villages))
|
||||
villageDTOs := make([]VillageResponseDTO, len(district.Villages))
|
||||
for i, village := range district.Villages {
|
||||
villageDTOs[i] = dto.VillageResponseDTO{
|
||||
villageDTOs[i] = VillageResponseDTO{
|
||||
ID: village.ID,
|
||||
DistrictID: village.DistrictID,
|
||||
Name: village.Name,
|
||||
|
@ -373,7 +372,7 @@ func (s *wilayahIndonesiaService) GetDistrictByID(ctx context.Context, id string
|
|||
districtDTO.Villages = villageDTOs
|
||||
|
||||
cacheData := struct {
|
||||
Data dto.DistrictResponseDTO `json:"data"`
|
||||
Data DistrictResponseDTO `json:"data"`
|
||||
TotalVillages int `json:"total_villages"`
|
||||
}{
|
||||
Data: districtDTO,
|
||||
|
@ -387,11 +386,11 @@ func (s *wilayahIndonesiaService) GetDistrictByID(ctx context.Context, id string
|
|||
return &districtDTO, totalVillages, nil
|
||||
}
|
||||
|
||||
func (s *wilayahIndonesiaService) GetAllVillages(ctx context.Context, page, limit int) ([]dto.VillageResponseDTO, int, error) {
|
||||
func (s *wilayahIndonesiaService) GetAllVillages(ctx context.Context, page, limit int) ([]VillageResponseDTO, int, error) {
|
||||
cacheKey := fmt.Sprintf("villages_page:%d_limit:%d", page, limit)
|
||||
|
||||
var cachedResponse struct {
|
||||
Data []dto.VillageResponseDTO `json:"data"`
|
||||
Data []VillageResponseDTO `json:"data"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
|
@ -404,9 +403,9 @@ func (s *wilayahIndonesiaService) GetAllVillages(ctx context.Context, page, limi
|
|||
return nil, 0, fmt.Errorf("failed to fetch villages: %w", err)
|
||||
}
|
||||
|
||||
villageDTOs := make([]dto.VillageResponseDTO, len(villages))
|
||||
villageDTOs := make([]VillageResponseDTO, len(villages))
|
||||
for i, village := range villages {
|
||||
villageDTOs[i] = dto.VillageResponseDTO{
|
||||
villageDTOs[i] = VillageResponseDTO{
|
||||
ID: village.ID,
|
||||
DistrictID: village.DistrictID,
|
||||
Name: village.Name,
|
||||
|
@ -414,7 +413,7 @@ func (s *wilayahIndonesiaService) GetAllVillages(ctx context.Context, page, limi
|
|||
}
|
||||
|
||||
cacheData := struct {
|
||||
Data []dto.VillageResponseDTO `json:"data"`
|
||||
Data []VillageResponseDTO `json:"data"`
|
||||
Total int `json:"total"`
|
||||
}{
|
||||
Data: villageDTOs,
|
||||
|
@ -428,10 +427,10 @@ func (s *wilayahIndonesiaService) GetAllVillages(ctx context.Context, page, limi
|
|||
return villageDTOs, total, nil
|
||||
}
|
||||
|
||||
func (s *wilayahIndonesiaService) GetVillageByID(ctx context.Context, id string) (*dto.VillageResponseDTO, error) {
|
||||
func (s *wilayahIndonesiaService) GetVillageByID(ctx context.Context, id string) (*VillageResponseDTO, error) {
|
||||
cacheKey := fmt.Sprintf("village:%s", id)
|
||||
|
||||
var cachedResponse dto.VillageResponseDTO
|
||||
var cachedResponse VillageResponseDTO
|
||||
if err := utils.GetCache(cacheKey, &cachedResponse); err == nil {
|
||||
return &cachedResponse, nil
|
||||
}
|
||||
|
@ -441,7 +440,7 @@ func (s *wilayahIndonesiaService) GetVillageByID(ctx context.Context, id string)
|
|||
return nil, fmt.Errorf("village not found: %w", err)
|
||||
}
|
||||
|
||||
villageResponse := &dto.VillageResponseDTO{
|
||||
villageResponse := &VillageResponseDTO{
|
||||
ID: village.ID,
|
||||
DistrictID: village.DistrictID,
|
||||
Name: village.Name,
|
||||
|
|
|
@ -7,6 +7,7 @@ type IdentityCard struct {
|
|||
UserID string `gorm:"not null" json:"userId"`
|
||||
User User `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"user"`
|
||||
Identificationumber string `gorm:"not null" json:"identificationumber"`
|
||||
Fullname string `gorm:"not null" json:"fullname"`
|
||||
Placeofbirth string `gorm:"not null" json:"placeofbirth"`
|
||||
Dateofbirth string `gorm:"not null" json:"dateofbirth"`
|
||||
Gender string `gorm:"not null" json:"gender"`
|
||||
|
|
Can't render this file because it is too large.
|
|
@ -9,7 +9,9 @@ import (
|
|||
"rijig/internal/identitycart"
|
||||
"rijig/internal/role"
|
||||
"rijig/internal/userpin"
|
||||
"rijig/internal/userprofile"
|
||||
"rijig/internal/whatsapp"
|
||||
"rijig/internal/wilayahindo"
|
||||
"rijig/middleware"
|
||||
|
||||
// "rijig/presentation"
|
||||
|
@ -19,8 +21,9 @@ import (
|
|||
|
||||
func SetupRoutes(app *fiber.App) {
|
||||
apa := app.Group(os.Getenv("BASE_URL"))
|
||||
whatsapp.WhatsAppRouter(apa)
|
||||
apa.Static("/uploads", "./public"+os.Getenv("BASE_URL")+"/uploads")
|
||||
a := app.Group(os.Getenv("BASE_URL"))
|
||||
whatsapp.WhatsAppRouter(a)
|
||||
|
||||
api := app.Group(os.Getenv("BASE_URL"))
|
||||
api.Use(middleware.APIKeyMiddleware)
|
||||
|
@ -32,6 +35,8 @@ func SetupRoutes(app *fiber.App) {
|
|||
role.UserRoleRouter(api)
|
||||
|
||||
article.ArticleRouter(api)
|
||||
userprofile.UserProfileRouter(api)
|
||||
wilayahindo.WilayahRouter(api)
|
||||
|
||||
// || auth router || //
|
||||
// presentation.AuthRouter(api)
|
||||
|
@ -58,5 +63,4 @@ func SetupRoutes(app *fiber.App) {
|
|||
// // presentation.AboutRouter(api)
|
||||
// presentation.TrashRouter(api)
|
||||
// presentation.CoverageAreaRouter(api)
|
||||
whatsapp.WhatsAppRouter(api)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue