Fork de wikipp, le moteur de wiki en c++, basé sur cppcms. Le fork ajoute la langue française
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

page.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. #include "page.h"
  2. #include "page_content.h"
  3. #include "wiki.h"
  4. #include "diff.h"
  5. #include <booster/posix_time.h>
  6. #include <cppcms/url_dispatcher.h>
  7. #include <cppcms/cache_interface.h>
  8. #define _(X) ::cppcms::locale::translate(X)
  9. namespace content {
  10. // Page content
  11. page_form::page_form(apps::wiki *_w):
  12. w(_w)
  13. {
  14. title.message(_("Title"));
  15. content.message(_("Content"));
  16. pad_url.message(_("Pad URL"));
  17. sidebar.message(_("Sidebar"));
  18. save.value(_("Save"));
  19. save_cont.value(_("Save and Continue"));
  20. preview.value(_("Preview"));
  21. fields.add(title);
  22. fields.add(content);
  23. fields.add(pad_url);
  24. fields.add(sidebar);
  25. buttons.add(save);
  26. buttons.add(save_cont);
  27. buttons.add(preview);
  28. buttons.add(users_only);
  29. add(fields);
  30. add(buttons);
  31. users_only.help(_("Disable editing by visitors"));
  32. users_only.error_message(_("Please Login"));
  33. title.non_empty();
  34. content.rows(25);
  35. content.cols(60);
  36. sidebar.rows(10);
  37. sidebar.cols(60);
  38. }
  39. bool page_form::validate()
  40. {
  41. bool res=form::validate();
  42. if(users_only.value() && !w->users.auth()) {
  43. users_only.valid(false);
  44. users_only.value(false);
  45. return false;
  46. }
  47. return res;
  48. }
  49. } // namespace content
  50. namespace apps {
  51. page::page(wiki &w):
  52. master(w)
  53. {
  54. wi.dispatcher().assign("^/page/(\\w+)/version/(\\d+)$",&page::display_ver,this,1,2);
  55. wi.dispatcher().assign("^/page/(\\w+)/?$",&page::display,this,1);
  56. wi.dispatcher().assign("^/page/(\\w+)/edit(/version/(\\d+))?$",&page::edit,this,1,3);
  57. wi.dispatcher().assign("^/page/(\\w+)/history(/|/(\\d+))?$",&page::history,this,1,3);
  58. wi.dispatcher().assign("^/page/(\\w+)/diff/(\\d+)vs(\\d+)/?$",&page::diff,this,1,2,3);
  59. }
  60. std::string page::diff_url(int v1,int v2,std::string l,std::string s)
  61. {
  62. if(l.empty()) l=locale_name;
  63. if(s.empty()) s=slug;
  64. return wi.root(l) +
  65. (booster::locale::format("/page/{1}/diff/{2}vs{3}") % s % v1 % v2).str();
  66. }
  67. std::string page::page_url(std::string l,std::string s)
  68. {
  69. if(l.empty()) l=locale_name;
  70. if(s.empty()) s=slug;
  71. return wi.root(l)+"/page/"+s;
  72. }
  73. std::string page::page_version_url(int ver,std::string l,std::string s)
  74. {
  75. if(l.empty()) l=locale_name;
  76. if(s.empty()) s=slug;
  77. return wi.root(l)+
  78. (booster::locale::format("/page/{1}/version/{2}") % s % ver).str();
  79. }
  80. std::string page::edit_url()
  81. {
  82. return wi.root()+"/page/"+slug+"/edit";
  83. }
  84. std::string page::edit_version_url(int ver)
  85. {
  86. return (booster::locale::format(edit_url()+"/version/{1}") % ver).str();
  87. }
  88. std::string page::history_url(int n)
  89. {
  90. std::string u=wi.root()+"/page/"+slug+"/history/";
  91. if(n)
  92. u+=(booster::locale::format("{1}") % n).str();
  93. return u;
  94. }
  95. void page::diff(std::string slug,std::string sv1,std::string sv2)
  96. {
  97. int v1=atoi(sv1.c_str()), v2=atoi(sv2.c_str());
  98. this->slug=slug;
  99. cppdb::session sql(conn);
  100. cppdb::result r;
  101. content::diff c;
  102. c.v1=v1;
  103. c.v2=v2;
  104. c.edit_v1=edit_version_url(v1);
  105. c.edit_v2=edit_version_url(v2);
  106. r=sql<< "SELECT version,history.title,history.content,history.pad_url,history.sidebar,pages.title FROM pages "
  107. "JOIN history ON pages.id=history.id "
  108. "WHERE lang=? AND slug=? AND version IN (?,?) " << locale_name << slug << v1 << v2;
  109. std::string t1,c1,p1,s1,t2,c2,p2,s2;
  110. int count=0;
  111. while(r.next()) {
  112. int ver;
  113. r>>ver;
  114. if(ver==v1) {
  115. r>>t1>>c1>>p2>>s1>>c.title;
  116. }
  117. else {
  118. r>>t2>>c2>>p2>>s2;
  119. }
  120. count++;
  121. }
  122. if(count != 2) {
  123. c.no_versions=true;
  124. master::ini(c);
  125. render("diff",c);
  126. return;
  127. }
  128. if(t1!=t2) {
  129. c.title_diff=true;
  130. c.title_1=t1;
  131. c.title_2=t2;
  132. }
  133. else {
  134. c.title=t1;
  135. }
  136. if(c1!=c2) {
  137. c.content_diff=true;
  138. std::vector<std::string> X=split(c1);
  139. std::vector<std::string> Y=split(c2);
  140. diff::diff(X,Y,c.content_diff_content);
  141. }
  142. if(p1!=p2) {
  143. c.pad_url_diff=true;
  144. std::vector<std::string> X=split(p1);
  145. std::vector<std::string> Y=split(p2);
  146. diff::diff(X,Y,c.pad_url_diff_content);
  147. }
  148. if(s1!=s2) {
  149. c.sidebar_diff=true;
  150. std::vector<std::string> X=split(s1);
  151. std::vector<std::string> Y=split(s2);
  152. diff::diff(X,Y,c.sidebar_diff_content);
  153. }
  154. if(t1==t2 && c1==c2 && p1==p2 && s1==s2)
  155. c.no_diff=true;
  156. master::ini(c);
  157. render("diff",c);
  158. }
  159. void page::history(std::string slug,std::string page)
  160. {
  161. this->slug=slug;
  162. unsigned const vers=10;
  163. int offset;
  164. content::history c;
  165. master::ini(c);
  166. if(page.empty())
  167. offset=0;
  168. else
  169. offset=atoi(page.c_str());
  170. cppdb::session sql(conn);
  171. cppdb::result r;
  172. r=sql<< "SELECT title,id FROM pages "
  173. "WHERE pages.lang=? AND pages.slug=? " << locale_name << slug << cppdb::row;
  174. if(r.empty()) {
  175. redirect(locale_name);
  176. return;
  177. }
  178. int id;
  179. r>>c.title>>id;
  180. r=sql<< "SELECT created,version,author FROM history "
  181. "WHERE id=? "
  182. "ORDER BY version DESC "
  183. "LIMIT ? "
  184. "OFFSET ?"
  185. <<id << vers+1 << offset*vers;
  186. c.hist.reserve(vers);
  187. for(unsigned i=0;r.next() && i<vers;i++) {
  188. int ver;
  189. c.hist.resize(i+1);
  190. std::tm update = std::tm();
  191. r>> update >> ver >> c.hist[i].author ;
  192. c.hist[i].update = mktime(&update);
  193. c.hist[i].version=ver;
  194. c.hist[i].show_url=page_version_url(ver);
  195. c.hist[i].edit_url=edit_version_url(ver);
  196. if(ver>1)
  197. c.hist[i].diff_url=diff_url(ver-1,ver);
  198. }
  199. if(r.next()) {
  200. c.page=history_url(offset+1);
  201. }
  202. c.page_link=page_url();
  203. render("history",c);
  204. }
  205. void page::display(std::string slug)
  206. {
  207. this->slug=slug;
  208. std::string key="article_"+locale_name+":"+slug;
  209. // if(cache().fetch_page(key))
  210. // return;
  211. content::page c;
  212. cppdb::session sql(conn);
  213. cppdb::result r;
  214. r=sql<< "SELECT title,content,sidebar FROM pages WHERE lang=? AND slug=?"
  215. <<locale_name << slug << cppdb::row;
  216. if(r.empty()) {
  217. std::string redirect=edit_url();
  218. std::cerr << " Page " << redirect << std::endl;
  219. response().set_redirect_header(redirect);
  220. return;
  221. }
  222. ini(c);
  223. r >> c.title >> c.content >> c.sidebar;
  224. render("page",c);
  225. cache().store_page(key);
  226. }
  227. void page::ini(content::page &c)
  228. {
  229. master::ini(c);
  230. c.edit_link=edit_url();
  231. c.history_link=history_url();
  232. }
  233. void page::edit(std::string slug,std::string version)
  234. {
  235. this->slug=slug;
  236. content::edit_page c(&wi);
  237. if(request().request_method()=="POST") {
  238. if(!edit_on_post(c))
  239. return;
  240. }
  241. else {
  242. if(version.empty()) {
  243. c.new_page=!load(c.form);
  244. if(c.new_page) {
  245. wi.options.load();
  246. c.form.users_only.value(wi.options.global.users_only_edit);
  247. }
  248. }
  249. else {
  250. int ver=atoi(version.c_str());
  251. if(!load_history(ver,c.form)) {
  252. redirect(locale_name,slug);
  253. return;
  254. }
  255. }
  256. if(c.form.users_only.value() && !wi.users.auth()) {
  257. wi.users.error_forbidden();
  258. }
  259. }
  260. ini(c);
  261. c.back=page_url();
  262. c.submit=edit_url();
  263. render("edit_page",c);
  264. }
  265. bool page::load(content::page_form &form)
  266. {
  267. cppdb::session sql(conn);
  268. cppdb::result r;
  269. r=sql<< "SELECT title,content,pad_url,sidebar,users_only "
  270. "FROM pages WHERE lang=? AND slug=?" << locale_name << slug << cppdb::row;
  271. if(!r.empty()) {
  272. std::string title,content,pad_url,sidebar;
  273. int users_only;
  274. r >> title >> content >> pad_url >> sidebar >> users_only;
  275. form.title.value(title);
  276. form.content.value(content);
  277. form.pad_url.value(pad_url);
  278. form.sidebar.value(sidebar);
  279. form.users_only.value(users_only);
  280. return true;
  281. }
  282. wi.options.load();
  283. form.users_only.set(wi.options.global.users_only_edit);
  284. return false;
  285. }
  286. void page::redirect(std::string loc,std::string slug)
  287. {
  288. std::string redirect=page_url(loc,slug);
  289. response().set_redirect_header(redirect);
  290. }
  291. void page::save(int id,content::page_form &form,cppdb::session &sql)
  292. {
  293. std::tm t = booster::ptime::local_time(booster::ptime::now());
  294. wi.users.auth();
  295. if(id!=-1) {
  296. sql<< "UPDATE pages SET content=?,title=?,pad_url=?,sidebar=?,users_only=? "
  297. "WHERE lang=? AND slug=?"
  298. << form.content.value() << form.title.value() << form.pad_url.value()
  299. << form.sidebar.value() << form.users_only.value()
  300. << locale_name << slug << cppdb::exec;
  301. }
  302. else {
  303. cppdb::statement s;
  304. s=sql<< "INSERT INTO pages(lang,slug,title,content,pad_url,sidebar,users_only) "
  305. "VALUES(?,?,?,?,?,?,?)"
  306. << locale_name << slug
  307. << form.title.value()
  308. << form.content.value()
  309. << form.pad_url.value()
  310. << form.sidebar.value()
  311. << form.users_only.value();
  312. s.exec();
  313. id=s.sequence_last("pages_id_seq");
  314. }
  315. sql<< "INSERT INTO history(id,version,created,title,content,pad_url,sidebar,author) "
  316. "SELECT ?,"
  317. " (SELECT COALESCE(MAX(version),0)+1 FROM history WHERE id=?),"
  318. " ?,?,?,?,?,?"
  319. << id << id << t
  320. << form.title.value()
  321. << form.content.value()
  322. << form.pad_url.value()
  323. << form.sidebar.value()
  324. << wi.users.username
  325. << cppdb::exec;
  326. }
  327. bool page::edit_on_post(content::edit_page &c)
  328. {
  329. wi.options.load();
  330. cppdb::session sql(conn);
  331. cppdb::transaction tr(sql);
  332. cppdb::result r;
  333. r=sql<< "SELECT id,users_only FROM pages WHERE lang=? and slug=?" << locale_name << slug << cppdb::row;
  334. int id=-1,users_only=wi.options.global.users_only_edit;
  335. if(!r.empty()) {
  336. r>>id>>users_only;
  337. }
  338. r.clear();
  339. if(users_only && !wi.users.auth()) {
  340. wi.users.error_forbidden();
  341. return false;
  342. }
  343. c.form.load(context());
  344. if(c.form.validate()) {
  345. if(c.form.save.value() || c.form.save_cont.value()) {
  346. save(id,c.form,sql);
  347. cache().rise("article_"+locale_name+":"+slug);
  348. }
  349. if(c.form.save.value()) {
  350. redirect(locale_name,slug);
  351. tr.commit();
  352. return false;
  353. }
  354. if(c.form.preview.value()) {
  355. c.title=c.form.title.value();
  356. c.content=c.form.content.value();
  357. c.pad_url=c.form.pad_url.value();
  358. c.sidebar=c.form.sidebar.value();
  359. }
  360. }
  361. tr.commit();
  362. return true;
  363. }
  364. bool page::load_history(int ver,content::page_form &form)
  365. {
  366. cppdb::session sql(conn);
  367. cppdb::result r;
  368. r=sql<< "SELECT history.title,history.content,history.pad_url,history.sidebar,pages.users_only "
  369. "FROM pages "
  370. "JOIN history ON pages.id=history.id "
  371. "WHERE pages.lang=? AND pages.slug=? AND history.version=?"
  372. <<locale_name<<slug<<ver<<cppdb::row;
  373. if(!r.empty()) {
  374. std::string title,content,pad_url,sidebar;
  375. int uonly;
  376. r >> title >> content >> pad_url >> sidebar >> uonly;
  377. form.title.value(title);
  378. form.content.value(content);
  379. form.pad_url.value(pad_url);
  380. form.sidebar.value(sidebar);
  381. form.users_only.value(uonly);
  382. return true;
  383. }
  384. return false;
  385. }
  386. void page::display_ver(std::string slug,std::string sid)
  387. {
  388. this->slug=slug;
  389. content::page_hist c;
  390. int id=atoi(sid.c_str());
  391. cppdb::result r;
  392. cppdb::session sql(conn);
  393. r=sql<< "SELECT history.title,history.content,history.pad_url,history.sidebar,history.created "
  394. "FROM pages "
  395. "JOIN history ON pages.id=history.id "
  396. "WHERE pages.lang=? AND pages.slug=? AND history.version=?"
  397. <<locale_name << slug << id << cppdb::row;
  398. if(!r.empty()) {
  399. redirect(locale_name,slug);
  400. return;
  401. }
  402. std::tm date;
  403. r>>c.title>>c.content>>c.sidebar>>date;
  404. c.date = mktime(&date);
  405. c.version=id;
  406. c.rollback=edit_version_url(id);
  407. ini(c);
  408. render("page_hist",c);
  409. }
  410. }