package redmine import ( "fmt" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/integration/iface" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/integration/null" "gitea.neur0tx.site/Neur0toxine/vegapokerbot/internal/integration/redmine/api" "go.uber.org/zap" "regexp" "strconv" "strings" ) var issueNumberMatcher = regexp.MustCompile(`(?m)\/issues\/(\d+)`) var sprintNames = []string{"sprint", "спринт"} type Redmine struct { api *api.Client log *zap.SugaredLogger spFieldName string } func New(params map[string]interface{}, log *zap.SugaredLogger) iface.Integration { uri, ok := params["url"] if !ok { return null.New() } key, ok := params["key"] if !ok { return null.New() } uriString, ok := uri.(string) if !ok { return null.New() } keyString, ok := key.(string) if !ok { return null.New() } var spField string if spFieldName, ok := params["sp_field"]; ok { if strField, ok := spFieldName.(string); ok { spField = strField } } return &Redmine{api: api.New(uriString, keyString, log), log: log, spFieldName: spField} } func (r *Redmine) GetTaskInfo(input string) (int, string) { taskNumber := r.getTaskNumber(input) if taskNumber == 0 { r.log.Debugf("[Redmine] Cannot extract task number from %s", input) return 0, "" } task, err := r.api.Issue(taskNumber) if err != nil { r.log.Errorf("[Redmine] Cannot get Redmine issue %d: %s", taskNumber, err) return 0, "" } sprint := r.getSprint(task.CustomFields) if sprint != "" { sprint = fmt.Sprintf(" - _%s_", sprint) } taskInfo := strings.ReplaceAll(fmt.Sprintf("_(%s) %s_: [%s](%s/issues/%d)%s", task.Project.Name, task.Tracker.Name, task.Subject, r.api.URL, taskNumber, sprint), "*", "") return task.ID, "\n" + taskInfo + "" } func (r *Redmine) PushVoteResult(id int, result float64) error { task, err := r.api.Issue(id) if err != nil { return err } issue := &api.Issue{ EstimatedHours: api.Hours(strconv.FormatFloat(result*8, 'f', 0, 64)), } if r.spFieldName != "" { for _, field := range task.CustomFields { field := field if field.Name == r.spFieldName { field.Value = strconv.FormatFloat(result, 'f', 1, 64) issue.CustomFields = []api.CustomField{field} } } } return r.api.UpdateIssue(id, issue) } func (r *Redmine) getTaskNumber(input string) int { num, err := strconv.Atoi(input) if err == nil && num > 0 { return num } matches := issueNumberMatcher.FindStringSubmatch(input) if len(matches) < 2 { return 0 } number, err := strconv.Atoi(matches[1]) if err != nil { return 0 } return number } func (r *Redmine) getSprint(fields []api.CustomField) string { for _, field := range fields { for _, name := range sprintNames { if strings.ToLower(field.Name) == name { return field.Value } } } return "" }