code.gitea.io/gitea@v1.19.3/modules/structs/issue.go (about) 1 // Copyright 2016 The Gogs Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package structs 5 6 import ( 7 "fmt" 8 "path" 9 "strings" 10 "time" 11 12 "gopkg.in/yaml.v3" 13 ) 14 15 // StateType issue state type 16 type StateType string 17 18 const ( 19 // StateOpen pr is opend 20 StateOpen StateType = "open" 21 // StateClosed pr is closed 22 StateClosed StateType = "closed" 23 // StateAll is all 24 StateAll StateType = "all" 25 ) 26 27 // PullRequestMeta PR info if an issue is a PR 28 type PullRequestMeta struct { 29 HasMerged bool `json:"merged"` 30 Merged *time.Time `json:"merged_at"` 31 } 32 33 // RepositoryMeta basic repository information 34 type RepositoryMeta struct { 35 ID int64 `json:"id"` 36 Name string `json:"name"` 37 Owner string `json:"owner"` 38 FullName string `json:"full_name"` 39 } 40 41 // Issue represents an issue in a repository 42 // swagger:model 43 type Issue struct { 44 ID int64 `json:"id"` 45 URL string `json:"url"` 46 HTMLURL string `json:"html_url"` 47 Index int64 `json:"number"` 48 Poster *User `json:"user"` 49 OriginalAuthor string `json:"original_author"` 50 OriginalAuthorID int64 `json:"original_author_id"` 51 Title string `json:"title"` 52 Body string `json:"body"` 53 Ref string `json:"ref"` 54 Attachments []*Attachment `json:"assets"` 55 Labels []*Label `json:"labels"` 56 Milestone *Milestone `json:"milestone"` 57 // deprecated 58 Assignee *User `json:"assignee"` 59 Assignees []*User `json:"assignees"` 60 // Whether the issue is open or closed 61 // 62 // type: string 63 // enum: open,closed 64 State StateType `json:"state"` 65 IsLocked bool `json:"is_locked"` 66 Comments int `json:"comments"` 67 // swagger:strfmt date-time 68 Created time.Time `json:"created_at"` 69 // swagger:strfmt date-time 70 Updated time.Time `json:"updated_at"` 71 // swagger:strfmt date-time 72 Closed *time.Time `json:"closed_at"` 73 // swagger:strfmt date-time 74 Deadline *time.Time `json:"due_date"` 75 76 PullRequest *PullRequestMeta `json:"pull_request"` 77 Repo *RepositoryMeta `json:"repository"` 78 } 79 80 // CreateIssueOption options to create one issue 81 type CreateIssueOption struct { 82 // required:true 83 Title string `json:"title" binding:"Required"` 84 Body string `json:"body"` 85 Ref string `json:"ref"` 86 // deprecated 87 Assignee string `json:"assignee"` 88 Assignees []string `json:"assignees"` 89 // swagger:strfmt date-time 90 Deadline *time.Time `json:"due_date"` 91 // milestone id 92 Milestone int64 `json:"milestone"` 93 // list of label ids 94 Labels []int64 `json:"labels"` 95 Closed bool `json:"closed"` 96 } 97 98 // EditIssueOption options for editing an issue 99 type EditIssueOption struct { 100 Title string `json:"title"` 101 Body *string `json:"body"` 102 Ref *string `json:"ref"` 103 // deprecated 104 Assignee *string `json:"assignee"` 105 Assignees []string `json:"assignees"` 106 Milestone *int64 `json:"milestone"` 107 State *string `json:"state"` 108 // swagger:strfmt date-time 109 Deadline *time.Time `json:"due_date"` 110 RemoveDeadline *bool `json:"unset_due_date"` 111 } 112 113 // EditDeadlineOption options for creating a deadline 114 type EditDeadlineOption struct { 115 // required:true 116 // swagger:strfmt date-time 117 Deadline *time.Time `json:"due_date"` 118 } 119 120 // IssueDeadline represents an issue deadline 121 // swagger:model 122 type IssueDeadline struct { 123 // swagger:strfmt date-time 124 Deadline *time.Time `json:"due_date"` 125 } 126 127 // IssueFormFieldType defines issue form field type, can be "markdown", "textarea", "input", "dropdown" or "checkboxes" 128 type IssueFormFieldType string 129 130 const ( 131 IssueFormFieldTypeMarkdown IssueFormFieldType = "markdown" 132 IssueFormFieldTypeTextarea IssueFormFieldType = "textarea" 133 IssueFormFieldTypeInput IssueFormFieldType = "input" 134 IssueFormFieldTypeDropdown IssueFormFieldType = "dropdown" 135 IssueFormFieldTypeCheckboxes IssueFormFieldType = "checkboxes" 136 ) 137 138 // IssueFormField represents a form field 139 // swagger:model 140 type IssueFormField struct { 141 Type IssueFormFieldType `json:"type" yaml:"type"` 142 ID string `json:"id" yaml:"id"` 143 Attributes map[string]interface{} `json:"attributes" yaml:"attributes"` 144 Validations map[string]interface{} `json:"validations" yaml:"validations"` 145 } 146 147 // IssueTemplate represents an issue template for a repository 148 // swagger:model 149 type IssueTemplate struct { 150 Name string `json:"name" yaml:"name"` 151 Title string `json:"title" yaml:"title"` 152 About string `json:"about" yaml:"about"` // Using "description" in a template file is compatible 153 Labels IssueTemplateLabels `json:"labels" yaml:"labels"` 154 Ref string `json:"ref" yaml:"ref"` 155 Content string `json:"content" yaml:"-"` 156 Fields []*IssueFormField `json:"body" yaml:"body"` 157 FileName string `json:"file_name" yaml:"-"` 158 } 159 160 type IssueTemplateLabels []string 161 162 func (l *IssueTemplateLabels) UnmarshalYAML(value *yaml.Node) error { 163 var labels []string 164 if value.IsZero() { 165 *l = labels 166 return nil 167 } 168 switch value.Kind { 169 case yaml.ScalarNode: 170 str := "" 171 err := value.Decode(&str) 172 if err != nil { 173 return err 174 } 175 for _, v := range strings.Split(str, ",") { 176 if v = strings.TrimSpace(v); v == "" { 177 continue 178 } 179 labels = append(labels, v) 180 } 181 *l = labels 182 return nil 183 case yaml.SequenceNode: 184 if err := value.Decode(&labels); err != nil { 185 return err 186 } 187 *l = labels 188 return nil 189 } 190 return fmt.Errorf("line %d: cannot unmarshal %s into IssueTemplateLabels", value.Line, value.ShortTag()) 191 } 192 193 // IssueTemplateType defines issue template type 194 type IssueTemplateType string 195 196 const ( 197 IssueTemplateTypeMarkdown IssueTemplateType = "md" 198 IssueTemplateTypeYaml IssueTemplateType = "yaml" 199 ) 200 201 // Type returns the type of IssueTemplate, can be "md", "yaml" or empty for known 202 func (it IssueTemplate) Type() IssueTemplateType { 203 if base := path.Base(it.FileName); base == "config.yaml" || base == "config.yml" { 204 // ignore config.yaml which is a special configuration file 205 return "" 206 } 207 if ext := path.Ext(it.FileName); ext == ".md" { 208 return IssueTemplateTypeMarkdown 209 } else if ext == ".yaml" || ext == ".yml" { 210 return IssueTemplateTypeYaml 211 } 212 return "" 213 }