1
- use crate :: github:: { GithubClient , Issue } ;
1
+ use anyhow:: Result ;
2
+ use serde:: { Deserialize , Serialize } ;
3
+ use tokio_postgres:: Client as DbClient ;
4
+
5
+ use crate :: {
6
+ db:: issue_data:: IssueData ,
7
+ github:: { GithubClient , Issue } ,
8
+ } ;
2
9
use std:: fmt:: Write ;
3
10
4
11
pub struct ErrorComment < ' a > {
@@ -51,7 +58,11 @@ impl<'a> PingComment<'a> {
51
58
}
52
59
}
53
60
54
- pub struct EditIssueBody < ' a > {
61
+ pub struct EditIssueBody < ' a , T >
62
+ where
63
+ T : for < ' t > Deserialize < ' t > + Serialize + Default + std:: fmt:: Debug + Sync + PartialEq + Clone ,
64
+ {
65
+ issue_data : IssueData < ' a , T > ,
55
66
issue : & ' a Issue ,
56
67
id : & ' static str ,
57
68
}
@@ -63,88 +74,47 @@ fn normalize_body(body: &str) -> String {
63
74
str:: replace ( body, "\r \n " , "\n " )
64
75
}
65
76
66
- impl < ' a > EditIssueBody < ' a > {
67
- pub fn new ( issue : & ' a Issue , id : & ' static str ) -> EditIssueBody < ' a > {
68
- EditIssueBody { issue, id }
69
- }
70
-
71
- fn get_current ( & self ) -> Option < String > {
72
- let self_issue_body = normalize_body ( & self . issue . body ) ;
73
- let start_section = self . start_section ( ) ;
74
- let end_section = self . end_section ( ) ;
75
- if self_issue_body. contains ( START_BOT ) {
76
- if self_issue_body. contains ( & start_section) {
77
- let start_idx = self_issue_body. find ( & start_section) . unwrap ( ) ;
78
- let end_idx = self_issue_body. find ( & end_section) . unwrap ( ) ;
79
- let current =
80
- String :: from ( & self_issue_body[ start_idx..( end_idx + end_section. len ( ) ) ] ) ;
81
- Some ( current)
82
- } else {
83
- None
84
- }
85
- } else {
86
- None
77
+ impl < ' a , T > EditIssueBody < ' a , T >
78
+ where
79
+ T : for < ' t > Deserialize < ' t > + Serialize + Default + std:: fmt:: Debug + Sync + PartialEq + Clone ,
80
+ {
81
+ pub async fn load (
82
+ db : & ' a mut DbClient ,
83
+ issue : & ' a Issue ,
84
+ id : & ' static str ,
85
+ ) -> Result < EditIssueBody < ' a , T > > {
86
+ let issue_data = IssueData :: load ( db, issue, id) . await ?;
87
+
88
+ let mut edit = EditIssueBody {
89
+ issue_data,
90
+ issue,
91
+ id,
92
+ } ;
93
+
94
+ // Legacy, if we find data inside the issue body for the current
95
+ // id, use that instead of the (hopefully) default value given
96
+ // by IssueData.
97
+ if let Some ( d) = edit. current_data_markdown ( ) {
98
+ edit. issue_data . data = d;
87
99
}
88
- }
89
-
90
- pub fn current_data < T : serde:: de:: DeserializeOwned > ( & self ) -> Option < T > {
91
- let all = self . get_current ( ) ?;
92
- let start = self . data_section_start ( ) ;
93
- let end = self . data_section_end ( ) ;
94
- let start_idx = all. find ( & start) . unwrap ( ) ;
95
- let end_idx = all. find ( & end) . unwrap ( ) ;
96
- let text = & all[ ( start_idx + start. len ( ) ) ..end_idx] ;
97
- Some ( serde_json:: from_str ( text) . unwrap_or_else ( |e| {
98
- panic ! ( "deserializing data {:?} failed: {:?}" , text, e) ;
99
- } ) )
100
- }
101
-
102
- fn start_section ( & self ) -> String {
103
- format ! ( "<!-- TRIAGEBOT_{}_START -->\n " , self . id)
104
- }
105
-
106
- fn end_section ( & self ) -> String {
107
- format ! ( "\n <!-- TRIAGEBOT_{}_END -->\n " , self . id)
108
- }
109
-
110
- fn data_section_start ( & self ) -> String {
111
- format ! ( "\n <!-- TRIAGEBOT_{}_DATA_START$$" , self . id)
112
- }
113
100
114
- fn data_section_end ( & self ) -> String {
115
- format ! ( "$$TRIAGEBOT_{}_DATA_END -->\n " , self . id)
101
+ Ok ( edit)
116
102
}
117
103
118
- fn data_section < T > ( & self , data : T ) -> String
119
- where
120
- T : serde:: Serialize ,
121
- {
122
- format ! (
123
- "{}{}{}" ,
124
- self . data_section_start( ) ,
125
- serde_json:: to_string( & data) . unwrap( ) ,
126
- self . data_section_end( )
127
- )
104
+ pub fn data_mut ( & mut self ) -> & mut T {
105
+ & mut self . issue_data . data
128
106
}
129
107
130
- pub async fn apply < T > ( & self , client : & GithubClient , text : String , data : T ) -> anyhow:: Result < ( ) >
131
- where
132
- T : serde:: Serialize ,
133
- {
108
+ pub async fn apply ( self , client : & GithubClient , text : String ) -> anyhow:: Result < ( ) > {
134
109
let mut current_body = normalize_body ( & self . issue . body . clone ( ) ) ;
135
110
let start_section = self . start_section ( ) ;
136
111
let end_section = self . end_section ( ) ;
137
112
138
- let bot_section = format ! (
139
- "{}{}{}{}" ,
140
- start_section,
141
- text,
142
- self . data_section( data) ,
143
- end_section
144
- ) ;
113
+ let bot_section = format ! ( "{}{}{}" , start_section, text, end_section) ;
145
114
let empty_bot_section = format ! ( "{}{}" , start_section, end_section) ;
146
-
147
115
let all_new = format ! ( "\n \n {}{}{}" , START_BOT , bot_section, END_BOT ) ;
116
+
117
+ // Edit or add the new text the current triagebot section
148
118
if current_body. contains ( START_BOT ) {
149
119
if current_body. contains ( & start_section) {
150
120
let start_idx = current_body. find ( & start_section) . unwrap ( ) ;
@@ -166,6 +136,59 @@ impl<'a> EditIssueBody<'a> {
166
136
167
137
self . issue . edit_body ( & client, & new_body) . await ?;
168
138
}
139
+
140
+ // Save the state in the database
141
+ self . issue_data . save ( ) . await ?;
142
+
169
143
Ok ( ( ) )
170
144
}
145
+
146
+ fn start_section ( & self ) -> String {
147
+ format ! ( "<!-- TRIAGEBOT_{}_START -->\n " , self . id)
148
+ }
149
+
150
+ fn end_section ( & self ) -> String {
151
+ format ! ( "\n <!-- TRIAGEBOT_{}_END -->\n " , self . id)
152
+ }
153
+
154
+ // Legacy, only used for handling data inside the issue body it-self
155
+
156
+ fn current_data_markdown ( & self ) -> Option < T > {
157
+ let all = self . get_current_markdown ( ) ?;
158
+ let start = self . data_section_start ( ) ;
159
+ let end = self . data_section_end ( ) ;
160
+ let start_idx = all. find ( & start) . unwrap ( ) ;
161
+ let end_idx = all. find ( & end) . unwrap ( ) ;
162
+ let text = & all[ ( start_idx + start. len ( ) ) ..end_idx] ;
163
+ Some ( serde_json:: from_str ( text) . unwrap_or_else ( |e| {
164
+ panic ! ( "deserializing data {:?} failed: {:?}" , text, e) ;
165
+ } ) )
166
+ }
167
+
168
+ fn get_current_markdown ( & self ) -> Option < String > {
169
+ let self_issue_body = normalize_body ( & self . issue . body ) ;
170
+ let start_section = self . start_section ( ) ;
171
+ let end_section = self . end_section ( ) ;
172
+ if self_issue_body. contains ( START_BOT ) {
173
+ if self_issue_body. contains ( & start_section) {
174
+ let start_idx = self_issue_body. find ( & start_section) . unwrap ( ) ;
175
+ let end_idx = self_issue_body. find ( & end_section) . unwrap ( ) ;
176
+ let current =
177
+ String :: from ( & self_issue_body[ start_idx..( end_idx + end_section. len ( ) ) ] ) ;
178
+ Some ( current)
179
+ } else {
180
+ None
181
+ }
182
+ } else {
183
+ None
184
+ }
185
+ }
186
+
187
+ fn data_section_start ( & self ) -> String {
188
+ format ! ( "\n <!-- TRIAGEBOT_{}_DATA_START$$" , self . id)
189
+ }
190
+
191
+ fn data_section_end ( & self ) -> String {
192
+ format ! ( "$$TRIAGEBOT_{}_DATA_END -->\n " , self . id)
193
+ }
171
194
}
0 commit comments