1+ const baseController = require ( 'controllers/base.js' ) ;
2+ const interfaceModel = require ( 'models/interface.js' ) ;
3+ const projectModel = require ( 'models/project.js' ) ;
4+ const interfaceCatModel = require ( 'models/interfaceCat.js' ) ;
5+ const yapi = require ( 'yapi.js' ) ;
6+
7+
8+ class exportSwaggerController extends baseController {
9+ constructor ( ctx ) {
10+ super ( ctx ) ;
11+ this . catModel = yapi . getInst ( interfaceCatModel ) ;
12+ this . interModel = yapi . getInst ( interfaceModel ) ;
13+ this . projectModel = yapi . getInst ( projectModel ) ;
14+ }
15+
16+ /*
17+ handleListClass,handleExistId is same as the exportController(yapi-plugin-export-data).
18+ No DRY,but i have no idea to optimize it.
19+ */
20+
21+ async handleListClass ( pid , status ) {
22+ let result = await this . catModel . list ( pid ) ,
23+ newResult = [ ] ;
24+ for ( let i = 0 , item , list ; i < result . length ; i ++ ) {
25+ item = result [ i ] . toObject ( ) ;
26+ list = await this . interModel . listByInterStatus ( item . _id , status ) ;
27+ list = list . sort ( ( a , b ) => {
28+ return a . index - b . index ;
29+ } ) ;
30+ if ( list . length > 0 ) {
31+ item . list = list ;
32+ newResult . push ( item ) ;
33+ }
34+ }
35+
36+ return newResult ;
37+ }
38+
39+ handleExistId ( data ) {
40+ function delArrId ( arr , fn ) {
41+ if ( ! Array . isArray ( arr ) ) return ;
42+ arr . forEach ( item => {
43+ delete item . _id ;
44+ delete item . __v ;
45+ delete item . uid ;
46+ delete item . edit_uid ;
47+ delete item . catid ;
48+ delete item . project_id ;
49+
50+ if ( typeof fn === 'function' ) fn ( item ) ;
51+ } ) ;
52+ }
53+
54+ delArrId ( data , function ( item ) {
55+ delArrId ( item . list , function ( api ) {
56+ delArrId ( api . req_body_form ) ;
57+ delArrId ( api . req_params ) ;
58+ delArrId ( api . req_query ) ;
59+ delArrId ( api . req_headers ) ;
60+ if ( api . query_path && typeof api . query_path === 'object' ) {
61+ delArrId ( api . query_path . params ) ;
62+ }
63+ } ) ;
64+ } ) ;
65+
66+ return data ;
67+ }
68+
69+ async exportData ( ctx ) {
70+ let pid = ctx . request . query . pid ;
71+ let type = ctx . request . query . type ;
72+ let status = ctx . request . query . status ;
73+
74+ if ( ! pid ) {
75+ ctx . body = yapi . commons . resReturn ( null , 200 , 'pid 不为空' ) ;
76+ }
77+ let curProject ;
78+ let tp = '' ;
79+ try {
80+ curProject = await this . projectModel . get ( pid ) ;
81+ ctx . set ( 'Content-Type' , 'application/octet-stream' ) ;
82+ const list = await this . handleListClass ( pid , status ) ;
83+
84+ switch ( type ) {
85+ case 'OpenAPIV2' :
86+ { //in this time, only implemented OpenAPI V2.0
87+ let data = this . handleExistId ( list ) ;
88+ let model = await convertToSwaggerV2Model ( data ) ;
89+ tp = JSON . stringify ( model , null , 2 ) ;
90+ ctx . set ( 'Content-Disposition' , `attachment; filename=swaggerApi.json` ) ;
91+ return ( ctx . body = tp ) ;
92+ }
93+ default :
94+ {
95+ ctx . body = yapi . commons . resReturn ( null , 400 , 'type 无效参数' )
96+ }
97+ }
98+ } catch ( error ) {
99+ yapi . commons . log ( error , 'error' ) ;
100+ ctx . body = yapi . commons . resReturn ( null , 502 , '下载出错' ) ;
101+ }
102+
103+ //Convert to SwaggerV2.0 (OpenAPI 2.0)
104+ async function convertToSwaggerV2Model ( list ) {
105+ const swaggerObj = {
106+ swagger : '2.0' ,
107+ info : {
108+ title : curProject . name ,
109+ version : 'last' , // last version
110+ description : curProject . desc
111+ } ,
112+ //host: "", // No find any info of host in this point :-)
113+ basePath : curProject . basepath ? curProject . basepath : '/' , //default base path is '/'(root)
114+ tags : ( ( ) => {
115+ let tagArray = [ ] ;
116+ list . forEach ( t => {
117+ tagArray . push ( {
118+ name : t . name ,
119+ description : t . desc
120+ /*externalDocs:{
121+ descroption:"",
122+ url:""
123+ } */
124+ } ) ;
125+ } ) ;
126+ return tagArray ;
127+ } ) ( ) ,
128+ schemes : [
129+ "http" //Only http
130+ ] ,
131+ paths : ( ( ) => {
132+ let apisObj = { } ;
133+ for ( let aptTag of list ) { //list of category
134+ for ( let api of aptTag . list ) //list of api
135+ {
136+ if ( apisObj [ api . path ] == null ) {
137+ apisObj [ api . path ] = { } ;
138+ }
139+ apisObj [ api . path ] [ api . method . toLowerCase ( ) ] = ( ( ) => {
140+ let apiItem = { } ;
141+ apiItem [ 'tags' ] = [ aptTag . name ] ;
142+ apiItem [ 'summary' ] = api . title ;
143+ apiItem [ 'description' ] = api . markdown ;
144+ switch ( api . req_body_type ) {
145+ case 'form' :
146+ case 'file' :
147+ apiItem [ 'consumes' ] = [ 'multipart/form-data' ] ; //form data required
148+ break ;
149+ case 'json' :
150+ apiItem [ 'consumes' ] = [ 'application/json' ] ;
151+ break ;
152+ case 'raw' :
153+ apiItem [ 'consumes' ] = [ 'text/plain' ] ;
154+ break ;
155+ default :
156+ break ;
157+ }
158+ apiItem [ 'parameters' ] = ( ( ) => {
159+ let paramArray = [ ] ;
160+ for ( let p of api . req_headers ) //Headers parameters
161+ {
162+ //swagger has consumes proprety, so skip proprety "Content-Type"
163+ if ( p . name === 'Content-Type' ) {
164+ continue ;
165+ }
166+ paramArray . push ( {
167+ name : p . name ,
168+ in : 'header' ,
169+ description : `${ p . name } (Only:${ p . value } )` ,
170+ required : p . required === 1 ,
171+ type : 'string' , //always be type string
172+ default : p . value
173+ } ) ;
174+ }
175+ for ( let p of api . req_params ) //Path parameters
176+ {
177+ paramArray . push ( {
178+ name : p . name ,
179+ in : 'path' ,
180+ description : p . desc ,
181+ required : true , //swagger path parameters required proprety must be always true,
182+ type : 'string' //always be type string
183+ } ) ;
184+ }
185+ for ( let p of api . req_query ) //Query parameters
186+ {
187+ paramArray . push ( {
188+ name : p . name ,
189+ in : 'query' ,
190+ required : p . required === 1 ,
191+ description : p . desc ,
192+ type : 'string' //always be type string
193+ } ) ;
194+ }
195+ switch ( api . req_body_type ) //Body parameters
196+ {
197+ case 'form' :
198+ {
199+ for ( let p of api . req_body_form ) {
200+ paramArray . push ( {
201+ name : p . name ,
202+ in : 'formData' ,
203+ required : p . required === 1 ,
204+ description : p . desc ,
205+ type : p . type === 'text' ? 'string' : 'file' //in this time .formData type have only text or file
206+ } ) ;
207+ }
208+ break ;
209+ }
210+ case 'json' :
211+ {
212+ if ( api . req_body_other ) {
213+ let jsonParam = JSON . parse ( api . req_body_other ) ;
214+ if ( jsonParam ) {
215+ paramArray . push ( {
216+ name : 'root' ,
217+ in : 'body' ,
218+ description : jsonParam . description ,
219+ schema : jsonParam //as same as swagger's format
220+ } ) ;
221+ }
222+ }
223+ break ;
224+ }
225+ case 'file' :
226+ {
227+ paramArray . push ( {
228+ name : 'upfile' ,
229+ in : 'formData' , //use formData
230+ description : api . req_body_other ,
231+ type : 'file'
232+ } ) ;
233+ break ;
234+ }
235+ case 'raw' :
236+ {
237+ paramArray . push ( {
238+ name : 'raw' ,
239+ in : 'body' ,
240+ description : 'raw paramter' ,
241+ schema : {
242+ type : 'string' ,
243+ format : 'binary' ,
244+ default : api . req_body_other
245+ }
246+ } ) ;
247+ break ;
248+ }
249+ default :
250+ break ;
251+ }
252+ return paramArray ;
253+ } ) ( ) ;
254+ apiItem [ 'responses' ] = {
255+ '200' : {
256+ description : 'successful operation' ,
257+ schema : ( ( ) => {
258+ let schemaObj = { } ;
259+ if ( api . res_body_type === 'raw' ) {
260+ schemaObj [ 'type' ] = 'string' ;
261+ schemaObj [ 'format' ] = 'binary' ;
262+ schemaObj [ 'default' ] = api . res_body ;
263+ } else if ( api . res_body_type === 'json' ) {
264+ if ( api . res_body ) {
265+ let resBody = JSON . parse ( api . res_body ) ;
266+ if ( resBody !== null ) {
267+ //schemaObj['type']=resBody.type;
268+ schemaObj = resBody ; //as the parameters,
269+ }
270+ }
271+ }
272+ return schemaObj ;
273+ } ) ( )
274+ }
275+ } ;
276+ return apiItem ;
277+ } ) ( ) ;
278+ }
279+ }
280+ return apisObj ;
281+ } ) ( )
282+ } ;
283+ return swaggerObj ;
284+ }
285+ }
286+ }
287+
288+ module . exports = exportSwaggerController ;
0 commit comments