Fork de wikipp, le moteur de wiki en c++, basé sur cppcms. Le fork ajoute la langue française
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

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. }