PageRenderTime 33ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/src/wordpress.js

http://github.com/jquery/plugins.jquery.com
JavaScript | 533 lines | 418 code | 101 blank | 14 comment | 41 complexity | 80c362f63c059e11197e8de00ffb548b MD5 | raw file
  1. var fs = require( "fs" ),
  2. mysql = require( "mysql" ),
  3. Step = require( "step" ),
  4. config = require( "./config" );
  5. var db,
  6. postIds = {},
  7. optionsTable = table( "options" ),
  8. postmetaTable = table( "postmeta" ),
  9. postsTable = table( "posts" ),
  10. termsTable = table( "terms" ),
  11. termRelationshipsTable = table( "term_relationships" ),
  12. termTaxonomyTable = table( "term_taxonomy" );
  13. function table( name ) {
  14. return "wp_" + (config.siteId ? config.siteId + "_" : "") + name;
  15. }
  16. function toLocalDate( date ) {
  17. return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate() + " " +
  18. date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();
  19. }
  20. function toGmtDate( date ) {
  21. return date.getUTCFullYear() + "-" + (date.getUTCMonth() + 1) + "-" + date.getUTCDate() + " " +
  22. date.getUTCHours() + ":" + date.getUTCMinutes() + ":" + date.getUTCSeconds();
  23. }
  24. function auto( fn ) {
  25. return function() {
  26. if ( !db ) {
  27. connect();
  28. }
  29. fn.apply( this, arguments );
  30. };
  31. }
  32. function connect() {
  33. db = mysql.createClient({
  34. host: config.dbHost,
  35. port: config.dbPort,
  36. user: config.dbUser,
  37. password: config.dbPassword,
  38. database: config.dbName
  39. });
  40. }
  41. /** posts **/
  42. function getPostId( name, fn ) {
  43. if ( name in postIds ) {
  44. return process.nextTick(function() {
  45. fn( null, postIds[ name ] );
  46. });
  47. }
  48. db.query( "SELECT `ID` FROM `" + postsTable + "` WHERE `post_name` = ?",
  49. [ name ], function( error, rows ) {
  50. if ( error ) {
  51. return fn( error );
  52. }
  53. if ( !rows.length ) {
  54. return fn( null, null );
  55. }
  56. postIds[ name ] = rows[ 0 ].ID;
  57. fn( null, rows[ 0 ].ID );
  58. });
  59. }
  60. function requirePostId( name, fn ) {
  61. getPostId( name, function( error, id ) {
  62. if ( error ) {
  63. return fn( error );
  64. }
  65. if ( !id ) {
  66. return fn( new Error( "No post '" + name + "'." ) );
  67. }
  68. fn( null, id );
  69. });
  70. }
  71. function createOrUpdatePost( data, fn ) {
  72. getPostId( data.name, function( error, id ) {
  73. if ( error ) {
  74. return fn( error );
  75. }
  76. if ( id ) {
  77. updatePost( id, data, fn );
  78. } else {
  79. createPost( data, fn );
  80. }
  81. });
  82. }
  83. function createPost( data, fn ) {
  84. var localDate = toLocalDate( data.date ),
  85. gmtDate = toGmtDate( data.date ),
  86. status = data.draft ? "draft" : "publish",
  87. parent = data.parent || 0;
  88. db.query( "INSERT INTO `" + postsTable + "` " +
  89. "SET `post_type` = 'page', `post_name` = ?, `post_title` = ?, `post_content` = ?, " +
  90. "`post_status` = ?, `post_parent` = ?, " +
  91. "`post_date` = ?, `post_date_gmt` = ?, `post_modified` = ?, `post_modified_gmt` = ?",
  92. [ data.name, data.title, data.content, status, parent, localDate, gmtDate, localDate, gmtDate ],
  93. function( error, info ) {
  94. if ( error ) {
  95. return fn( error );
  96. }
  97. postIds[ data.name ] = info.insertId;
  98. fn( null, info.insertId );
  99. });
  100. }
  101. function updatePost( id, data, fn ) {
  102. var localDate = toLocalDate( data.date ),
  103. gmtDate = toGmtDate( data.date ),
  104. status = data.draft ? "draft" : "publish";
  105. db.query( "UPDATE `" + postsTable + "` " +
  106. "SET `post_title` = ?, `post_content` = ?, `post_status` = ?, " +
  107. "`post_date` = ?, `post_date_gmt` = ?, `post_modified` = ?, `post_modified_gmt` = ? " +
  108. "WHERE `ID` = ?",
  109. [ data.title, data.content, status, localDate, gmtDate, localDate, gmtDate, id ],
  110. function( error ) {
  111. if ( error ) {
  112. return fn( error );
  113. }
  114. fn( null, id );
  115. });
  116. }
  117. function publishPost( id, fn ) {
  118. db.query( "UPDATE `" + postsTable + "` SET `post_status` = 'publish' WHERE `ID` = ?",
  119. [ id ], function( error ) {
  120. fn( error );
  121. });
  122. }
  123. /** meta **/
  124. function setMeta( id, key, value, fn ) {
  125. Step(
  126. function() {
  127. db.query( "SELECT `meta_id`, `meta_value` FROM `" + postmetaTable + "` " +
  128. "WHERE `post_id` = ? AND `meta_key` = ?",
  129. [ id, key ], this.parallel() );
  130. },
  131. function( error, rows ) {
  132. if ( error ) {
  133. return fn( error );
  134. }
  135. if ( !rows.length ) {
  136. db.query( "INSERT INTO `" + postmetaTable + "` " +
  137. "SET `post_id` = ?, `meta_key` = ?, `meta_value` = ?",
  138. [ id, key, value ], this );
  139. } else {
  140. db.query( "UPDATE `" + postmetaTable + "` " +
  141. "SET `meta_value` = ? WHERE `meta_id` = ?",
  142. [ value, rows[ 0 ].meta_id ], this );
  143. }
  144. },
  145. function( error ) {
  146. fn( error );
  147. }
  148. );
  149. }
  150. function getMeta( id, key, fn ) {
  151. db.query( "SELECT `meta_value` FROM `" + postmetaTable + "` " +
  152. "WHERE `post_id` = ? AND `meta_key` = ?",
  153. [ id, key ], function( error, rows ) {
  154. if ( error ) {
  155. return fn( error );
  156. }
  157. if ( !rows.length ) {
  158. return fn( null, null );
  159. }
  160. fn( null, rows[ 0 ].meta_value );
  161. });
  162. }
  163. /** terms **/
  164. function createTerm( term, fn ) {
  165. Step(
  166. function() {
  167. db.query( "INSERT INTO `" + termsTable + "` SET `name` = ?, `slug` = ? " +
  168. "ON DUPLICATE KEY UPDATE `term_id` = LAST_INSERT_ID(`term_id`)",
  169. [ term, term ], this );
  170. },
  171. function( error, info ) {
  172. if ( error ) {
  173. return fn( error );
  174. }
  175. db.query( "INSERT INTO `" + termTaxonomyTable + "` " +
  176. "SET `term_id` = ?, `taxonomy` = 'post_tag' " +
  177. "ON DUPLICATE KEY UPDATE `term_taxonomy_id` = LAST_INSERT_ID(`term_taxonomy_id`)",
  178. [ info.insertId ], this );
  179. },
  180. function( error, info ) {
  181. if ( error ) {
  182. return fn( error );
  183. }
  184. fn( null, info.insertId );
  185. }
  186. );
  187. }
  188. function setTerm( postId, term, fn ) {
  189. Step(
  190. function() {
  191. createTerm( term, this );
  192. },
  193. function( error, termId ) {
  194. if ( error ) {
  195. return fn( error );
  196. }
  197. db.query( "INSERT INTO `" + termRelationshipsTable + "` " +
  198. "SET `object_id` = ?, `term_taxonomy_id` = ?",
  199. [ postId, termId ], this );
  200. },
  201. function( error ) {
  202. fn( error );
  203. }
  204. );
  205. }
  206. function setTerms( postId, terms, fn ) {
  207. Step(
  208. function() {
  209. db.query( "DELETE FROM `" + termRelationshipsTable + "` WHERE `object_id` = ?",
  210. [ postId ], this );
  211. },
  212. function( error ) {
  213. if ( error ) {
  214. return fn( error );
  215. }
  216. if ( !terms || !terms.length ) {
  217. return process.nextTick(function() {
  218. fn( null );
  219. });
  220. }
  221. var group = this.group();
  222. terms.forEach(function( term ) {
  223. setTerm( postId, term, group() );
  224. });
  225. },
  226. function( error ) {
  227. fn( error );
  228. }
  229. );
  230. }
  231. /** util **/
  232. function flush( fn ) {
  233. db.query( "DELETE FROM `" + optionsTable + "` WHERE `option_name` = 'rewrite_rules'", fn );
  234. }
  235. var wordpress = module.exports = {
  236. getPageId: auto( getPostId ),
  237. createPage: auto(function( data, package, meta, fn ) {
  238. Step(
  239. function() {
  240. createOrUpdatePost( data, this );
  241. },
  242. function( error, id ) {
  243. if ( error ) {
  244. return fn( error );
  245. }
  246. this.parallel()( null, id );
  247. setMeta( id, "package_json", JSON.stringify( package ), this.parallel() );
  248. for ( var key in meta ) {
  249. setMeta( id, key, meta[ key ], this.parallel() );
  250. }
  251. setTerms( id, package.keywords, this.parallel() );
  252. },
  253. function( error, id ) {
  254. if ( error ) {
  255. return fn( error );
  256. }
  257. fn( null, id );
  258. }
  259. );
  260. }),
  261. publish: auto(function( plugin, fn ) {
  262. Step(
  263. function() {
  264. requirePostId( plugin, this );
  265. },
  266. function( error, id ) {
  267. if ( error ) {
  268. return fn( error );
  269. }
  270. publishPost( id, fn );
  271. }
  272. );
  273. }),
  274. getVersions: auto(function( plugin, fn ) {
  275. Step(
  276. function() {
  277. getPostId( plugin, this );
  278. },
  279. function( error, id ) {
  280. if ( error ) {
  281. return fn( error );
  282. }
  283. if ( !id ) {
  284. return fn( null, [] );
  285. }
  286. getMeta( id, "versions", this );
  287. },
  288. function( error, versions ) {
  289. if ( error ) {
  290. return fn( error );
  291. }
  292. fn( null, versions ? JSON.parse( versions ) : [] );
  293. }
  294. );
  295. }),
  296. setVersions: auto(function( plugin, versions, latest, fn ) {
  297. Step(
  298. function() {
  299. requirePostId( plugin, this );
  300. },
  301. function( error, id ) {
  302. if ( error ) {
  303. return fn( error );
  304. }
  305. setMeta( id, "versions", JSON.stringify( versions ), this.parallel() );
  306. setMeta( id, "latest", latest, this.parallel() );
  307. },
  308. function( error ) {
  309. fn( error );
  310. }
  311. );
  312. }),
  313. setMeta: auto(function( plugin, meta, fn ) {
  314. Step(
  315. function() {
  316. requirePostId( plugin, this );
  317. },
  318. function( error, id ) {
  319. if ( error ) {
  320. return fn( error );
  321. }
  322. for ( var key in meta ) {
  323. setMeta( id, key, meta[ key ], this.parallel() );
  324. }
  325. },
  326. function( error ) {
  327. fn( error );
  328. }
  329. );
  330. }),
  331. flush: auto( flush ),
  332. end: function() {
  333. if ( db ) {
  334. db.end();
  335. db = null;
  336. }
  337. },
  338. _reset: auto(function( fn ) {
  339. var path = require( "path" );
  340. Step(
  341. // remove existing content
  342. function() {
  343. var group = this.group();
  344. // remove existing content
  345. [
  346. postmetaTable,
  347. postsTable,
  348. termsTable,
  349. termRelationshipsTable,
  350. termTaxonomyTable
  351. ].forEach(function( table ) {
  352. db.query( "TRUNCATE TABLE `" + table + "`", group() );
  353. });
  354. },
  355. // create update page
  356. function( error ) {
  357. if ( error ) {
  358. return fn( error );
  359. }
  360. db.query( "INSERT INTO `" + postsTable + "` " +
  361. "SET `post_type` = 'page', `post_name` = 'update', `post_title` = 'update', " +
  362. "`post_status` = 'publish', `post_content_filtered` = ?",
  363. [ path.resolve( __dirname, "update.js" ) ], this );
  364. },
  365. // set page template for update page
  366. function( error, info ) {
  367. if ( error ) {
  368. return fn( error );
  369. }
  370. setMeta( info.insertId, "_wp_page_template", "post-receive.php", this );
  371. },
  372. // find all documentation pages to create
  373. function( error ) {
  374. if ( error ) {
  375. return fn( error );
  376. }
  377. fs.readdir( path.resolve( __dirname, "../pages" ), this );
  378. },
  379. // read in documentation pages
  380. function( error, files ) {
  381. if ( error ) {
  382. return fn( error );
  383. }
  384. this.parallel()( null, files );
  385. var group = this.group();
  386. files.forEach(function( file ) {
  387. fs.readFile( path.resolve( __dirname, "../pages", file ), "utf8", group() );
  388. });
  389. },
  390. // generate documentation pages
  391. function( error, files, contents ) {
  392. if ( error ) {
  393. return fn( error );
  394. }
  395. var group = this.group();
  396. contents.forEach(function( content, i ) {
  397. var lines = content.split( "\n" ),
  398. title = lines.shift();
  399. lines.shift();
  400. createPost({
  401. name: "_" + files[ i ],
  402. title: title,
  403. content: lines.join( "\n" ),
  404. date: new Date()
  405. }, group() );
  406. });
  407. },
  408. // set page template for documentation pages
  409. function( error, pageIds ) {
  410. if ( error ) {
  411. return fn( error );
  412. }
  413. var group = this.group();
  414. pageIds.forEach(function( id ) {
  415. setMeta( id, "_wp_page_template", "blank-page.php", group() );
  416. });
  417. },
  418. // clear rewrite rules
  419. function( error ) {
  420. if ( error ) {
  421. return fn( error );
  422. }
  423. wordpress.flush( this );
  424. },
  425. // close database connection
  426. function( error ) {
  427. wordpress.end();
  428. fn( error );
  429. }
  430. );
  431. })
  432. };