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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"rijig/dto"
|
|
||||||
"rijig/utils"
|
"rijig/utils"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
@ -20,7 +19,7 @@ func NewAboutHandler(aboutService AboutService) *AboutHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *AboutHandler) CreateAbout(c *fiber.Ctx) error {
|
func (h *AboutHandler) CreateAbout(c *fiber.Ctx) error {
|
||||||
var request dto.RequestAboutDTO
|
var request RequestAboutDTO
|
||||||
if err := c.BodyParser(&request); err != nil {
|
if err := c.BodyParser(&request); err != nil {
|
||||||
return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Invalid request body", map[string][]string{"body": {"Invalid body"}})
|
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 {
|
func (h *AboutHandler) UpdateAbout(c *fiber.Ctx) error {
|
||||||
id := c.Params("id")
|
id := c.Params("id")
|
||||||
|
|
||||||
var request dto.RequestAboutDTO
|
var request RequestAboutDTO
|
||||||
if err := c.BodyParser(&request); err != nil {
|
if err := c.BodyParser(&request); err != nil {
|
||||||
log.Printf("Error parsing request body: %v", err)
|
log.Printf("Error parsing request body: %v", err)
|
||||||
return utils.BadRequest(c, "Invalid input data")
|
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 {
|
func (h *AboutHandler) CreateAboutDetail(c *fiber.Ctx) error {
|
||||||
var request dto.RequestAboutDetailDTO
|
var request RequestAboutDetailDTO
|
||||||
if err := c.BodyParser(&request); err != nil {
|
if err := c.BodyParser(&request); err != nil {
|
||||||
log.Printf("Error parsing request body: %v", err)
|
log.Printf("Error parsing request body: %v", err)
|
||||||
return utils.BadRequest(c, "Invalid input data")
|
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 {
|
func (h *AboutHandler) UpdateAboutDetail(c *fiber.Ctx) error {
|
||||||
id := c.Params("id")
|
id := c.Params("id")
|
||||||
|
|
||||||
var request dto.RequestAboutDetailDTO
|
var request RequestAboutDetailDTO
|
||||||
if err := c.BodyParser(&request); err != nil {
|
if err := c.BodyParser(&request); err != nil {
|
||||||
log.Printf("Error parsing request body: %v", err)
|
log.Printf("Error parsing request body: %v", err)
|
||||||
return utils.BadRequest(c, "Invalid input data")
|
return utils.BadRequest(c, "Invalid input data")
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"rijig/dto"
|
|
||||||
"rijig/model"
|
"rijig/model"
|
||||||
"rijig/utils"
|
"rijig/utils"
|
||||||
"time"
|
"time"
|
||||||
|
@ -24,15 +23,15 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type AboutService interface {
|
type AboutService interface {
|
||||||
CreateAbout(ctx context.Context, request dto.RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*dto.ResponseAboutDTO, error)
|
CreateAbout(ctx context.Context, request RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*ResponseAboutDTO, error)
|
||||||
UpdateAbout(ctx context.Context, id string, request dto.RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*dto.ResponseAboutDTO, error)
|
UpdateAbout(ctx context.Context, id string, request RequestAboutDTO, coverImageAbout *multipart.FileHeader) (*ResponseAboutDTO, error)
|
||||||
GetAllAbout(ctx context.Context) ([]dto.ResponseAboutDTO, error)
|
GetAllAbout(ctx context.Context) ([]ResponseAboutDTO, error)
|
||||||
GetAboutByID(ctx context.Context, id string) (*dto.ResponseAboutDTO, error)
|
GetAboutByID(ctx context.Context, id string) (*ResponseAboutDTO, error)
|
||||||
GetAboutDetailById(ctx context.Context, id string) (*dto.ResponseAboutDetailDTO, error)
|
GetAboutDetailById(ctx context.Context, id string) (*ResponseAboutDetailDTO, error)
|
||||||
DeleteAbout(ctx context.Context, id string) error
|
DeleteAbout(ctx context.Context, id string) error
|
||||||
|
|
||||||
CreateAboutDetail(ctx context.Context, request dto.RequestAboutDetailDTO, coverImageAboutDetail *multipart.FileHeader) (*dto.ResponseAboutDetailDTO, error)
|
CreateAboutDetail(ctx context.Context, request RequestAboutDetailDTO, coverImageAboutDetail *multipart.FileHeader) (*ResponseAboutDetailDTO, error)
|
||||||
UpdateAboutDetail(ctx context.Context, id string, request dto.RequestAboutDetailDTO, imageDetail *multipart.FileHeader) (*dto.ResponseAboutDetailDTO, error)
|
UpdateAboutDetail(ctx context.Context, id string, request RequestAboutDetailDTO, imageDetail *multipart.FileHeader) (*ResponseAboutDetailDTO, error)
|
||||||
DeleteAboutDetail(ctx context.Context, id string) error
|
DeleteAboutDetail(ctx context.Context, id string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,11 +65,11 @@ func (s *aboutService) invalidateAboutDetailCaches(aboutDetailID, aboutID string
|
||||||
s.invalidateAboutCaches(aboutID)
|
s.invalidateAboutCaches(aboutID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatResponseAboutDetailDTO(about *model.AboutDetail) (*dto.ResponseAboutDetailDTO, error) {
|
func formatResponseAboutDetailDTO(about *model.AboutDetail) (*ResponseAboutDetailDTO, error) {
|
||||||
createdAt, _ := utils.FormatDateToIndonesianFormat(about.CreatedAt)
|
createdAt, _ := utils.FormatDateToIndonesianFormat(about.CreatedAt)
|
||||||
updatedAt, _ := utils.FormatDateToIndonesianFormat(about.UpdatedAt)
|
updatedAt, _ := utils.FormatDateToIndonesianFormat(about.UpdatedAt)
|
||||||
|
|
||||||
response := &dto.ResponseAboutDetailDTO{
|
response := &ResponseAboutDetailDTO{
|
||||||
ID: about.ID,
|
ID: about.ID,
|
||||||
AboutID: about.AboutID,
|
AboutID: about.AboutID,
|
||||||
ImageDetail: about.ImageDetail,
|
ImageDetail: about.ImageDetail,
|
||||||
|
@ -82,11 +81,11 @@ func formatResponseAboutDetailDTO(about *model.AboutDetail) (*dto.ResponseAboutD
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatResponseAboutDTO(about *model.About) (*dto.ResponseAboutDTO, error) {
|
func formatResponseAboutDTO(about *model.About) (*ResponseAboutDTO, error) {
|
||||||
createdAt, _ := utils.FormatDateToIndonesianFormat(about.CreatedAt)
|
createdAt, _ := utils.FormatDateToIndonesianFormat(about.CreatedAt)
|
||||||
updatedAt, _ := utils.FormatDateToIndonesianFormat(about.UpdatedAt)
|
updatedAt, _ := utils.FormatDateToIndonesianFormat(about.UpdatedAt)
|
||||||
|
|
||||||
response := &dto.ResponseAboutDTO{
|
response := &ResponseAboutDTO{
|
||||||
ID: about.ID,
|
ID: about.ID,
|
||||||
Title: about.Title,
|
Title: about.Title,
|
||||||
CoverImage: about.CoverImage,
|
CoverImage: about.CoverImage,
|
||||||
|
@ -194,7 +193,7 @@ func deleteCoverImageAbout(coverimageAboutPath string) error {
|
||||||
return nil
|
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()
|
errors, valid := request.ValidateAbout()
|
||||||
if !valid {
|
if !valid {
|
||||||
return nil, fmt.Errorf("validation error: %v", errors)
|
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
|
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()
|
errors, valid := request.ValidateAbout()
|
||||||
if !valid {
|
if !valid {
|
||||||
return nil, fmt.Errorf("validation error: %v", errors)
|
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
|
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 {
|
if err := utils.GetCache(cacheKeyAllAbout, &cachedAbouts); err == nil {
|
||||||
return cachedAbouts, 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)
|
return nil, fmt.Errorf("failed to get About list: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var aboutDTOList []dto.ResponseAboutDTO
|
var aboutDTOList []ResponseAboutDTO
|
||||||
for _, about := range aboutList {
|
for _, about := range aboutList {
|
||||||
response, err := formatResponseAboutDTO(&about)
|
response, err := formatResponseAboutDTO(&about)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -300,10 +299,10 @@ func (s *aboutService) GetAllAbout(ctx context.Context) ([]dto.ResponseAboutDTO,
|
||||||
return aboutDTOList, nil
|
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)
|
cacheKey := fmt.Sprintf(cacheKeyAboutByID, id)
|
||||||
|
|
||||||
var cachedAbout dto.ResponseAboutDTO
|
var cachedAbout ResponseAboutDTO
|
||||||
if err := utils.GetCache(cacheKey, &cachedAbout); err == nil {
|
if err := utils.GetCache(cacheKey, &cachedAbout); err == nil {
|
||||||
return &cachedAbout, 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)
|
return nil, fmt.Errorf("error formatting About response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var responseDetails []dto.ResponseAboutDetailDTO
|
var responseDetails []ResponseAboutDetailDTO
|
||||||
for _, detail := range about.AboutDetail {
|
for _, detail := range about.AboutDetail {
|
||||||
formattedDetail, err := formatResponseAboutDetailDTO(&detail)
|
formattedDetail, err := formatResponseAboutDetailDTO(&detail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -336,10 +335,10 @@ func (s *aboutService) GetAboutByID(ctx context.Context, id string) (*dto.Respon
|
||||||
return response, nil
|
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)
|
cacheKey := fmt.Sprintf(cacheKeyAboutDetail, id)
|
||||||
|
|
||||||
var cachedDetail dto.ResponseAboutDetailDTO
|
var cachedDetail ResponseAboutDetailDTO
|
||||||
if err := utils.GetCache(cacheKey, &cachedDetail); err == nil {
|
if err := utils.GetCache(cacheKey, &cachedDetail); err == nil {
|
||||||
return &cachedDetail, nil
|
return &cachedDetail, nil
|
||||||
}
|
}
|
||||||
|
@ -390,7 +389,7 @@ func (s *aboutService) DeleteAbout(ctx context.Context, id string) error {
|
||||||
return nil
|
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()
|
errors, valid := request.ValidateAboutDetail()
|
||||||
if !valid {
|
if !valid {
|
||||||
return nil, fmt.Errorf("validation error: %v", errors)
|
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
|
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()
|
errors, valid := request.ValidateAboutDetail()
|
||||||
if !valid {
|
if !valid {
|
||||||
return nil, fmt.Errorf("validation error: %v", errors)
|
return nil, fmt.Errorf("validation error: %v", errors)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package address
|
package address
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"rijig/dto"
|
|
||||||
"rijig/middleware"
|
"rijig/middleware"
|
||||||
"rijig/utils"
|
"rijig/utils"
|
||||||
|
|
||||||
|
@ -17,7 +16,7 @@ func NewAddressHandler(addressService AddressService) *AddressHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *AddressHandler) CreateAddress(c *fiber.Ctx) error {
|
func (h *AddressHandler) CreateAddress(c *fiber.Ctx) error {
|
||||||
var request dto.CreateAddressDTO
|
var request CreateAddressDTO
|
||||||
claims, err := middleware.GetUserFromContext(c)
|
claims, err := middleware.GetUserFromContext(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -74,7 +73,7 @@ func (h *AddressHandler) UpdateAddress(c *fiber.Ctx) error {
|
||||||
|
|
||||||
addressID := c.Params("address_id")
|
addressID := c.Params("address_id")
|
||||||
|
|
||||||
var request dto.CreateAddressDTO
|
var request CreateAddressDTO
|
||||||
claims, err := middleware.GetUserFromContext(c)
|
claims, err := middleware.GetUserFromContext(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"rijig/dto"
|
|
||||||
"rijig/internal/wilayahindo"
|
"rijig/internal/wilayahindo"
|
||||||
"rijig/model"
|
"rijig/model"
|
||||||
"rijig/utils"
|
"rijig/utils"
|
||||||
|
@ -20,10 +19,10 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type AddressService interface {
|
type AddressService interface {
|
||||||
CreateAddress(ctx context.Context, userID string, request dto.CreateAddressDTO) (*dto.AddressResponseDTO, error)
|
CreateAddress(ctx context.Context, userID string, request CreateAddressDTO) (*AddressResponseDTO, error)
|
||||||
GetAddressByUserID(ctx context.Context, userID string) ([]dto.AddressResponseDTO, error)
|
GetAddressByUserID(ctx context.Context, userID string) ([]AddressResponseDTO, error)
|
||||||
GetAddressByID(ctx context.Context, userID, id string) (*dto.AddressResponseDTO, error)
|
GetAddressByID(ctx context.Context, userID, id string) (*AddressResponseDTO, error)
|
||||||
UpdateAddress(ctx context.Context, userID, id string, addressDTO dto.CreateAddressDTO) (*dto.AddressResponseDTO, error)
|
UpdateAddress(ctx context.Context, userID, id string, addressDTO CreateAddressDTO) (*AddressResponseDTO, error)
|
||||||
DeleteAddress(ctx context.Context, userID, id string) 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)
|
province, _, err := s.wilayahRepo.FindProvinceByID(ctx, addressDTO.Province, 0, 0)
|
||||||
if err != nil {
|
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
|
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)
|
createdAt, _ := utils.FormatDateToIndonesianFormat(address.CreatedAt)
|
||||||
updatedAt, _ := utils.FormatDateToIndonesianFormat(address.UpdatedAt)
|
updatedAt, _ := utils.FormatDateToIndonesianFormat(address.UpdatedAt)
|
||||||
|
|
||||||
return &dto.AddressResponseDTO{
|
return &AddressResponseDTO{
|
||||||
UserID: address.UserID,
|
UserID: address.UserID,
|
||||||
ID: address.ID,
|
ID: address.ID,
|
||||||
Province: address.Province,
|
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)
|
cacheKey := fmt.Sprintf(addressCacheKeyPattern, addressDTO.ID)
|
||||||
if err := utils.SetCache(cacheKey, addressDTO, cacheTTL); err != nil {
|
if err := utils.SetCache(cacheKey, addressDTO, cacheTTL); err != nil {
|
||||||
fmt.Printf("Error caching address to Redis: %v\n", err)
|
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)
|
addresses, err := s.addressRepo.FindAddressByUserID(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to fetch addresses: %w", err)
|
return nil, fmt.Errorf("failed to fetch addresses: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var addressDTOs []dto.AddressResponseDTO
|
var addressDTOs []AddressResponseDTO
|
||||||
for _, address := range addresses {
|
for _, address := range addresses {
|
||||||
addressDTOs = append(addressDTOs, *s.mapToResponseDTO(&address))
|
addressDTOs = append(addressDTOs, *s.mapToResponseDTO(&address))
|
||||||
}
|
}
|
||||||
|
@ -137,7 +136,7 @@ func (s *addressService) checkAddressOwnership(ctx context.Context, userID, addr
|
||||||
return address, nil
|
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)
|
provinceName, regencyName, districtName, villageName, err := s.validateWilayahIDs(ctx, addressDTO)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -168,10 +167,10 @@ func (s *addressService) CreateAddress(ctx context.Context, userID string, addre
|
||||||
return responseDTO, nil
|
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)
|
cacheKey := fmt.Sprintf(userAddressesCacheKeyPattern, userID)
|
||||||
var cachedAddresses []dto.AddressResponseDTO
|
var cachedAddresses []AddressResponseDTO
|
||||||
|
|
||||||
if err := utils.GetCache(cacheKey, &cachedAddresses); err == nil {
|
if err := utils.GetCache(cacheKey, &cachedAddresses); err == nil {
|
||||||
return cachedAddresses, nil
|
return cachedAddresses, nil
|
||||||
|
@ -180,7 +179,7 @@ func (s *addressService) GetAddressByUserID(ctx context.Context, userID string)
|
||||||
return s.cacheUserAddresses(ctx, userID)
|
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)
|
address, err := s.checkAddressOwnership(ctx, userID, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -188,7 +187,7 @@ func (s *addressService) GetAddressByID(ctx context.Context, userID, id string)
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheKey := fmt.Sprintf(addressCacheKeyPattern, id)
|
cacheKey := fmt.Sprintf(addressCacheKeyPattern, id)
|
||||||
var cachedAddress dto.AddressResponseDTO
|
var cachedAddress AddressResponseDTO
|
||||||
|
|
||||||
if err := utils.GetCache(cacheKey, &cachedAddress); err == nil {
|
if err := utils.GetCache(cacheKey, &cachedAddress); err == nil {
|
||||||
return &cachedAddress, nil
|
return &cachedAddress, nil
|
||||||
|
@ -200,7 +199,7 @@ func (s *addressService) GetAddressByID(ctx context.Context, userID, id string)
|
||||||
return responseDTO, nil
|
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)
|
address, err := s.checkAddressOwnership(ctx, userID, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -2,6 +2,8 @@ package authentication
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
"rijig/model"
|
"rijig/model"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
@ -15,6 +17,9 @@ type AuthenticationRepository interface {
|
||||||
CreateUser(ctx context.Context, user *model.User) error
|
CreateUser(ctx context.Context, user *model.User) error
|
||||||
UpdateUser(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
|
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 {
|
type authenticationRepository struct {
|
||||||
|
@ -84,3 +89,37 @@ func (r *authenticationRepository) PatchUser(ctx context.Context, userID string,
|
||||||
Where("id = ?", userID).
|
Where("id = ?", userID).
|
||||||
Updates(updates).Error
|
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")
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("user tidak ditemukan")
|
return nil, fmt.Errorf("user tidak ditemukan")
|
||||||
}
|
}
|
||||||
|
@ -324,24 +326,29 @@ func (s *authenticationService) VerifyLoginOTP(ctx context.Context, req *VerifyO
|
||||||
|
|
||||||
tokenResponse, err := utils.GenerateTokenPair(
|
tokenResponse, err := utils.GenerateTokenPair(
|
||||||
user.ID,
|
user.ID,
|
||||||
user.Role.RoleName,
|
normalizedRole,
|
||||||
req.DeviceID,
|
req.DeviceID,
|
||||||
"pin_verification_required",
|
user.RegistrationStatus,
|
||||||
int(user.RegistrationProgress),
|
int(user.RegistrationProgress),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("gagal generate token: %v", err)
|
return nil, fmt.Errorf("gagal generate token: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nextStep := utils.GetNextRegistrationStep(
|
||||||
|
normalizedRole,
|
||||||
|
int(user.RegistrationProgress),
|
||||||
|
user.RegistrationStatus,
|
||||||
|
)
|
||||||
|
|
||||||
return &AuthResponse{
|
return &AuthResponse{
|
||||||
Message: "OTP berhasil diverifikasi, silakan masukkan PIN",
|
Message: "otp berhasil diverifikasi",
|
||||||
AccessToken: tokenResponse.AccessToken,
|
AccessToken: tokenResponse.AccessToken,
|
||||||
RefreshToken: tokenResponse.RefreshToken,
|
RefreshToken: tokenResponse.RefreshToken,
|
||||||
TokenType: string(tokenResponse.TokenType),
|
TokenType: string(tokenResponse.TokenType),
|
||||||
ExpiresIn: tokenResponse.ExpiresIn,
|
ExpiresIn: tokenResponse.ExpiresIn,
|
||||||
User: convertUserToResponse(user),
|
|
||||||
RegistrationStatus: user.RegistrationStatus,
|
RegistrationStatus: user.RegistrationStatus,
|
||||||
NextStep: "Masukkan PIN",
|
NextStep: nextStep,
|
||||||
SessionID: tokenResponse.SessionID,
|
SessionID: tokenResponse.SessionID,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package company
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"rijig/config"
|
"rijig/config"
|
||||||
|
"rijig/internal/authentication"
|
||||||
"rijig/middleware"
|
"rijig/middleware"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
@ -9,7 +10,8 @@ import (
|
||||||
|
|
||||||
func CompanyRouter(api fiber.Router) {
|
func CompanyRouter(api fiber.Router) {
|
||||||
companyProfileRepo := NewCompanyProfileRepository(config.DB)
|
companyProfileRepo := NewCompanyProfileRepository(config.DB)
|
||||||
companyProfileService := NewCompanyProfileService(companyProfileRepo)
|
authRepo := authentication.NewAuthenticationRepository(config.DB)
|
||||||
|
companyProfileService := NewCompanyProfileService(companyProfileRepo, authRepo)
|
||||||
companyProfileHandler := NewCompanyProfileHandler(companyProfileService)
|
companyProfileHandler := NewCompanyProfileHandler(companyProfileService)
|
||||||
|
|
||||||
companyProfileAPI := api.Group("/companyprofile")
|
companyProfileAPI := api.Group("/companyprofile")
|
||||||
|
|
|
@ -3,8 +3,13 @@ package company
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"rijig/internal/authentication"
|
||||||
|
"rijig/internal/role"
|
||||||
|
"rijig/internal/userprofile"
|
||||||
"rijig/model"
|
"rijig/model"
|
||||||
"rijig/utils"
|
"rijig/utils"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CompanyProfileService interface {
|
type CompanyProfileService interface {
|
||||||
|
@ -13,15 +18,19 @@ type CompanyProfileService interface {
|
||||||
GetCompanyProfilesByUserID(ctx context.Context, userID string) ([]ResponseCompanyProfileDTO, error)
|
GetCompanyProfilesByUserID(ctx context.Context, userID string) ([]ResponseCompanyProfileDTO, error)
|
||||||
UpdateCompanyProfile(ctx context.Context, userID string, request *RequestCompanyProfileDTO) (*ResponseCompanyProfileDTO, error)
|
UpdateCompanyProfile(ctx context.Context, userID string, request *RequestCompanyProfileDTO) (*ResponseCompanyProfileDTO, error)
|
||||||
DeleteCompanyProfile(ctx context.Context, userID string) 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 {
|
type companyProfileService struct {
|
||||||
companyRepo CompanyProfileRepository
|
companyRepo CompanyProfileRepository
|
||||||
|
authRepo authentication.AuthenticationRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCompanyProfileService(companyRepo CompanyProfileRepository) CompanyProfileService {
|
func NewCompanyProfileService(companyRepo CompanyProfileRepository, authRepo authentication.AuthenticationRepository) CompanyProfileService {
|
||||||
return &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) {
|
func (s *companyProfileService) CreateCompanyProfile(ctx context.Context, userID string, request *RequestCompanyProfileDTO) (*ResponseCompanyProfileDTO, error) {
|
||||||
if errors, valid := request.ValidateCompanyProfileInput(); !valid {
|
// if errors, valid := request.ValidateCompanyProfileInput(); !valid {
|
||||||
return nil, fmt.Errorf("validation failed: %v", errors)
|
// return nil, fmt.Errorf("validation failed: %v", errors)
|
||||||
}
|
// }
|
||||||
|
|
||||||
companyProfile := &model.CompanyProfile{
|
companyProfile := &model.CompanyProfile{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
|
@ -134,3 +143,100 @@ func (s *companyProfileService) UpdateCompanyProfile(ctx context.Context, userID
|
||||||
func (s *companyProfileService) DeleteCompanyProfile(ctx context.Context, userID string) error {
|
func (s *companyProfileService) DeleteCompanyProfile(ctx context.Context, userID string) error {
|
||||||
return s.companyRepo.DeleteCompanyProfileByUserID(ctx, userID)
|
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"`
|
ID string `json:"id"`
|
||||||
UserID string `json:"userId"`
|
UserID string `json:"userId"`
|
||||||
Identificationumber string `json:"identificationumber"`
|
Identificationumber string `json:"identificationumber"`
|
||||||
|
Fullname string `json:"fullname"`
|
||||||
Placeofbirth string `json:"placeofbirth"`
|
Placeofbirth string `json:"placeofbirth"`
|
||||||
Dateofbirth string `json:"dateofbirth"`
|
Dateofbirth string `json:"dateofbirth"`
|
||||||
Gender string `json:"gender"`
|
Gender string `json:"gender"`
|
||||||
|
@ -31,9 +32,10 @@ type ResponseIdentityCardDTO struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type RequestIdentityCardDTO struct {
|
type RequestIdentityCardDTO struct {
|
||||||
DeviceID string `json:"device_id"`
|
// DeviceID string `json:"device_id"`
|
||||||
UserID string `json:"userId"`
|
UserID string `json:"userId"`
|
||||||
Identificationumber string `json:"identificationumber"`
|
Identificationumber string `json:"identificationumber"`
|
||||||
|
Fullname string `json:"fullname"`
|
||||||
Placeofbirth string `json:"placeofbirth"`
|
Placeofbirth string `json:"placeofbirth"`
|
||||||
Dateofbirth string `json:"dateofbirth"`
|
Dateofbirth string `json:"dateofbirth"`
|
||||||
Gender string `json:"gender"`
|
Gender string `json:"gender"`
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package identitycart
|
package identitycart
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"rijig/middleware"
|
"rijig/middleware"
|
||||||
"rijig/utils"
|
"rijig/utils"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
@ -18,27 +20,33 @@ func NewIdentityCardHandler(service IdentityCardService) *IdentityCardHandler {
|
||||||
func (h *IdentityCardHandler) CreateIdentityCardHandler(c *fiber.Ctx) error {
|
func (h *IdentityCardHandler) CreateIdentityCardHandler(c *fiber.Ctx) error {
|
||||||
claims, err := middleware.GetUserFromContext(c)
|
claims, err := middleware.GetUserFromContext(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
log.Printf("Error getting user from context: %v", err)
|
||||||
}
|
return utils.Unauthorized(c, "unauthorized access")
|
||||||
|
|
||||||
cardPhoto, err := c.FormFile("cardphoto")
|
|
||||||
if err != nil {
|
|
||||||
return utils.BadRequest(c, "KTP photo is required")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var input RequestIdentityCardDTO
|
var input RequestIdentityCardDTO
|
||||||
if err := c.BodyParser(&input); err != nil {
|
if err := c.BodyParser(&input); err != nil {
|
||||||
|
log.Printf("Error parsing body: %v", err)
|
||||||
return utils.BadRequest(c, "Invalid input format")
|
return utils.BadRequest(c, "Invalid input format")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if errs, valid := input.ValidateIdentityCardInput(); !valid {
|
if errs, valid := input.ValidateIdentityCardInput(); !valid {
|
||||||
return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Input validation failed", errs)
|
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 {
|
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)
|
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 {
|
func (h *IdentityCardHandler) GetIdentityByID(c *fiber.Ctx) error {
|
||||||
id := c.Params("id")
|
id := c.Params("id")
|
||||||
if 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)
|
result, err := h.service.GetIdentityCardByID(c.Context(), id)
|
||||||
if err != nil {
|
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 {
|
func (h *IdentityCardHandler) GetIdentityByUserId(c *fiber.Ctx) error {
|
||||||
claims, err := middleware.GetUserFromContext(c)
|
claims, err := middleware.GetUserFromContext(c)
|
||||||
if err != nil {
|
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)
|
result, err := h.service.GetIdentityCardsByUserID(c.Context(), claims.UserID)
|
||||||
if err != nil {
|
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 (
|
import (
|
||||||
"rijig/config"
|
"rijig/config"
|
||||||
"rijig/internal/authentication"
|
"rijig/internal/authentication"
|
||||||
|
"rijig/internal/userprofile"
|
||||||
"rijig/middleware"
|
"rijig/middleware"
|
||||||
|
"rijig/utils"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
@ -11,25 +13,34 @@ import (
|
||||||
func UserIdentityCardRoute(api fiber.Router) {
|
func UserIdentityCardRoute(api fiber.Router) {
|
||||||
identityRepo := NewIdentityCardRepository(config.DB)
|
identityRepo := NewIdentityCardRepository(config.DB)
|
||||||
authRepo := authentication.NewAuthenticationRepository(config.DB)
|
authRepo := authentication.NewAuthenticationRepository(config.DB)
|
||||||
identityService := NewIdentityCardService(identityRepo, authRepo)
|
userRepo := userprofile.NewUserProfileRepository(config.DB)
|
||||||
|
identityService := NewIdentityCardService(identityRepo, authRepo, userRepo)
|
||||||
identityHandler := NewIdentityCardHandler(identityService)
|
identityHandler := NewIdentityCardHandler(identityService)
|
||||||
|
|
||||||
identity := api.Group("/identity")
|
identity := api.Group("/identity")
|
||||||
|
|
||||||
identity.Post("/create",
|
identity.Post("/create",
|
||||||
middleware.AuthMiddleware(),
|
middleware.AuthMiddleware(),
|
||||||
middleware.RequireRoles("pengelola", "pengepul"),
|
middleware.RequireRoles(utils.RolePengepul),
|
||||||
identityHandler.CreateIdentityCardHandler,
|
identityHandler.CreateIdentityCardHandler,
|
||||||
)
|
)
|
||||||
identity.Get("/:id",
|
identity.Get("/:id",
|
||||||
middleware.AuthMiddleware(),
|
middleware.AuthMiddleware(),
|
||||||
middleware.RequireRoles("pengelola", "pengepul"),
|
|
||||||
identityHandler.GetIdentityByID,
|
identityHandler.GetIdentityByID,
|
||||||
)
|
)
|
||||||
|
identity.Get("/s",
|
||||||
|
middleware.AuthMiddleware(),
|
||||||
|
identityHandler.GetIdentityByUserId,
|
||||||
|
)
|
||||||
identity.Get("/",
|
identity.Get("/",
|
||||||
middleware.AuthMiddleware(),
|
middleware.AuthMiddleware(),
|
||||||
middleware.RequireRoles("pengelola", "pengepul"),
|
middleware.RequireRoles(utils.RoleAdministrator),
|
||||||
identityHandler.GetIdentityByUserId,
|
identityHandler.GetAllIdentityCardsByRegStatus,
|
||||||
|
)
|
||||||
|
identity.Patch("/:userId/status",
|
||||||
|
middleware.AuthMiddleware(),
|
||||||
|
middleware.RequireRoles(utils.RoleAdministrator),
|
||||||
|
identityHandler.UpdateUserRegistrationStatusByIdentityCard,
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,36 +2,49 @@ package identitycart
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"rijig/internal/authentication"
|
"rijig/internal/authentication"
|
||||||
|
"rijig/internal/role"
|
||||||
|
"rijig/internal/userprofile"
|
||||||
"rijig/model"
|
"rijig/model"
|
||||||
"rijig/utils"
|
"rijig/utils"
|
||||||
"strings"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IdentityCardService interface {
|
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)
|
GetIdentityCardByID(ctx context.Context, id string) (*ResponseIdentityCardDTO, error)
|
||||||
GetIdentityCardsByUserID(ctx context.Context, userID 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)
|
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 {
|
type identityCardService struct {
|
||||||
identityRepo IdentityCardRepository
|
identityRepo IdentityCardRepository
|
||||||
authRepo authentication.AuthenticationRepository
|
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{
|
return &identityCardService{
|
||||||
identityRepo: identityRepo,
|
identityRepo,
|
||||||
authRepo: authRepo,
|
authRepo, userRepo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IdentityCardWithUserDTO struct {
|
||||||
|
IdentityCard ResponseIdentityCardDTO `json:"identity_card"`
|
||||||
|
User userprofile.UserProfileResponseDTO `json:"user"`
|
||||||
|
}
|
||||||
|
|
||||||
func FormatResponseIdentityCard(identityCard *model.IdentityCard) (*ResponseIdentityCardDTO, error) {
|
func FormatResponseIdentityCard(identityCard *model.IdentityCard) (*ResponseIdentityCardDTO, error) {
|
||||||
createdAt, _ := utils.FormatDateToIndonesianFormat(identityCard.CreatedAt)
|
createdAt, _ := utils.FormatDateToIndonesianFormat(identityCard.CreatedAt)
|
||||||
updatedAt, _ := utils.FormatDateToIndonesianFormat(identityCard.UpdatedAt)
|
updatedAt, _ := utils.FormatDateToIndonesianFormat(identityCard.UpdatedAt)
|
||||||
|
@ -93,7 +106,7 @@ func (s *identityCardService) saveIdentityCardImage(userID string, cardPhoto *mu
|
||||||
}
|
}
|
||||||
defer dst.Close()
|
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)
|
return "", fmt.Errorf("failed to save card photo: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,16 +136,7 @@ func deleteIdentityCardImage(imagePath string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *identityCardService) CreateIdentityCard(ctx context.Context, userID string, request *RequestIdentityCardDTO, cardPhoto *multipart.FileHeader) (*authentication.AuthResponse, error) {
|
func (s *identityCardService) CreateIdentityCard(ctx context.Context, userID, deviceID 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")
|
|
||||||
}
|
|
||||||
|
|
||||||
cardPhotoPath, err := s.saveIdentityCardImage(userID, cardPhoto)
|
cardPhotoPath, err := s.saveIdentityCardImage(userID, cardPhoto)
|
||||||
if err != nil {
|
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)
|
return nil, fmt.Errorf("failed to find user: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate user data
|
|
||||||
if user.Role.RoleName == "" {
|
if user.Role.RoleName == "" {
|
||||||
return nil, fmt.Errorf("user role not found")
|
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{}{
|
updates := map[string]interface{}{
|
||||||
"registration_progress": newRegistrationProgress,
|
"registration_progress": utils.ProgressDataSubmitted,
|
||||||
"registration_status": newRegistrationStatus,
|
"registration_status": utils.RegStatusPending,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.authRepo.PatchUser(ctx, userID, updates)
|
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)
|
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("Token Generation Parameters:")
|
||||||
log.Printf("- UserID: '%s'", user.ID)
|
log.Printf("- UserID: '%s'", user.ID)
|
||||||
log.Printf("- Role: '%s'", user.Role.RoleName)
|
log.Printf("- Role: '%s'", user.Role.RoleName)
|
||||||
log.Printf("- DeviceID: '%s'", request.DeviceID)
|
log.Printf("- DeviceID: '%s'", deviceID)
|
||||||
log.Printf("- Registration Status: '%s'", newRegistrationStatus)
|
log.Printf("- Registration Status: '%s'", utils.RegStatusPending)
|
||||||
|
|
||||||
// Generate token pair with updated status
|
|
||||||
tokenResponse, err := utils.GenerateTokenPair(
|
tokenResponse, err := utils.GenerateTokenPair(
|
||||||
user.ID,
|
updated.ID,
|
||||||
user.Role.RoleName,
|
updated.Role.RoleName,
|
||||||
request.DeviceID,
|
deviceID,
|
||||||
newRegistrationStatus,
|
updated.RegistrationStatus,
|
||||||
newRegistrationProgress,
|
int(updated.RegistrationProgress),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("GenerateTokenPair error: %v", err)
|
log.Printf("GenerateTokenPair error: %v", err)
|
||||||
return nil, fmt.Errorf("failed to generate token: %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{
|
return &authentication.AuthResponse{
|
||||||
Message: "identity card berhasil diunggah, silakan tunggu konfirmasi dari admin dalam 1x24 jam",
|
Message: "identity card berhasil diunggah, silakan tunggu konfirmasi dari admin dalam 1x24 jam",
|
||||||
AccessToken: tokenResponse.AccessToken,
|
AccessToken: tokenResponse.AccessToken,
|
||||||
RefreshToken: tokenResponse.RefreshToken,
|
RefreshToken: tokenResponse.RefreshToken,
|
||||||
TokenType: string(tokenResponse.TokenType),
|
TokenType: string(tokenResponse.TokenType),
|
||||||
ExpiresIn: tokenResponse.ExpiresIn,
|
ExpiresIn: tokenResponse.ExpiresIn,
|
||||||
RegistrationStatus: newRegistrationStatus,
|
RegistrationStatus: updated.RegistrationStatus,
|
||||||
NextStep: tokenResponse.NextStep,
|
NextStep: nextStep,
|
||||||
SessionID: tokenResponse.SessionID,
|
SessionID: tokenResponse.SessionID,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -319,3 +315,164 @@ func (s *identityCardService) UpdateIdentityCard(ctx context.Context, userID str
|
||||||
|
|
||||||
return idcardResponseDTO, nil
|
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 {
|
type RequestPinDTO struct {
|
||||||
DeviceId string `json:"device_id"`
|
// DeviceId string `json:"device_id"`
|
||||||
Pin string `json:"userpin"`
|
Pin string `json:"userpin"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,47 +15,39 @@ func NewUserPinHandler(service UserPinService) *UserPinHandler {
|
||||||
return &UserPinHandler{service}
|
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 {
|
func (h *UserPinHandler) CreateUserPinHandler(c *fiber.Ctx) error {
|
||||||
// Ambil klaim pengguna yang sudah diautentikasi
|
|
||||||
claims, err := middleware.GetUserFromContext(c)
|
claims, err := middleware.GetUserFromContext(c)
|
||||||
if err != nil {
|
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
|
var req RequestPinDTO
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
return utils.BadRequest(c, "Invalid request body")
|
return utils.BadRequest(c, "Invalid request body")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validasi request PIN
|
|
||||||
if errs, ok := req.ValidateRequestPinDTO(); !ok {
|
if errs, ok := req.ValidateRequestPinDTO(); !ok {
|
||||||
return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Validation error", errs)
|
return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Validation error", errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panggil service untuk membuat PIN
|
pintokenresponse, err := h.service.CreateUserPin(c.Context(), claims.UserID, claims.DeviceID, &req)
|
||||||
err = h.service.CreateUserPin(c.Context(), claims.UserID, &req)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() == "PIN already created" {
|
if err.Error() == Pinhasbeencreated {
|
||||||
return utils.BadRequest(c, err.Error()) // Jika PIN sudah ada, kembalikan error 400
|
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.SuccessWithData(c, "PIN created successfully", pintokenresponse)
|
||||||
return utils.Success(c, "PIN created successfully")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *UserPinHandler) VerifyPinHandler(c *fiber.Ctx) error {
|
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)
|
claims, err := middleware.GetUserFromContext(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -66,12 +58,10 @@ func (h *UserPinHandler) VerifyPinHandler(c *fiber.Ctx) error {
|
||||||
return utils.BadRequest(c, "Invalid request body")
|
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 {
|
if err != nil {
|
||||||
return utils.BadRequest(c, err.Error())
|
return utils.BadRequest(c, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils.SuccessWithData(c, "PIN verified successfully", fiber.Map{
|
return utils.SuccessWithData(c, "PIN verified successfully", token)
|
||||||
"token": token,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package userpin
|
||||||
import (
|
import (
|
||||||
"rijig/config"
|
"rijig/config"
|
||||||
"rijig/internal/authentication"
|
"rijig/internal/authentication"
|
||||||
|
"rijig/internal/userprofile"
|
||||||
"rijig/middleware"
|
"rijig/middleware"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
@ -11,8 +12,9 @@ import (
|
||||||
func UsersPinRoute(api fiber.Router) {
|
func UsersPinRoute(api fiber.Router) {
|
||||||
userPinRepo := NewUserPinRepository(config.DB)
|
userPinRepo := NewUserPinRepository(config.DB)
|
||||||
authRepo := authentication.NewAuthenticationRepository(config.DB)
|
authRepo := authentication.NewAuthenticationRepository(config.DB)
|
||||||
|
userprofileRepo := userprofile.NewUserProfileRepository(config.DB)
|
||||||
|
|
||||||
userPinService := NewUserPinService(userPinRepo, authRepo)
|
userPinService := NewUserPinService(userPinRepo, authRepo, userprofileRepo)
|
||||||
|
|
||||||
userPinHandler := NewUserPinHandler(userPinService)
|
userPinHandler := NewUserPinHandler(userPinService)
|
||||||
|
|
||||||
|
|
|
@ -2,45 +2,51 @@ package userpin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"rijig/internal/authentication"
|
"rijig/internal/authentication"
|
||||||
|
"rijig/internal/userprofile"
|
||||||
"rijig/model"
|
"rijig/model"
|
||||||
"rijig/utils"
|
"rijig/utils"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserPinService interface {
|
type UserPinService interface {
|
||||||
CreateUserPin(ctx context.Context, userID string, dto *RequestPinDTO) error
|
CreateUserPin(ctx context.Context, userID, deviceId string, dto *RequestPinDTO) (*authentication.AuthResponse, error)
|
||||||
VerifyUserPin(ctx context.Context, userID string, pin *RequestPinDTO) (*utils.TokenResponse, error)
|
VerifyUserPin(ctx context.Context, userID, deviceID string, pin *RequestPinDTO) (*utils.TokenResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type userPinService struct {
|
type userPinService struct {
|
||||||
UserPinRepo UserPinRepository
|
UserPinRepo UserPinRepository
|
||||||
authRepo authentication.AuthenticationRepository
|
authRepo authentication.AuthenticationRepository
|
||||||
|
userProfileRepo userprofile.UserProfileRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUserPinService(UserPinRepo UserPinRepository,
|
func NewUserPinService(UserPinRepo UserPinRepository,
|
||||||
authRepo authentication.AuthenticationRepository) UserPinService {
|
authRepo authentication.AuthenticationRepository,
|
||||||
return &userPinService{UserPinRepo, authRepo}
|
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 {
|
func (s *userPinService) CreateUserPin(ctx context.Context, userID, deviceId string, dto *RequestPinDTO) (*authentication.AuthResponse, error) {
|
||||||
return fmt.Errorf("validation error: %v", errs)
|
|
||||||
}
|
|
||||||
|
|
||||||
existingPin, err := s.UserPinRepo.FindByUserID(ctx, userID)
|
_, err := s.UserPinRepo.FindByUserID(ctx, userID)
|
||||||
if err != nil {
|
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)
|
hashed, err := utils.HashingPlainText(dto.Pin)
|
||||||
if err != nil {
|
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{
|
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 {
|
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")
|
||||||
|
|
||||||
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,
|
|
||||||
"registration_status": utils.RegStatusComplete,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to update user progress: %w", err)
|
|
||||||
}
|
}
|
||||||
|
return nil, fmt.Errorf("failed to create pin: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
updates := map[string]interface{}{
|
||||||
|
"registration_progress": utils.ProgressComplete,
|
||||||
|
"registration_status": utils.RegStatusComplete,
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
user, err := s.authRepo.FindUserByID(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("user not found")
|
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)
|
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
|
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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"rijig/model"
|
"rijig/model"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AuthenticationRepository interface {
|
type UserProfileRepository interface {
|
||||||
UpdateUser(ctx context.Context, user *model.User) error
|
GetByID(ctx context.Context, userID string) (*model.User, error)
|
||||||
PatchUser(ctx context.Context, userID string, updates map[string]interface{}) 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
|
db *gorm.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAuthenticationRepository(db *gorm.DB) AuthenticationRepository {
|
func NewUserProfileRepository(db *gorm.DB) UserProfileRepository {
|
||||||
return &authenticationRepository{db}
|
return &userProfileRepository{
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *authenticationRepository) UpdateUser(ctx context.Context, user *model.User) error {
|
func (r *userProfileRepository) GetByID(ctx context.Context, userID string) (*model.User, error) {
|
||||||
return r.db.WithContext(ctx).
|
var user model.User
|
||||||
Model(&model.User{}).
|
|
||||||
Where("id = ?", user.ID).
|
err := r.db.WithContext(ctx).
|
||||||
Updates(user).Error
|
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 {
|
func (r *userProfileRepository) GetByRoleName(ctx context.Context, roleName string) ([]*model.User, error) {
|
||||||
return r.db.WithContext(ctx).
|
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{}).
|
Model(&model.User{}).
|
||||||
Where("id = ?", userID).
|
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
|
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
|
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
|
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
|
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"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"rijig/dto"
|
|
||||||
"rijig/model"
|
"rijig/model"
|
||||||
"rijig/utils"
|
"rijig/utils"
|
||||||
)
|
)
|
||||||
|
@ -13,17 +12,17 @@ import (
|
||||||
type WilayahIndonesiaService interface {
|
type WilayahIndonesiaService interface {
|
||||||
ImportDataFromCSV(ctx context.Context) error
|
ImportDataFromCSV(ctx context.Context) error
|
||||||
|
|
||||||
GetAllProvinces(ctx context.Context, 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) (*dto.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)
|
GetAllRegencies(ctx context.Context, page, limit int) ([]RegencyResponseDTO, int, error)
|
||||||
GetRegencyByID(ctx context.Context, id string, page, limit int) (*dto.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)
|
GetAllDistricts(ctx context.Context, page, limit int) ([]DistrictResponseDTO, int, error)
|
||||||
GetDistrictByID(ctx context.Context, id string, page, limit int) (*dto.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)
|
GetAllVillages(ctx context.Context, page, limit int) ([]VillageResponseDTO, int, error)
|
||||||
GetVillageByID(ctx context.Context, id string) (*dto.VillageResponseDTO, error)
|
GetVillageByID(ctx context.Context, id string) (*VillageResponseDTO, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type wilayahIndonesiaService struct {
|
type wilayahIndonesiaService struct {
|
||||||
|
@ -122,11 +121,11 @@ func (s *wilayahIndonesiaService) ImportDataFromCSV(ctx context.Context) error {
|
||||||
return nil
|
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)
|
cacheKey := fmt.Sprintf("provinces_page:%d_limit:%d", page, limit)
|
||||||
|
|
||||||
var cachedResponse struct {
|
var cachedResponse struct {
|
||||||
Data []dto.ProvinceResponseDTO `json:"data"`
|
Data []ProvinceResponseDTO `json:"data"`
|
||||||
Total int `json:"total"`
|
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)
|
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 {
|
for i, province := range provinces {
|
||||||
provinceDTOs[i] = dto.ProvinceResponseDTO{
|
provinceDTOs[i] = ProvinceResponseDTO{
|
||||||
ID: province.ID,
|
ID: province.ID,
|
||||||
Name: province.Name,
|
Name: province.Name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheData := struct {
|
cacheData := struct {
|
||||||
Data []dto.ProvinceResponseDTO `json:"data"`
|
Data []ProvinceResponseDTO `json:"data"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
}{
|
}{
|
||||||
Data: provinceDTOs,
|
Data: provinceDTOs,
|
||||||
|
@ -162,11 +161,11 @@ func (s *wilayahIndonesiaService) GetAllProvinces(ctx context.Context, page, lim
|
||||||
return provinceDTOs, total, nil
|
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)
|
cacheKey := fmt.Sprintf("province:%s_page:%d_limit:%d", id, page, limit)
|
||||||
|
|
||||||
var cachedResponse struct {
|
var cachedResponse struct {
|
||||||
Data dto.ProvinceResponseDTO `json:"data"`
|
Data ProvinceResponseDTO `json:"data"`
|
||||||
TotalRegencies int `json:"total_regencies"`
|
TotalRegencies int `json:"total_regencies"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,14 +178,14 @@ func (s *wilayahIndonesiaService) GetProvinceByID(ctx context.Context, id string
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
provinceDTO := dto.ProvinceResponseDTO{
|
provinceDTO := ProvinceResponseDTO{
|
||||||
ID: province.ID,
|
ID: province.ID,
|
||||||
Name: province.Name,
|
Name: province.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
regencyDTOs := make([]dto.RegencyResponseDTO, len(province.Regencies))
|
regencyDTOs := make([]RegencyResponseDTO, len(province.Regencies))
|
||||||
for i, regency := range province.Regencies {
|
for i, regency := range province.Regencies {
|
||||||
regencyDTOs[i] = dto.RegencyResponseDTO{
|
regencyDTOs[i] = RegencyResponseDTO{
|
||||||
ID: regency.ID,
|
ID: regency.ID,
|
||||||
ProvinceID: regency.ProvinceID,
|
ProvinceID: regency.ProvinceID,
|
||||||
Name: regency.Name,
|
Name: regency.Name,
|
||||||
|
@ -195,7 +194,7 @@ func (s *wilayahIndonesiaService) GetProvinceByID(ctx context.Context, id string
|
||||||
provinceDTO.Regencies = regencyDTOs
|
provinceDTO.Regencies = regencyDTOs
|
||||||
|
|
||||||
cacheData := struct {
|
cacheData := struct {
|
||||||
Data dto.ProvinceResponseDTO `json:"data"`
|
Data ProvinceResponseDTO `json:"data"`
|
||||||
TotalRegencies int `json:"total_regencies"`
|
TotalRegencies int `json:"total_regencies"`
|
||||||
}{
|
}{
|
||||||
Data: provinceDTO,
|
Data: provinceDTO,
|
||||||
|
@ -209,11 +208,11 @@ func (s *wilayahIndonesiaService) GetProvinceByID(ctx context.Context, id string
|
||||||
return &provinceDTO, totalRegencies, nil
|
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)
|
cacheKey := fmt.Sprintf("regencies_page:%d_limit:%d", page, limit)
|
||||||
|
|
||||||
var cachedResponse struct {
|
var cachedResponse struct {
|
||||||
Data []dto.RegencyResponseDTO `json:"data"`
|
Data []RegencyResponseDTO `json:"data"`
|
||||||
Total int `json:"total"`
|
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)
|
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 {
|
for i, regency := range regencies {
|
||||||
regencyDTOs[i] = dto.RegencyResponseDTO{
|
regencyDTOs[i] = RegencyResponseDTO{
|
||||||
ID: regency.ID,
|
ID: regency.ID,
|
||||||
ProvinceID: regency.ProvinceID,
|
ProvinceID: regency.ProvinceID,
|
||||||
Name: regency.Name,
|
Name: regency.Name,
|
||||||
|
@ -236,7 +235,7 @@ func (s *wilayahIndonesiaService) GetAllRegencies(ctx context.Context, page, lim
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheData := struct {
|
cacheData := struct {
|
||||||
Data []dto.RegencyResponseDTO `json:"data"`
|
Data []RegencyResponseDTO `json:"data"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
}{
|
}{
|
||||||
Data: regencyDTOs,
|
Data: regencyDTOs,
|
||||||
|
@ -250,11 +249,11 @@ func (s *wilayahIndonesiaService) GetAllRegencies(ctx context.Context, page, lim
|
||||||
return regencyDTOs, total, nil
|
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)
|
cacheKey := fmt.Sprintf("regency:%s_page:%d_limit:%d", id, page, limit)
|
||||||
|
|
||||||
var cachedResponse struct {
|
var cachedResponse struct {
|
||||||
Data dto.RegencyResponseDTO `json:"data"`
|
Data RegencyResponseDTO `json:"data"`
|
||||||
TotalDistricts int `json:"total_districts"`
|
TotalDistricts int `json:"total_districts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,15 +266,15 @@ func (s *wilayahIndonesiaService) GetRegencyByID(ctx context.Context, id string,
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
regencyDTO := dto.RegencyResponseDTO{
|
regencyDTO := RegencyResponseDTO{
|
||||||
ID: regency.ID,
|
ID: regency.ID,
|
||||||
ProvinceID: regency.ProvinceID,
|
ProvinceID: regency.ProvinceID,
|
||||||
Name: regency.Name,
|
Name: regency.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
districtDTOs := make([]dto.DistrictResponseDTO, len(regency.Districts))
|
districtDTOs := make([]DistrictResponseDTO, len(regency.Districts))
|
||||||
for i, district := range regency.Districts {
|
for i, district := range regency.Districts {
|
||||||
districtDTOs[i] = dto.DistrictResponseDTO{
|
districtDTOs[i] = DistrictResponseDTO{
|
||||||
ID: district.ID,
|
ID: district.ID,
|
||||||
RegencyID: district.RegencyID,
|
RegencyID: district.RegencyID,
|
||||||
Name: district.Name,
|
Name: district.Name,
|
||||||
|
@ -284,7 +283,7 @@ func (s *wilayahIndonesiaService) GetRegencyByID(ctx context.Context, id string,
|
||||||
regencyDTO.Districts = districtDTOs
|
regencyDTO.Districts = districtDTOs
|
||||||
|
|
||||||
cacheData := struct {
|
cacheData := struct {
|
||||||
Data dto.RegencyResponseDTO `json:"data"`
|
Data RegencyResponseDTO `json:"data"`
|
||||||
TotalDistricts int `json:"total_districts"`
|
TotalDistricts int `json:"total_districts"`
|
||||||
}{
|
}{
|
||||||
Data: regencyDTO,
|
Data: regencyDTO,
|
||||||
|
@ -298,11 +297,11 @@ func (s *wilayahIndonesiaService) GetRegencyByID(ctx context.Context, id string,
|
||||||
return ®encyDTO, totalDistricts, nil
|
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)
|
cacheKey := fmt.Sprintf("districts_page:%d_limit:%d", page, limit)
|
||||||
|
|
||||||
var cachedResponse struct {
|
var cachedResponse struct {
|
||||||
Data []dto.DistrictResponseDTO `json:"data"`
|
Data []DistrictResponseDTO `json:"data"`
|
||||||
Total int `json:"total"`
|
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)
|
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 {
|
for i, district := range districts {
|
||||||
districtDTOs[i] = dto.DistrictResponseDTO{
|
districtDTOs[i] = DistrictResponseDTO{
|
||||||
ID: district.ID,
|
ID: district.ID,
|
||||||
RegencyID: district.RegencyID,
|
RegencyID: district.RegencyID,
|
||||||
Name: district.Name,
|
Name: district.Name,
|
||||||
|
@ -325,7 +324,7 @@ func (s *wilayahIndonesiaService) GetAllDistricts(ctx context.Context, page, lim
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheData := struct {
|
cacheData := struct {
|
||||||
Data []dto.DistrictResponseDTO `json:"data"`
|
Data []DistrictResponseDTO `json:"data"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
}{
|
}{
|
||||||
Data: districtDTOs,
|
Data: districtDTOs,
|
||||||
|
@ -339,11 +338,11 @@ func (s *wilayahIndonesiaService) GetAllDistricts(ctx context.Context, page, lim
|
||||||
return districtDTOs, total, nil
|
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)
|
cacheKey := fmt.Sprintf("district:%s_page:%d_limit:%d", id, page, limit)
|
||||||
|
|
||||||
var cachedResponse struct {
|
var cachedResponse struct {
|
||||||
Data dto.DistrictResponseDTO `json:"data"`
|
Data DistrictResponseDTO `json:"data"`
|
||||||
TotalVillages int `json:"total_villages"`
|
TotalVillages int `json:"total_villages"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,15 +355,15 @@ func (s *wilayahIndonesiaService) GetDistrictByID(ctx context.Context, id string
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
districtDTO := dto.DistrictResponseDTO{
|
districtDTO := DistrictResponseDTO{
|
||||||
ID: district.ID,
|
ID: district.ID,
|
||||||
RegencyID: district.RegencyID,
|
RegencyID: district.RegencyID,
|
||||||
Name: district.Name,
|
Name: district.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
villageDTOs := make([]dto.VillageResponseDTO, len(district.Villages))
|
villageDTOs := make([]VillageResponseDTO, len(district.Villages))
|
||||||
for i, village := range district.Villages {
|
for i, village := range district.Villages {
|
||||||
villageDTOs[i] = dto.VillageResponseDTO{
|
villageDTOs[i] = VillageResponseDTO{
|
||||||
ID: village.ID,
|
ID: village.ID,
|
||||||
DistrictID: village.DistrictID,
|
DistrictID: village.DistrictID,
|
||||||
Name: village.Name,
|
Name: village.Name,
|
||||||
|
@ -373,7 +372,7 @@ func (s *wilayahIndonesiaService) GetDistrictByID(ctx context.Context, id string
|
||||||
districtDTO.Villages = villageDTOs
|
districtDTO.Villages = villageDTOs
|
||||||
|
|
||||||
cacheData := struct {
|
cacheData := struct {
|
||||||
Data dto.DistrictResponseDTO `json:"data"`
|
Data DistrictResponseDTO `json:"data"`
|
||||||
TotalVillages int `json:"total_villages"`
|
TotalVillages int `json:"total_villages"`
|
||||||
}{
|
}{
|
||||||
Data: districtDTO,
|
Data: districtDTO,
|
||||||
|
@ -387,11 +386,11 @@ func (s *wilayahIndonesiaService) GetDistrictByID(ctx context.Context, id string
|
||||||
return &districtDTO, totalVillages, nil
|
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)
|
cacheKey := fmt.Sprintf("villages_page:%d_limit:%d", page, limit)
|
||||||
|
|
||||||
var cachedResponse struct {
|
var cachedResponse struct {
|
||||||
Data []dto.VillageResponseDTO `json:"data"`
|
Data []VillageResponseDTO `json:"data"`
|
||||||
Total int `json:"total"`
|
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)
|
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 {
|
for i, village := range villages {
|
||||||
villageDTOs[i] = dto.VillageResponseDTO{
|
villageDTOs[i] = VillageResponseDTO{
|
||||||
ID: village.ID,
|
ID: village.ID,
|
||||||
DistrictID: village.DistrictID,
|
DistrictID: village.DistrictID,
|
||||||
Name: village.Name,
|
Name: village.Name,
|
||||||
|
@ -414,7 +413,7 @@ func (s *wilayahIndonesiaService) GetAllVillages(ctx context.Context, page, limi
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheData := struct {
|
cacheData := struct {
|
||||||
Data []dto.VillageResponseDTO `json:"data"`
|
Data []VillageResponseDTO `json:"data"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
}{
|
}{
|
||||||
Data: villageDTOs,
|
Data: villageDTOs,
|
||||||
|
@ -428,10 +427,10 @@ func (s *wilayahIndonesiaService) GetAllVillages(ctx context.Context, page, limi
|
||||||
return villageDTOs, total, nil
|
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)
|
cacheKey := fmt.Sprintf("village:%s", id)
|
||||||
|
|
||||||
var cachedResponse dto.VillageResponseDTO
|
var cachedResponse VillageResponseDTO
|
||||||
if err := utils.GetCache(cacheKey, &cachedResponse); err == nil {
|
if err := utils.GetCache(cacheKey, &cachedResponse); err == nil {
|
||||||
return &cachedResponse, 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)
|
return nil, fmt.Errorf("village not found: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
villageResponse := &dto.VillageResponseDTO{
|
villageResponse := &VillageResponseDTO{
|
||||||
ID: village.ID,
|
ID: village.ID,
|
||||||
DistrictID: village.DistrictID,
|
DistrictID: village.DistrictID,
|
||||||
Name: village.Name,
|
Name: village.Name,
|
||||||
|
|
|
@ -7,6 +7,7 @@ type IdentityCard struct {
|
||||||
UserID string `gorm:"not null" json:"userId"`
|
UserID string `gorm:"not null" json:"userId"`
|
||||||
User User `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"user"`
|
User User `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"user"`
|
||||||
Identificationumber string `gorm:"not null" json:"identificationumber"`
|
Identificationumber string `gorm:"not null" json:"identificationumber"`
|
||||||
|
Fullname string `gorm:"not null" json:"fullname"`
|
||||||
Placeofbirth string `gorm:"not null" json:"placeofbirth"`
|
Placeofbirth string `gorm:"not null" json:"placeofbirth"`
|
||||||
Dateofbirth string `gorm:"not null" json:"dateofbirth"`
|
Dateofbirth string `gorm:"not null" json:"dateofbirth"`
|
||||||
Gender string `gorm:"not null" json:"gender"`
|
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/identitycart"
|
||||||
"rijig/internal/role"
|
"rijig/internal/role"
|
||||||
"rijig/internal/userpin"
|
"rijig/internal/userpin"
|
||||||
|
"rijig/internal/userprofile"
|
||||||
"rijig/internal/whatsapp"
|
"rijig/internal/whatsapp"
|
||||||
|
"rijig/internal/wilayahindo"
|
||||||
"rijig/middleware"
|
"rijig/middleware"
|
||||||
|
|
||||||
// "rijig/presentation"
|
// "rijig/presentation"
|
||||||
|
@ -19,8 +21,9 @@ import (
|
||||||
|
|
||||||
func SetupRoutes(app *fiber.App) {
|
func SetupRoutes(app *fiber.App) {
|
||||||
apa := app.Group(os.Getenv("BASE_URL"))
|
apa := app.Group(os.Getenv("BASE_URL"))
|
||||||
whatsapp.WhatsAppRouter(apa)
|
|
||||||
apa.Static("/uploads", "./public"+os.Getenv("BASE_URL")+"/uploads")
|
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 := app.Group(os.Getenv("BASE_URL"))
|
||||||
api.Use(middleware.APIKeyMiddleware)
|
api.Use(middleware.APIKeyMiddleware)
|
||||||
|
@ -32,6 +35,8 @@ func SetupRoutes(app *fiber.App) {
|
||||||
role.UserRoleRouter(api)
|
role.UserRoleRouter(api)
|
||||||
|
|
||||||
article.ArticleRouter(api)
|
article.ArticleRouter(api)
|
||||||
|
userprofile.UserProfileRouter(api)
|
||||||
|
wilayahindo.WilayahRouter(api)
|
||||||
|
|
||||||
// || auth router || //
|
// || auth router || //
|
||||||
// presentation.AuthRouter(api)
|
// presentation.AuthRouter(api)
|
||||||
|
@ -58,5 +63,4 @@ func SetupRoutes(app *fiber.App) {
|
||||||
// // presentation.AboutRouter(api)
|
// // presentation.AboutRouter(api)
|
||||||
// presentation.TrashRouter(api)
|
// presentation.TrashRouter(api)
|
||||||
// presentation.CoverageAreaRouter(api)
|
// presentation.CoverageAreaRouter(api)
|
||||||
whatsapp.WhatsAppRouter(api)
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue