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.
gnosygnu_xowa/400_xowa/src/gplx/xowa/wikis/pages/Xow_page_mgr.java

199 lines
10 KiB

/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.wikis.pages; import gplx.*; import gplx.xowa.*; import gplx.xowa.wikis.*;
import gplx.xowa.wikis.nss.*; import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*; import gplx.xowa.langs.vnts.*;
import gplx.xowa.guis.views.*; import gplx.xowa.parsers.utils.*;
import gplx.xowa.wikis.pages.dbs.*; import gplx.xowa.wikis.pages.redirects.*;
public class Xow_page_mgr implements Gfo_invk {
private final Xowe_wiki wiki;
public Xow_page_mgr(Xowe_wiki wiki) {this.wiki = wiki;}
public Xoae_page Load_page_by_ttl (Xoa_ttl ttl) {return Load_page(ttl, Bool_.N);}
public Xoae_page Load_page_by_ttl_for_msg (Xoa_ttl ttl) {return Load_page(ttl, Bool_.Y);}
private Xoae_page Load_page(Xoa_ttl ttl, boolean called_from_msg) {
Xoae_page rv = Xoae_page.New(wiki, ttl);
Load_by_ns(rv, wiki.Utl__url_parser().Parse(ttl.Raw()), ttl, called_from_msg);
return rv;
}
private void Load_by_ns(Xoae_page rv, Xoa_url url, Xoa_ttl ttl, boolean called_from_msg) {
rv.Url_(url); // NOTE: must update page.Url(); should combine with Xoae_page.New()
// WORKAROUND: loop twice in order to allow redirects from regular page to special
for (int i = 0; i < 2; i++) {
Xow_ns ns = ttl.Ns();
switch (ns.Id()) {
case Xow_ns_.Tid__special: // Special pages are built (not loaded from db)
wiki.Special_mgr().Special__gen(wiki.App(), wiki, rv, url, ttl);
Xopg_redirect_itm redirect_itm = rv.Redirect_trail().Itms__get_at_nth_or_null();
if (redirect_itm != null) {
rv.Redirect_trail().Clear(); // clear needed; EX: Special:Random -> [[Redirected_page]] -> {must clear here} -> [[Page]]
Load_by_ns(rv, redirect_itm.Url(), redirect_itm.Ttl(), called_from_msg);
}
return;
case Xow_ns_.Tid__mediawiki: // MediaWiki msgs can either be loaded from memory, or from database
if ( !called_from_msg // if called_from_msg, fall through to actual data retrieval below, else infinite loop; DATE:2014-05-09
&& Xow_page_tid.Identify_by_ttl(ttl.Page_db()) == Xow_page_tid.Tid_wikitext // skip ".js" and ".css" pages in MediaWiki; DATE:2014-06-13
) {
Xol_lang_itm lang = wiki.Lang();
byte[] msg_key = ttl.Page_db();
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_b512();
msg_key = lang.Case_mgr().Case_build_1st_lower(tmp_bfr, msg_key, 0, msg_key.length);
byte[] msg_val = Xol_msg_mgr_.Get_msg_itm(tmp_bfr, wiki, wiki.Lang(), msg_key).Val(); // NOTE: do not change to Get_msg_val; Get_msg_val, also replaces $1 with values, and $1 needs to be preserved for callers;
rv.Db().Text().Text_bry_(msg_val);
tmp_bfr.Mkr_rls();
return;
}
break;
}
Xoa_ttl redirect_ttl = Load_from_db(rv, ns, ttl, url.Qargs_mgr().Match(Xoa_url_.Qarg__redirect, Xoa_url_.Qarg__redirect__no));
// GOTO_BY_LOOP: handle redirect to special
if (redirect_ttl != null && redirect_ttl.Ns().Id_is_special()) {
ttl = redirect_ttl;
url = wiki.Utl__url_parser().Parse(ttl.Raw()); // update url w/ redirected ttl; need to update qargs else will redirect to correct ttl (Special:XowaCfg) but not qargs (grp=xowa.addon.math); EX:src=Options/Math; trg=Special:XowaCfg?grp=xowa.addon.math; DATE:2017-01-02
rv.Redirect_trail().Clear();
rv.Db().Page().Exists_y_();
}
// not a redirect to special; just exit
else
return;
}
}
public Xoa_ttl Load_from_db(Xoae_page rv, Xow_ns ns, Xoa_ttl ttl, boolean redirect_force) {
int redirects = 0;
Xowd_page_itm page_row = Xowd_page_itm.new_tmp();
while (true) { // loop until (a) no more redirects or (b) page not found
// load from page table
boolean exists = wiki.Db_mgr().Load_mgr().Load_by_ttl(page_row, ns, ttl.Page_db());
if (!exists) {rv.Db().Page().Exists_n_(); return ttl;}
if (wiki.App().Mode().Tid_is_gui()) // NOTE: must check if gui, else will write during mass build; DATE:2014-05-03
wiki.Appe().Usr_dlg().Prog_many("", "", "loading page for ~{0}", ttl.Raw());
// load page_info
rv.Db().Page().Id_(page_row.Id()).Modified_on_(page_row.Modified_on()).Html_db_id_(page_row.Html_db_id());
// load from text table
wiki.Db_mgr().Load_mgr().Load_page(page_row, ns);
byte[] wtxt = page_row.Text();
rv.Db().Text().Text_bry_(wtxt);
if (redirect_force) return ttl; // redirect_force passed; return page now, even if page is a redirect elsewhere; NOTE: only applies to WTXT, not HTML
// handle redirects for html_dbs
if ( page_row.Redirect_id() > 0 // redirect exists
&& Bry_.Len_eq_0(wtxt)) { // wikitext is not found
Redirect_to_html_page(rv, wiki, page_row);
return ttl;
}
// handle redirects
Xoa_ttl redirect_ttl = wiki.Redirect_mgr().Extract_redirect(wtxt);
if ( redirect_ttl == null // not a redirect
|| redirects++ > 4) // too many redirects; something went wrong
return redirect_ttl;
// redirect; do some bookkeeping and reset ns / ttl
// NOTE: this adds the target ttl to redirect_mgr (#REDIRECT [[A]]); note that special redirects will add source ttl; DATE:2016-07-31
rv.Redirect_trail().Itms__add__article(Xoa_url.New(wiki, rv.Ttl()), rv.Ttl(), wtxt);// NOTE: must be url_encoded; EX: "en.wikipedia.org/?!" should generate link of "en.wikipedia.org/%3F!?redirect=no"
rv.Ttl_(redirect_ttl);
ns = redirect_ttl.Ns();
ttl = redirect_ttl;
}
}
private void Redirect_to_html_page(Xoae_page rv, Xowe_wiki wiki, Xowd_page_itm page_row) { // handle redirects for HtmlDbs; PAGE:fr.b:Wikibooks DATE:2016-07-14
// load redirect
Xowd_page_itm redirect_row = new Xowd_page_itm();
wiki.Db_mgr().Load_mgr().Load_by_id(redirect_row, page_row.Redirect_id());
if (rv.Db().Page().Exists_n()) {
return;
}
// set redirect data
rv.Db().Page().Id_(redirect_row.Id()).Modified_on_(redirect_row.Modified_on()).Html_db_id_(redirect_row.Html_db_id());
Xoa_ttl redirect_ttl = wiki.Ttl_parse(redirect_row.Ns_id(), redirect_row.Ttl_page_db());
rv.Ttl_(redirect_ttl);
rv.Redirect_trail().Itms__add__article(Xoa_url.New(wiki, redirect_ttl), redirect_ttl, Bry_.Empty); // NOTE: must be url_encoded; EX: "en.wikipedia.org/?!" should generate link of "en.wikipedia.org/%3F!?redirect=no"
}
public Xoae_page Load_page_and_parse(Xoa_url url, Xoa_ttl ttl) {return Load_page_and_parse(url, ttl, wiki.Lang(), wiki.Appe().Gui_mgr().Browser_win().Active_tab(), true);}
public Xoae_page Load_page_and_parse(Xoa_url url, Xoa_ttl ttl, Xol_lang_itm lang, Xog_tab_itm tab, boolean parse_page) {
wiki.Init_assert();
Xoae_page page = Xoae_page.New(wiki, ttl); page.Tab_data().Tab_(tab);
// COMMENT: breaks position-restore when moving back from history; if (tab != null) tab.Page_ref_(page); // HACK: (1) null check for http server; (2) Page_ref_(page) needed for log in xobc
this.Load_by_ns(page, url, ttl, false);
if (page.Db().Page().Exists_n()) { // page doesn't exist; try variants
boolean vnt_missing = true;
Xol_vnt_mgr vnt_mgr = lang.Vnt_mgr();
if (vnt_mgr.Enabled()) { // if vnt enabled, then try to load by vnt form; DATE:2015-09-15
gplx.xowa.wikis.data.tbls.Xowd_page_itm page_itm = vnt_mgr.Convert_mgr().Convert_ttl(wiki, ttl);
if (page_itm != null && page_itm.Exists()) {
Xoa_ttl vnt_ttl = Xoa_ttl.Parse(wiki, ttl.Ns().Id(), page_itm.Ttl_page_db());
page = this.Load_page(vnt_ttl, false);
vnt_missing = page.Db().Page().Exists_n();
}
}
if (vnt_missing) {
if (ttl.Ns().Id_is_file()) {
Xowe_wiki commons_wiki = (Xowe_wiki)wiki.Appe().Wiki_mgr().Get_by_or_null(wiki.Commons_wiki_key());
if (commons_wiki != null) { // commons exists
if (!Bry_.Eq(wiki.Domain_bry(), commons_wiki.Domain_bry())) { // !Bry_.Eq is recursion guard
Xoae_page rv = commons_wiki.Data_mgr().Load_page_and_parse(url, ttl, wiki.Lang(), tab, true);
if (rv.Db().Page().Exists()) {
rv.Commons_mgr().Source_wiki_(wiki);
return rv;
}
else {
rv.Db().Page().Exists_y_();
page.Commons_mgr().Xowa_mockup_(true);
return page;
}
}
}
}
else {
page.Db().Page().Exists_n_();
return page;
}
}
}
if (page.Db().Page().Exists_n()) return page; // NOTE: commons can return null page
page.Tab_data().Tab_(tab);
page.Lang_(lang);
if (parse_page)
wiki.Parser_mgr().Parse(page, false); // NOTE: do not clear page b/c reused for search
return page;
}
public void Redirect(Xoae_page page, byte[] page_bry) {
Xoa_ttl trg_ttl = Xoa_ttl.Parse(wiki, page_bry);
Xoa_url trg_url = Xoa_url.New(wiki.Domain_bry(), page_bry);
page.Ttl_(trg_ttl).Url_(trg_url);
page.Redirect_trail().Itms__add__article(trg_url, trg_ttl, null);
wiki.Data_mgr().Load_from_db(page, trg_ttl.Ns(), trg_ttl, trg_url.Qargs_mgr().Match(Xoa_url_.Qarg__redirect, Xoa_url_.Qarg__redirect__no));
}
public void RedirectWithoutLoading(Xoae_page page, byte[] ttl_bry) {
// ISSUE#:719:redirect should not call .Load_from_db else redirect info will get lost; EX:"Redirected from trg_ttl" instead of "Redirected from src_ttl"; PAGE:en.s; DATE:2020-05-13
Xoa_ttl ttl = Xoa_ttl.Parse(wiki, ttl_bry);
Xoa_url url = Xoa_url.New(wiki.Domain_bry(), ttl.Full_db());
page.Ttl_(ttl).Url_(url);
page.Redirect_trail().Itms__add__article(url, ttl, null);
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_create_enabled_)) wiki.Db_mgr().Save_mgr().Create_enabled_(m.ReadYn("v"));
else if (ctx.Match(k, Invk_update_modified_on_enabled_)) wiki.Db_mgr().Save_mgr().Update_modified_on_enabled_(m.ReadYn("v"));
else return Gfo_invk_.Rv_unhandled;
return this;
}
private static final String Invk_create_enabled_ = "create_enabled_", Invk_update_modified_on_enabled_ = "update_modified_on_enabled_";
}