@@ -64,6 +64,7 @@ const (
64
64
tplReactions base.TplName = "repo/issue/view_content/reactions"
65
65
66
66
issueTemplateKey = "IssueTemplate"
67
+ issueFormTemplateKey = "IssueFormTemplate"
67
68
issueTemplateTitleKey = "IssueTemplateTitle"
68
69
)
69
70
@@ -722,16 +723,16 @@ func RetrieveRepoMetas(ctx *context.Context, repo *repo_model.Repository, isPull
722
723
return labels
723
724
}
724
725
725
- func getFileContentFromDefaultBranch (ctx * context.Context , filename string ) (string , bool ) {
726
- if ctx . Repo .Commit == nil {
726
+ func getFileContentFromDefaultBranch (repo * context.Repository , filename string ) (string , bool ) {
727
+ if repo .Commit == nil {
727
728
var err error
728
- ctx . Repo . Commit , err = ctx . Repo . GitRepo .GetBranchCommit (ctx . Repo .Repository .DefaultBranch )
729
+ repo . Commit , err = repo . GitRepo .GetBranchCommit (repo .Repository .DefaultBranch )
729
730
if err != nil {
730
731
return "" , false
731
732
}
732
733
}
733
734
734
- entry , err := ctx . Repo .Commit .GetTreeEntryByPath (filename )
735
+ entry , err := repo .Commit .GetTreeEntryByPath (filename )
735
736
if err != nil {
736
737
return "" , false
737
738
}
@@ -750,53 +751,89 @@ func getFileContentFromDefaultBranch(ctx *context.Context, filename string) (str
750
751
return string (bytes ), true
751
752
}
752
753
753
- func setTemplateIfExists (ctx * context.Context , ctxDataKey string , possibleDirs , possibleFiles []string ) {
754
+ func getTemplate (repo * context.Repository , template string , possibleDirs , possibleFiles []string ) (
755
+ outMeta * api.IssueTemplate ,
756
+ outTemplateBody string ,
757
+ outFormTemplateBody * api.IssueFormTemplate ,
758
+ err error ,
759
+ ) {
760
+ // Add `possibleFiles` and each `{possibleDirs}/{template}` to `templateCandidates`
754
761
templateCandidates := make ([]string , 0 , len (possibleFiles ))
755
- if ctx . FormString ( " template" ) != "" {
762
+ if template != "" {
756
763
for _ , dirName := range possibleDirs {
757
- templateCandidates = append (templateCandidates , path .Join (dirName , ctx . FormString ( " template" ) ))
764
+ templateCandidates = append (templateCandidates , path .Join (dirName , template ))
758
765
}
759
766
}
760
767
templateCandidates = append (templateCandidates , possibleFiles ... ) // Append files to the end because they should be fallback
768
+
761
769
for _ , filename := range templateCandidates {
762
- templateContent , found := getFileContentFromDefaultBranch (ctx , filename )
770
+ // Read each template
771
+ templateContent , found := getFileContentFromDefaultBranch (repo , filename )
763
772
if found {
764
- var meta api.IssueTemplate
765
- templateBody , err := markdown .ExtractMetadata (templateContent , & meta )
773
+ meta := api.IssueTemplate {FileName : filename }
774
+
775
+ if strings .HasSuffix (filename , ".md" ) {
776
+ // Parse markdown template
777
+ outTemplateBody , err = markdown .ExtractMetadata (templateContent , meta )
778
+ } else if strings .HasSuffix (filename , ".yaml" ) || strings .HasSuffix (filename , ".yml" ) {
779
+ // Parse yaml (form) template
780
+ outFormTemplateBody , err = context .ExtractTemplateFromYaml ([]byte (templateContent ), & meta )
781
+ outFormTemplateBody .FileName = path .Base (filename )
782
+ } else {
783
+ err = errors .New ("invalid template type" )
784
+ }
766
785
if err != nil {
767
- log .Debug ("could not extract metadata from %s [%s]: %v" , filename , ctx . Repo .Repository .FullName (), err )
768
- ctx . Data [ ctxDataKey ] = templateContent
769
- return
786
+ log .Debug ("could not extract metadata from %s [%s]: %v" , filename , repo .Repository .FullName (), err )
787
+ outTemplateBody = templateContent
788
+ err = nil
770
789
}
771
- ctx .Data [issueTemplateTitleKey ] = meta .Title
772
- ctx .Data [ctxDataKey ] = templateBody
773
- labelIDs := make ([]string , 0 , len (meta .Labels ))
774
- if repoLabels , err := issues_model .GetLabelsByRepoID (ctx , ctx .Repo .Repository .ID , "" , db.ListOptions {}); err == nil {
775
- ctx .Data ["Labels" ] = repoLabels
776
- if ctx .Repo .Owner .IsOrganization () {
777
- if orgLabels , err := issues_model .GetLabelsByOrgID (ctx , ctx .Repo .Owner .ID , ctx .FormString ("sort" ), db.ListOptions {}); err == nil {
778
- ctx .Data ["OrgLabels" ] = orgLabels
779
- repoLabels = append (repoLabels , orgLabels ... )
780
- }
781
- }
782
790
783
- for _ , metaLabel := range meta .Labels {
784
- for _ , repoLabel := range repoLabels {
785
- if strings .EqualFold (repoLabel .Name , metaLabel ) {
786
- repoLabel .IsChecked = true
787
- labelIDs = append (labelIDs , strconv .FormatInt (repoLabel .ID , 10 ))
788
- break
789
- }
790
- }
791
+ outMeta = & meta
792
+ return
793
+ }
794
+ }
795
+ err = errors .New ("no template found" )
796
+ return
797
+ }
798
+
799
+ func setTemplateIfExists (ctx * context.Context , ctxDataKey string , possibleDirs , possibleFiles []string ) {
800
+ templateMeta , templateBody , formTemplateBody , err := getTemplate (ctx .Repo , ctx .FormString ("template" ), possibleDirs , possibleFiles )
801
+ if err != nil {
802
+ return
803
+ }
804
+
805
+ if formTemplateBody != nil {
806
+ ctx .Data [issueFormTemplateKey ] = formTemplateBody
807
+ }
808
+
809
+ ctx .Data [issueTemplateTitleKey ] = templateMeta .Title
810
+ ctx .Data [ctxDataKey ] = templateBody
811
+
812
+ labelIDs := make ([]string , 0 , len (templateMeta .Labels ))
813
+ if repoLabels , err := issues_model .GetLabelsByRepoID (ctx , ctx .Repo .Repository .ID , "" , db.ListOptions {}); err == nil {
814
+ ctx .Data ["Labels" ] = repoLabels
815
+ if ctx .Repo .Owner .IsOrganization () {
816
+ if orgLabels , err := issues_model .GetLabelsByOrgID (ctx , ctx .Repo .Owner .ID , ctx .FormString ("sort" ), db.ListOptions {}); err == nil {
817
+ ctx .Data ["OrgLabels" ] = orgLabels
818
+ repoLabels = append (repoLabels , orgLabels ... )
819
+ }
820
+ }
821
+
822
+ for _ , metaLabel := range templateMeta .Labels {
823
+ for _ , repoLabel := range repoLabels {
824
+ if strings .EqualFold (repoLabel .Name , metaLabel ) {
825
+ repoLabel .IsChecked = true
826
+ labelIDs = append (labelIDs , strconv .FormatInt (repoLabel .ID , 10 ))
827
+ break
791
828
}
792
829
}
793
- ctx .Data ["HasSelectedLabel" ] = len (labelIDs ) > 0
794
- ctx .Data ["label_ids" ] = strings .Join (labelIDs , "," )
795
- ctx .Data ["Reference" ] = meta .Ref
796
- ctx .Data ["RefEndName" ] = git .RefEndName (meta .Ref )
797
- return
798
830
}
799
831
}
832
+ ctx .Data ["HasSelectedLabel" ] = len (labelIDs ) > 0
833
+ ctx .Data ["label_ids" ] = strings .Join (labelIDs , "," )
834
+ ctx .Data ["Reference" ] = templateMeta .Ref
835
+ ctx .Data ["RefEndName" ] = git .RefEndName (templateMeta .Ref )
836
+ return
800
837
}
801
838
802
839
// NewIssue render creating issue page
@@ -997,6 +1034,65 @@ func ValidateRepoMetas(ctx *context.Context, form forms.CreateIssueForm, isPull
997
1034
return labelIDs , assigneeIDs , milestoneID , form .ProjectID
998
1035
}
999
1036
1037
+ // Renders the given form values to Markdown
1038
+ // Returns an empty string if user submitted a non-form issue
1039
+ func renderIssueFormValues (ctx * context.Context , form * url.Values ) (string , error ) {
1040
+ // Skip if submitted without a form
1041
+ if form .Has ("content" ) || ! form .Has ("form-type" ) {
1042
+ return "" , nil
1043
+ }
1044
+
1045
+ // Fetch template
1046
+ _ , _ , formTemplateBody , err := getTemplate (
1047
+ ctx .Repo ,
1048
+ form .Get ("form-type" ),
1049
+ context .IssueTemplateDirCandidates ,
1050
+ IssueTemplateCandidates ,
1051
+ )
1052
+ if err != nil {
1053
+ return "" , err
1054
+ }
1055
+ if formTemplateBody == nil {
1056
+ return "" , errors .New ("no form template found" )
1057
+ }
1058
+
1059
+ // Render values
1060
+ result := ""
1061
+ for _ , field := range formTemplateBody .Fields {
1062
+ if field .Id != "" {
1063
+ // Get field label
1064
+ label := field .Attributes ["label" ]
1065
+ if label == "" {
1066
+ label = field .Id
1067
+ }
1068
+
1069
+ // Format the value into Markdown
1070
+ switch field .Type {
1071
+ case "markdown" :
1072
+ // Markdown blocks do not appear in output
1073
+ case "input" , "textarea" , "dropdown" :
1074
+ if renderType , ok := field .Attributes ["render" ]; ok {
1075
+ result += fmt .Sprintf ("### %s\n ```%s\n %s\n ```\n \n " , label , renderType , form .Get ("form-field-" + field .Id ))
1076
+ } else {
1077
+ result += fmt .Sprintf ("### %s\n %s\n \n " , label , form .Get ("form-field-" + field .Id ))
1078
+ }
1079
+ case "checkboxes" :
1080
+ result += fmt .Sprintf ("### %s\n " , label )
1081
+ for i , option := range field .Attributes ["options" ].([]interface {}) {
1082
+ checked := " "
1083
+ if form .Get (fmt .Sprintf ("form-field-%s-%d" , field .Id , i )) == "on" {
1084
+ checked = "x"
1085
+ }
1086
+ result += fmt .Sprintf ("- [%s] %s\n " , checked , option .(map [interface {}]interface {})["label" ])
1087
+ }
1088
+ result += "\n "
1089
+ }
1090
+ }
1091
+ }
1092
+
1093
+ return result , nil
1094
+ }
1095
+
1000
1096
// NewIssuePost response for creating new issue
1001
1097
func NewIssuePost (ctx * context.Context ) {
1002
1098
form := web .GetForm (ctx ).(* forms.CreateIssueForm )
@@ -1031,14 +1127,24 @@ func NewIssuePost(ctx *context.Context) {
1031
1127
return
1032
1128
}
1033
1129
1130
+ // If the issue submitted is a form, render it to Markdown
1131
+ issueContents , err := renderIssueFormValues (ctx , & ctx .Req .Form )
1132
+ if err != nil {
1133
+ return
1134
+ }
1135
+ if issueContents == "" {
1136
+ // Not a form
1137
+ issueContents = form .Content
1138
+ }
1139
+
1034
1140
issue := & issues_model.Issue {
1035
1141
RepoID : repo .ID ,
1036
1142
Repo : repo ,
1037
1143
Title : form .Title ,
1038
1144
PosterID : ctx .Doer .ID ,
1039
1145
Poster : ctx .Doer ,
1040
1146
MilestoneID : milestoneID ,
1041
- Content : form . Content ,
1147
+ Content : issueContents ,
1042
1148
Ref : form .Ref ,
1043
1149
}
1044
1150
0 commit comments