Files
base/internal/application/profile/service.go
2026-04-10 18:25:21 +03:30

316 lines
8.2 KiB
Go

package profile
import (
"context"
"github.com/google/uuid"
"github.com/rs/zerolog"
"github.com/samber/lo"
"go.uber.org/fx"
"base/internal/domain/profile"
"base/internal/dto"
)
type Service interface {
Create(ctx context.Context, req dto.CreateProfileRequest) (*dto.ProfileResponse, error)
Update(ctx context.Context, req dto.UpdateProfileRequest) (*dto.ProfileResponse, error)
GetByID(ctx context.Context, id uuid.UUID) (*dto.ProfileResponse, error)
GetByHandle(ctx context.Context, handle string) (*dto.ProfileResponse, error)
List(ctx context.Context, req dto.ListProfilesRequest) (*dto.ListProfilesResponse, error)
Delete(ctx context.Context, id uuid.UUID) error
}
type service struct {
logger zerolog.Logger
profileRepo profile.Repository
}
type Param struct {
Logger zerolog.Logger
ProfileRepo profile.Repository
fx.In
}
func New(param Param) Service {
return &service{
logger: param.Logger,
profileRepo: param.ProfileRepo,
}
}
func (s *service) Create(ctx context.Context, req dto.CreateProfileRequest) (*dto.ProfileResponse, error) {
domainProfile := &profile.Profile{
ID: uuid.New(),
Handle: req.Handle,
PageSectionOrder: req.PageSectionOrder,
Hero: profile.Hero{
Role: &profile.Role{
ID: lo.FromPtr(req.Hero.RoleID),
Level: req.Hero.RoleLevel,
},
FirstName: req.Hero.FirstName,
LastName: req.Hero.LastName,
Company: req.Hero.Company,
ShortDescription: req.Hero.ShortDescription,
ResumeLink: req.Hero.ResumeLink,
CTAEnabled: req.Hero.CTAEnabled,
Avatar: req.Hero.Avatar,
},
About: profile.About{
ProfilePicture: req.About.ProfilePicture,
About: req.About.About,
},
Contact: profile.Contact{
Email: req.Contact.Email,
Phone: req.Contact.Phone,
},
PageSetting: profile.PageSetting{
VisibilityLevel: req.PageSetting.VisibilityLevel,
},
}
if req.Hero.RoleID != nil {
domainProfile.Hero.Role = &profile.Role{
ID: *req.Hero.RoleID,
}
}
for _, skill := range req.Skills {
domainProfile.Skills = append(domainProfile.Skills, profile.Skill{
SkillName: skill.SkillName,
Level: skill.Level,
})
}
for _, achievement := range req.About.Achievements {
domainProfile.About.Achievements = append(domainProfile.About.Achievements, profile.Achievement{
Title: achievement.Title,
Value: achievement.Value,
Enabled: achievement.Enabled,
})
}
for _, socialLink := range req.Contact.SocialLinks {
domainProfile.Contact.SocialLinks = append(domainProfile.Contact.SocialLinks, profile.SocialLink{
LinkType: socialLink.LinkType,
Link: socialLink.Link,
})
}
if err := s.profileRepo.Create(ctx, domainProfile); err != nil {
return nil, err
}
return s.toProfileResponse(domainProfile), nil
}
func (s *service) Update(ctx context.Context, req dto.UpdateProfileRequest) (*dto.ProfileResponse, error) {
id, err := uuid.Parse(req.ID)
if err != nil {
return nil, profile.ErrProfileNotFound
}
// First, get the existing profile to ensure it exists
existingProfile, err := s.profileRepo.FindByID(ctx, id)
if err != nil {
return nil, profile.ErrProfileNotFound
}
domainProfile := &profile.Profile{
ID: id,
Handle: req.Handle,
PageSectionOrder: req.PageSectionOrder,
Hero: profile.Hero{
FirstName: req.Hero.FirstName,
Role: &profile.Role{
ID: lo.FromPtr(req.Hero.RoleID),
Level: req.Hero.RoleLevel,
},
LastName: req.Hero.LastName,
Company: req.Hero.Company,
ShortDescription: req.Hero.ShortDescription,
ResumeLink: req.Hero.ResumeLink,
CTAEnabled: req.Hero.CTAEnabled,
Avatar: req.Hero.Avatar,
},
About: profile.About{
ProfilePicture: req.About.ProfilePicture,
About: req.About.About,
},
Contact: profile.Contact{
Email: req.Contact.Email,
Phone: req.Contact.Phone,
},
PageSetting: profile.PageSetting{
VisibilityLevel: req.PageSetting.VisibilityLevel,
},
}
if req.Hero.RoleID != nil {
domainProfile.Hero.Role = &profile.Role{
ID: *req.Hero.RoleID,
}
} else if existingProfile != nil && existingProfile.Hero.Role != nil {
domainProfile.Hero.Role = existingProfile.Hero.Role
}
if req.Hero.RoleLevel == "" && existingProfile != nil {
domainProfile.Hero.Role.Level = existingProfile.Hero.Role.Level
}
for _, skill := range req.Skills {
domainProfile.Skills = append(domainProfile.Skills, profile.Skill{
SkillName: skill.SkillName,
Level: skill.Level,
})
}
for _, achievement := range req.About.Achievements {
domainProfile.About.Achievements = append(domainProfile.About.Achievements, profile.Achievement{
Title: achievement.Title,
Value: achievement.Value,
Enabled: achievement.Enabled,
})
}
for _, socialLink := range req.Contact.SocialLinks {
domainProfile.Contact.SocialLinks = append(domainProfile.Contact.SocialLinks, profile.SocialLink{
LinkType: socialLink.LinkType,
Link: socialLink.Link,
})
}
if err := s.profileRepo.Update(ctx, domainProfile); err != nil {
return nil, err
}
return s.toProfileResponse(domainProfile), nil
}
func (s *service) GetByID(ctx context.Context, id uuid.UUID) (*dto.ProfileResponse, error) {
profileData, err := s.profileRepo.FindByID(ctx, id)
if err != nil {
return nil, profile.ErrProfileNotFound
}
return s.toProfileResponse(profileData), nil
}
func (s *service) GetByHandle(ctx context.Context, handle string) (*dto.ProfileResponse, error) {
profileData, err := s.profileRepo.FindByHandle(ctx, handle)
if err != nil {
return nil, profile.ErrProfileNotFound
}
return s.toProfileResponse(profileData), nil
}
func (s *service) List(ctx context.Context, req dto.ListProfilesRequest) (*dto.ListProfilesResponse, error) {
filter := profile.Filter{
FirstName: req.FirstName,
LastName: req.LastName,
Company: req.Company,
SkillName: req.SkillName,
Page: req.Page,
PageSize: req.PageSize,
SortedBy: req.SortedBy,
Ascending: req.Ascending,
}
if req.Page == 0 {
filter.Page = 1
}
if req.PageSize == 0 {
filter.PageSize = 10
}
if req.RoleID != nil {
filter.RoleID = *req.RoleID
}
profiles, total, err := s.profileRepo.FindAll(ctx, filter)
if err != nil {
return nil, err
}
response := &dto.ListProfilesResponse{
Profiles: make([]dto.ProfileResponse, len(profiles)),
Total: total,
Page: filter.Page,
PageSize: filter.PageSize,
}
for i, p := range profiles {
response.Profiles[i] = *s.toProfileResponse(p)
}
return response, nil
}
func (s *service) Delete(ctx context.Context, id uuid.UUID) error {
// Get profile first to ensure it exists
profileData, err := s.profileRepo.FindByID(ctx, id)
if err != nil {
return profile.ErrProfileNotFound
}
return s.profileRepo.Delete(ctx, profileData)
}
func (s *service) toProfileResponse(p *profile.Profile) *dto.ProfileResponse {
resp := &dto.ProfileResponse{
ID: p.ID,
Handle: p.Handle,
PageSectionOrder: p.PageSectionOrder,
Hero: dto.HeroDTO{
FirstName: p.Hero.FirstName,
LastName: p.Hero.LastName,
Company: p.Hero.Company,
ShortDescription: p.Hero.ShortDescription,
ResumeLink: p.Hero.ResumeLink,
CTAEnabled: p.Hero.CTAEnabled,
Avatar: p.Hero.Avatar,
},
About: dto.AboutDTO{
ProfilePicture: p.About.ProfilePicture,
About: p.About.About,
},
Contact: dto.ContactDTO{
Email: p.Contact.Email,
Phone: p.Contact.Phone,
},
PageSetting: dto.PageSettingDTO{
VisibilityLevel: p.PageSetting.VisibilityLevel,
},
}
if p.Hero.Role != nil {
resp.Hero.RoleID = &p.Hero.Role.ID
}
for _, skill := range p.Skills {
resp.Skills = append(resp.Skills, dto.SkillDTO{
SkillName: skill.SkillName,
Level: skill.Level,
})
}
for _, achievement := range p.About.Achievements {
resp.About.Achievements = append(resp.About.Achievements, dto.AchievementDTO{
Title: achievement.Title,
Value: achievement.Value,
Enabled: achievement.Enabled,
})
}
for _, socialLink := range p.Contact.SocialLinks {
resp.Contact.SocialLinks = append(resp.Contact.SocialLinks, dto.SocialLinkDTO{
LinkType: socialLink.LinkType,
Link: socialLink.Link,
})
}
return resp
}