Fork de wikipp, le moteur de wiki en c++, basé sur cppcms. Le fork ajoute la langue française
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

page.cpp 10.0KB

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