1
This commit is contained in:
467
internal/request_model/vacancy.go
Normal file
467
internal/request_model/vacancy.go
Normal file
@@ -0,0 +1,467 @@
|
||||
package requestmodel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"git-molva.ru/Molva/molva-backend/services/api_gateway/internal/constants"
|
||||
dbtypes "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/database/types"
|
||||
)
|
||||
|
||||
type VacancyStatus string
|
||||
|
||||
const (
|
||||
VacUnspecified VacancyStatus = "unspecified"
|
||||
VacNew VacancyStatus = "new"
|
||||
VacPending VacancyStatus = "pending"
|
||||
VacApproved VacancyStatus = "approved"
|
||||
VacRejected VacancyStatus = "rejected"
|
||||
)
|
||||
|
||||
func (s *VacancyStatus) NullString() *string {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return (*string)(s)
|
||||
}
|
||||
|
||||
type (
|
||||
// TODO: remove extra fields for agent
|
||||
Vacancy struct {
|
||||
Id string `json:"id"`
|
||||
Company VacancyCompanyInfo `json:"company"`
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
WorkFormat string `json:"work_format"`
|
||||
AgentReward *int32 `json:"agent_reward"`
|
||||
SalaryTop int32 `json:"salary_top"`
|
||||
SalaryBottom int32 `json:"salary_bottom"`
|
||||
Requirements *string `json:"requirements"`
|
||||
Responsibilities *string `json:"responsibilities"`
|
||||
ExtraInfo *string `json:"extra_info"`
|
||||
Region string `json:"region"`
|
||||
IsArchived bool `json:"is_archived"`
|
||||
TargetAction VacancyTargetAction `json:"target_action"`
|
||||
Moderation VacancyModeration `json:"moderation"`
|
||||
RequiredCandidates int32 `json:"required_candidates"`
|
||||
CurrentCandidates int32 `json:"current_candidates"`
|
||||
ExtraFields *string `json:"extra_fields"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
VacancyCompanyInfo struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
LogoLink *string `json:"logo_link"`
|
||||
}
|
||||
|
||||
VacancyTargetAction struct {
|
||||
Action string `json:"action"`
|
||||
Duration int32 `json:"duration"`
|
||||
}
|
||||
|
||||
VacancyModeration struct {
|
||||
Status VacancyStatus `json:"status"`
|
||||
DescriptionHistory []VacancyModerationDescription `json:"description_history"`
|
||||
}
|
||||
|
||||
VacancyModerationDescription struct {
|
||||
Description *string `json:"description"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
)
|
||||
|
||||
func (m *VacancyModeration) From(msg *dbtypes.VacancyModeration) *VacancyModeration {
|
||||
if msg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := &VacancyModeration{
|
||||
Status: VacancyStatus(msg.Status),
|
||||
DescriptionHistory: make([]VacancyModerationDescription, len(msg.DescriptionHistory)),
|
||||
}
|
||||
|
||||
for i, desc := range msg.DescriptionHistory {
|
||||
res.DescriptionHistory[i] = VacancyModerationDescription{
|
||||
Description: desc.Description,
|
||||
CreatedAt: desc.CreatedAt.Format(time.DateOnly),
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (v *Vacancy) From(msg *dbtypes.Vacancy) *Vacancy {
|
||||
if msg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := &Vacancy{
|
||||
Id: msg.Id,
|
||||
Company: VacancyCompanyInfo{
|
||||
Id: msg.Company.Id,
|
||||
Name: msg.Company.Name,
|
||||
},
|
||||
Name: msg.Name,
|
||||
Address: msg.Address,
|
||||
WorkFormat: msg.WorkFormat,
|
||||
AgentReward: msg.AgentReward,
|
||||
SalaryTop: msg.SalaryTop,
|
||||
SalaryBottom: msg.SalaryBottom,
|
||||
Requirements: msg.Requirements,
|
||||
Responsibilities: msg.Responsibilities,
|
||||
ExtraInfo: msg.ExtraInfo,
|
||||
Region: msg.Region,
|
||||
IsArchived: msg.IsArchived,
|
||||
TargetAction: VacancyTargetAction{
|
||||
Action: msg.TargetAction.Action,
|
||||
Duration: msg.TargetAction.Duration,
|
||||
},
|
||||
Moderation: *new(VacancyModeration).From(&msg.Moderation),
|
||||
RequiredCandidates: msg.RequiredCandidates,
|
||||
CurrentCandidates: msg.CurrentCandidates,
|
||||
ExtraFields: msg.ExtraFields,
|
||||
CreatedAt: msg.CreatedAt.Format(time.DateOnly),
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
type (
|
||||
VacancyListGetRequest struct {
|
||||
Filters *VacancyListFilters
|
||||
Page uint64
|
||||
PageSize uint64
|
||||
}
|
||||
|
||||
VacancyListFilters struct {
|
||||
DistributorId *string
|
||||
CompanyId *string
|
||||
VacancyId *string
|
||||
Region *string
|
||||
SalaryBottom *int32
|
||||
SalaryTop *int32
|
||||
IsArchived *bool
|
||||
Status *VacancyStatus
|
||||
}
|
||||
|
||||
VacancyListGetResponse struct {
|
||||
Vacancies []Vacancy `json:"vacancies"`
|
||||
}
|
||||
)
|
||||
|
||||
func (f *VacancyListGetRequest) FromQuery(query url.Values) (*VacancyListGetRequest, error) {
|
||||
if query == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var filters VacancyListFilters
|
||||
|
||||
if val, ok := query["distributor_id"]; ok {
|
||||
filters.DistributorId = &val[0]
|
||||
}
|
||||
|
||||
if val, ok := query["company_id"]; ok {
|
||||
filters.CompanyId = &val[0]
|
||||
}
|
||||
|
||||
if val, ok := query["vacancy_id"]; ok {
|
||||
filters.VacancyId = &val[0]
|
||||
}
|
||||
|
||||
if val, ok := query["region"]; ok {
|
||||
filters.Region = &val[0]
|
||||
}
|
||||
|
||||
if val, ok := query["salary_bottom"]; ok {
|
||||
intVal, err := parseInt32(val[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid salary_bottom param: %w", err)
|
||||
}
|
||||
|
||||
filters.SalaryBottom = &intVal
|
||||
}
|
||||
|
||||
if val, ok := query["salary_top"]; ok {
|
||||
intVal, err := parseInt32(val[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid salary_top param: %w", err)
|
||||
}
|
||||
|
||||
filters.SalaryTop = &intVal
|
||||
}
|
||||
|
||||
if val, ok := query["is_archived"]; ok {
|
||||
flag := val[0] == "true" || val[0] == "1"
|
||||
filters.IsArchived = &flag
|
||||
}
|
||||
|
||||
if val, ok := query["status"]; ok {
|
||||
status := VacancyStatus(val[0])
|
||||
filters.Status = &status
|
||||
}
|
||||
|
||||
res := &VacancyListGetRequest{
|
||||
Filters: &filters,
|
||||
Page: constants.DefaultPaginationPage,
|
||||
PageSize: constants.DefaultPaginationPageSize,
|
||||
}
|
||||
|
||||
if val, ok := query["page"]; ok {
|
||||
intVal, err := parseUint64(val[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid page param: %w", err)
|
||||
}
|
||||
|
||||
res.Page = intVal
|
||||
}
|
||||
|
||||
if val, ok := query["page_size"]; ok {
|
||||
intVal, err := parseUint64(val[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid page_size param: %w", err)
|
||||
}
|
||||
|
||||
res.PageSize = intVal
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (r *VacancyListGetRequest) Validate() error {
|
||||
if r == nil {
|
||||
return fmt.Errorf("%w: request is nil", ErrValidation)
|
||||
}
|
||||
|
||||
if r.Filters != nil {
|
||||
if r.Filters.Status != nil && !(*r.Filters.Status == VacUnspecified ||
|
||||
*r.Filters.Status == VacNew ||
|
||||
*r.Filters.Status == VacPending ||
|
||||
*r.Filters.Status == VacApproved ||
|
||||
*r.Filters.Status == VacRejected) {
|
||||
return fmt.Errorf("%w: invalid status: %v", ErrValidation, *r.Filters.Status)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *VacancyListGetResponse) From(msg *dbtypes.VacancyListGetResponse) *VacancyListGetResponse {
|
||||
if msg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := &VacancyListGetResponse{
|
||||
Vacancies: make([]Vacancy, len(msg.Vacancies)),
|
||||
}
|
||||
|
||||
for i, vacancy := range msg.Vacancies {
|
||||
res.Vacancies[i] = *new(Vacancy).From(&vacancy)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
type (
|
||||
VacancyCreateRequest struct {
|
||||
CompanyId string `json:"company_id"`
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
WorkFormat string `json:"work_format"`
|
||||
AgentReward *int32 `json:"agent_reward"`
|
||||
SalaryTop int32 `json:"salary_top"`
|
||||
SalaryBottom int32 `json:"salary_bottom"`
|
||||
Requirements *string `json:"requirements"`
|
||||
Responsibilities *string `json:"responsibilities"`
|
||||
ExtraInfo *string `json:"extra_info"`
|
||||
Region string `json:"region"`
|
||||
TargetAction VacancyTargetAction `json:"target_action"`
|
||||
RequiredCandidates int32 `json:"required_candidates"`
|
||||
CurrentCandidates int32 `json:"current_candidates"`
|
||||
ExtraFields *string `json:"extra_fields"`
|
||||
}
|
||||
|
||||
VacancyCreateResponse struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
)
|
||||
|
||||
func (r *VacancyCreateRequest) Validate() error {
|
||||
if r == nil {
|
||||
return fmt.Errorf("%w: request is nil", ErrValidation)
|
||||
}
|
||||
|
||||
if r.CompanyId == "" {
|
||||
return fmt.Errorf("%w: CompanyID is required", ErrValidation)
|
||||
}
|
||||
|
||||
if r.Name == "" {
|
||||
return fmt.Errorf("%w: Name is required", ErrValidation)
|
||||
}
|
||||
|
||||
if r.Address == "" {
|
||||
return fmt.Errorf("%w: Address is required", ErrValidation)
|
||||
}
|
||||
|
||||
if r.WorkFormat == "" {
|
||||
return fmt.Errorf("%w: WorkFormat is required", ErrValidation)
|
||||
}
|
||||
|
||||
if r.Region == "" {
|
||||
return fmt.Errorf("%w: Region is required", ErrValidation)
|
||||
}
|
||||
|
||||
if r.TargetAction.Action == "" {
|
||||
return fmt.Errorf("%w: TargetAction.Action is required", ErrValidation)
|
||||
}
|
||||
|
||||
if r.TargetAction.Duration == 0 {
|
||||
return fmt.Errorf("%w: TargetAction.Duration is required", ErrValidation)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *VacancyCreateResponse) From(msg *dbtypes.VacancyCreateResponse) *VacancyCreateResponse {
|
||||
if msg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &VacancyCreateResponse{
|
||||
Id: msg.Id,
|
||||
}
|
||||
}
|
||||
|
||||
type (
|
||||
VacancyUpdateRequest struct {
|
||||
Id string
|
||||
Name *string `json:"name"`
|
||||
Address *string `json:"address"`
|
||||
WorkFormat *string `json:"work_format"`
|
||||
AgentReward *int32 `json:"agent_reward"`
|
||||
SalaryTop *int32 `json:"salary_top"`
|
||||
SalaryBottom *int32 `json:"salary_bottom"`
|
||||
Requirements *string `json:"requirements"`
|
||||
Responsibilities *string `json:"responsibilities"`
|
||||
ExtraInfo *string `json:"extra_info"`
|
||||
Region *string `json:"region"`
|
||||
TargetAction VacancyTargetActionForUpdate `json:"target_action"`
|
||||
RequiredCandidates *int32 `json:"required_candidates"`
|
||||
ExtraFields *string `json:"extra_fields"`
|
||||
}
|
||||
|
||||
VacancyTargetActionForUpdate struct {
|
||||
Action *string `json:"action"`
|
||||
Duration *int32 `json:"duration"`
|
||||
}
|
||||
|
||||
VacancyUpdateResponse struct {
|
||||
}
|
||||
)
|
||||
|
||||
func (r *VacancyUpdateRequest) Validate() error {
|
||||
if r == nil {
|
||||
return fmt.Errorf("%w: request is nil", ErrValidation)
|
||||
}
|
||||
|
||||
if r.Id == "" {
|
||||
return fmt.Errorf("%w: ID is required", ErrValidation)
|
||||
}
|
||||
|
||||
if r.Name == nil && r.Address == nil && r.WorkFormat == nil && r.AgentReward == nil &&
|
||||
r.SalaryTop == nil && r.SalaryBottom == nil && r.Requirements == nil && r.Responsibilities == nil &&
|
||||
r.ExtraInfo == nil && r.Region == nil && r.TargetAction.Action == nil && r.TargetAction.Duration == nil &&
|
||||
r.RequiredCandidates == nil && r.ExtraFields == nil {
|
||||
return fmt.Errorf("%w: nothing to update", ErrValidation)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *VacancyUpdateResponse) From(msg *dbtypes.VacancyUpdateResponse) *VacancyUpdateResponse {
|
||||
if msg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &VacancyUpdateResponse{}
|
||||
}
|
||||
|
||||
type (
|
||||
VacancyDeleteRequest struct {
|
||||
Id string
|
||||
}
|
||||
|
||||
VacancyDeleteResponse struct {
|
||||
}
|
||||
)
|
||||
|
||||
func (r *VacancyDeleteRequest) Validate() error {
|
||||
if r == nil {
|
||||
return fmt.Errorf("%w: request is nil", ErrValidation)
|
||||
}
|
||||
|
||||
if r.Id == "" {
|
||||
return fmt.Errorf("%w: ID is required", ErrValidation)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *VacancyDeleteResponse) From(msg *dbtypes.VacancyDeleteResponse) *VacancyDeleteResponse {
|
||||
if msg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &VacancyDeleteResponse{}
|
||||
}
|
||||
|
||||
type (
|
||||
SendVacancyToModerationRequest struct {
|
||||
Id string
|
||||
}
|
||||
|
||||
SendVacancyToModerationResponse struct {
|
||||
}
|
||||
)
|
||||
|
||||
func (r *SendVacancyToModerationRequest) Validate() error {
|
||||
if r == nil {
|
||||
return fmt.Errorf("%w: request is nil", ErrValidation)
|
||||
}
|
||||
|
||||
if r.Id == "" {
|
||||
return fmt.Errorf("%w: ID is required", ErrValidation)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseInt32(val string) (int32, error) {
|
||||
intVal, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Check overflow int32
|
||||
if intVal < int(math.MinInt32) || intVal > int(math.MaxInt32) {
|
||||
return 0, constants.ErrIntOutOfRange
|
||||
}
|
||||
|
||||
//nolint:gosec // ignore integer overflow check for Atoi conversion to int32
|
||||
int32Val := int32(intVal)
|
||||
|
||||
return int32Val, nil
|
||||
}
|
||||
|
||||
func parseUint64(val string) (uint64, error) {
|
||||
uintVal, err := strconv.ParseUint(val, 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return uintVal, nil
|
||||
}
|
Reference in New Issue
Block a user