~bibledit/bibledit/ubuntu-cloud

« back to all changes in this revision

Viewing changes to resource/logic.cpp

  • Committer: Teus Benschop
  • Date: 2022-08-30 18:42:32 UTC
  • Revision ID: teusjannette@gmail.com-20220830184232-a5bf5fkj14cqdx01
new upstream version

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
#include <filter/shell.h>
38
38
#include <filter/roles.h>
39
39
#include <filter/diff.h>
 
40
#include <filter/google.h>
40
41
#include <resource/external.h>
41
42
#include <locale/translate.h>
42
43
#include <client/logic.h>
137
138
{
138
139
  Webserver_Request * request = static_cast<Webserver_Request *>(webserver_request);
139
140
 
140
 
  string html;
141
 
 
142
141
  // Determine the type of the resource.
143
 
  bool isBible = resource_logic_is_bible (resource);
144
 
  bool isUsfm = resource_logic_is_usfm (resource);
145
 
  bool isExternal = resource_logic_is_external (resource);
146
 
  bool isImage = resource_logic_is_image (resource);
147
 
  bool isLexicon = resource_logic_is_lexicon (resource);
148
 
  bool isSword = resource_logic_is_sword (resource);
149
 
  bool isBibleGateway = resource_logic_is_biblegateway (resource);
150
 
  bool isStudyLight = resource_logic_is_studylight (resource);
151
 
  bool isComparative = resource_logic_is_comparative (resource);
 
142
  bool is_bible = resource_logic_is_bible (resource);
 
143
  bool is_usfm = resource_logic_is_usfm (resource);
 
144
  bool is_external = resource_logic_is_external (resource);
 
145
  bool is_image = resource_logic_is_image (resource);
 
146
  bool is_lexicon = resource_logic_is_lexicon (resource);
 
147
  bool is_sword = resource_logic_is_sword (resource);
 
148
  bool is_bible_gateway = resource_logic_is_biblegateway (resource);
 
149
  bool is_study_light = resource_logic_is_studylight (resource);
 
150
  bool is_comparative = resource_logic_is_comparative (resource);
 
151
  bool is_translated = resource_logic_is_translated(resource);
152
152
 
153
153
  // Handle a comparative resource.
154
154
  // This type of resource is special.
155
155
  // It is not one resource, but made out of two resources.
156
156
  // It fetches data from two resources and combines that into one.
157
 
  if (isComparative) {
 
157
  if (is_comparative) {
158
158
#ifdef HAVE_CLOUD
159
 
    html = resource_logic_cloud_get_comparison (webserver_request, resource, book, chapter, verse, add_verse_numbers);
 
159
    return resource_logic_cloud_get_comparison (webserver_request, resource, book, chapter, verse, add_verse_numbers);
160
160
#endif
161
161
#ifdef HAVE_CLIENT
162
 
    html = resource_logic_client_fetch_cache_from_cloud (resource, book, chapter, verse);
 
162
    return resource_logic_client_fetch_cache_from_cloud (resource, book, chapter, verse);
163
163
#endif
164
 
    return html;
165
164
  }
166
165
 
 
166
  // Handle a translated resource.
 
167
  // This type of resource is special.
 
168
  // It consists of any of the other types of resources, as the base resource.
 
169
  // It gets that data, and then has that translated.
 
170
  if (is_translated) {
 
171
#ifdef HAVE_CLOUD
 
172
    return resource_logic_cloud_get_translation (webserver_request, resource, book, chapter, verse, add_verse_numbers);
 
173
#endif
 
174
#ifdef HAVE_CLIENT
 
175
    return resource_logic_client_fetch_cache_from_cloud (resource, book, chapter, verse);
 
176
#endif
 
177
  }
 
178
  
167
179
  Database_Mappings database_mappings;
168
180
 
169
181
  // Retrieve versification system of the active Bible.
172
184
 
173
185
  // Determine the versification system of the current resource.
174
186
  string resource_versification;
175
 
  if (isBible || isUsfm) {
 
187
  if (is_bible || is_usfm) {
176
188
    resource_versification = Database_Config_Bible::getVersificationSystem (bible);
177
 
  } else if (isExternal) {
 
189
  } else if (is_external) {
178
190
    resource_versification = resource_external_mapping (resource);
179
 
  } else if (isImage) {
180
 
  } else if (isLexicon) {
 
191
  } else if (is_image) {
 
192
  } else if (is_lexicon) {
181
193
    resource_versification = database_mappings.original ();
182
194
    if (resource == KJV_LEXICON_NAME) resource_versification = english ();
183
 
  } else if (isSword) {
184
 
    resource_versification = english ();
185
 
  } else if (isBibleGateway) {
186
 
    resource_versification = english ();
187
 
  } else if (isStudyLight) {
 
195
  } else if (is_sword) {
 
196
    resource_versification = english ();
 
197
  } else if (is_bible_gateway) {
 
198
    resource_versification = english ();
 
199
  } else if (is_study_light) {
188
200
    resource_versification = english ();
189
201
  } else {
190
202
  }
202
214
  // If there's been a mapping, the resource should include the verse number for clarity.
203
215
  if (passages.size () != 1) add_verse_numbers = true;
204
216
  for (auto passage : passages) {
205
 
    if (verse != convert_to_int (passage.verse)) {
 
217
    if (verse != convert_to_int (passage.m_verse)) {
206
218
      add_verse_numbers = true;
207
219
    }
208
220
  }
227
239
        if (resource_versification != database_mappings.original ()) {
228
240
          passages.clear ();
229
241
          for (auto & related_passage : related_passages) {
230
 
            vector <Passage> mapped_passages = database_mappings.translate (database_mappings.original (), resource_versification, related_passage.book, related_passage.chapter, convert_to_int (related_passage.verse));
 
242
            vector <Passage> mapped_passages = database_mappings.translate (database_mappings.original (), resource_versification, related_passage.m_book, related_passage.m_chapter, convert_to_int (related_passage.m_verse));
231
243
            passages.insert (passages.end (), mapped_passages.begin (), mapped_passages.end ());
232
244
          }
233
245
        }
234
246
      }
235
247
    }
236
248
  }
237
 
  
 
249
 
 
250
  string html;
 
251
 
238
252
  for (auto passage : passages) {
239
253
    string possible_included_passage;
240
 
    if (add_verse_numbers) possible_included_passage = passage.verse + " ";
241
 
    if (add_passages_in_full) possible_included_passage = filter_passage_display (passage.book, passage.chapter, passage.verse) + " ";
242
 
    if (isImage) possible_included_passage.clear ();
 
254
    if (add_verse_numbers) possible_included_passage = passage.m_verse + " ";
 
255
    if (add_passages_in_full) possible_included_passage = filter_passage_display (passage.m_book, passage.m_chapter, passage.m_verse) + " ";
 
256
    if (is_image) possible_included_passage.clear ();
243
257
    html.append (possible_included_passage);
244
 
    html.append (resource_logic_get_verse (webserver_request, resource, passage.book, passage.chapter, convert_to_int (passage.verse)));
 
258
    html.append (resource_logic_get_verse (webserver_request, resource, passage.m_book, passage.m_chapter, convert_to_int (passage.m_verse)));
245
259
  }
246
260
  
247
261
  return html;
278
292
    string chapter_usfm;
279
293
    if (isBible) chapter_usfm = request->database_bibles()->getChapter (resource, book, chapter);
280
294
    if (isLocalUsfm) chapter_usfm = database_usfmresources.getUsfm (resource, book, chapter);
281
 
    string verse_usfm = usfm_get_verse_text (chapter_usfm, verse);
 
295
    string verse_usfm = filter::usfm::get_verse_text (chapter_usfm, verse);
282
296
    string stylesheet = styles_logic_standard_sheet ();
283
297
    Filter_Text filter_text = Filter_Text (resource);
284
298
    filter_text.html_text_standard = new Html_Text ("");
383
397
    for (auto search_replace_set : search_replace_sets) {
384
398
      vector <string> search_replace = filter_string_explode(search_replace_set, '=');
385
399
      if (search_replace.size() == 2) {
386
 
        string search = search_replace[0];
387
 
        if (search.empty()) continue;
388
 
        string replace = search_replace[1];
389
 
        base = filter_string_str_replace(search, replace, base);
390
 
        update = filter_string_str_replace(search, replace, update);
 
400
        string search_item = search_replace[0];
 
401
        if (search_item.empty()) continue;
 
402
        string replace_item = search_replace[1];
 
403
        base = filter_string_str_replace(search_item, replace_item, base);
 
404
        update = filter_string_str_replace(search_item, replace_item, update);
391
405
      }
392
406
    }
393
407
  }
408
422
}
409
423
 
410
424
 
 
425
string resource_logic_cloud_get_translation (void * webserver_request,
 
426
                                             const string & resource, int book, int chapter, int verse,
 
427
                                             bool add_verse_numbers)
 
428
{
 
429
  // This function gets passed the resource title only.
 
430
  // So get all defined translated resources and look for the one with this title.
 
431
  // And then get the additional properties belonging to this resource.
 
432
  string title, original_resource, source_language, target_language;
 
433
  vector <string> resources = Database_Config_General::getTranslatedResources ();
 
434
  for (const auto & input : resources) {
 
435
    resource_logic_parse_translated_resource (input, &title, &original_resource, &source_language, &target_language);
 
436
    if (title == resource) break;
 
437
  }
 
438
  
 
439
  // Get the html of the resources to be translated.
 
440
  string original_text = resource_logic_get_html (webserver_request, original_resource, book, chapter, verse, add_verse_numbers);
 
441
  // Clean all html elements away from the text to get a better and cleaner translation.
 
442
  original_text = filter_string_html2text (original_text);
 
443
  
 
444
  // If the original text is empty, do not even send it to Google Translate, for saving resources.
 
445
  if (original_text.empty()) return string();
 
446
 
 
447
  // Run it through Google Translate.
 
448
  auto [ translation_success, translated_text, translation_error] = filter::google::translate (original_text, source_language.c_str(), target_language.c_str());
 
449
 
 
450
  // Done.
 
451
  if (translation_success) return translated_text;
 
452
  Database_Logs::log (translation_error);
 
453
  return "Failed to translate";
 
454
}
 
455
 
 
456
 
411
457
// This runs on the server.
412
458
// It gets the html or text contents for a $resource for serving it to a client.
413
459
string resource_logic_get_contents_for_client (string resource, int book, int chapter, int verse)
414
460
{
415
461
  // Determine the type of the current resource.
416
 
  bool isExternal = resource_logic_is_external (resource);
417
 
  bool isUsfm = resource_logic_is_usfm (resource);
418
 
  bool isSword = resource_logic_is_sword (resource);
419
 
  bool isBibleGateway = resource_logic_is_biblegateway (resource);
420
 
  bool isStudyLight = resource_logic_is_studylight (resource);
421
 
  bool isComparative = resource_logic_is_comparative (resource);
 
462
  bool is_external = resource_logic_is_external (resource);
 
463
  bool is_usfm = resource_logic_is_usfm (resource);
 
464
  bool is_sword = resource_logic_is_sword (resource);
 
465
  bool is_bible_gateway = resource_logic_is_biblegateway (resource);
 
466
  bool is_study_light = resource_logic_is_studylight (resource);
 
467
  bool is_comparative = resource_logic_is_comparative (resource);
 
468
  bool is_translated = resource_logic_is_translated(resource);
422
469
 
423
 
  if (isExternal) {
 
470
  if (is_external) {
424
471
    // The server fetches it from the web.
425
472
    return resource_external_cloud_fetch_cache_extract (resource, book, chapter, verse);
426
473
  }
427
474
  
428
 
  if (isUsfm) {
 
475
  if (is_usfm) {
429
476
    // Fetch from database and convert to html.
430
477
    Database_UsfmResources database_usfmresources;
431
478
    string chapter_usfm = database_usfmresources.getUsfm (resource, book, chapter);
432
 
    string verse_usfm = usfm_get_verse_text (chapter_usfm, verse);
 
479
    string verse_usfm = filter::usfm::get_verse_text (chapter_usfm, verse);
433
480
    string stylesheet = styles_logic_standard_sheet ();
434
481
    Filter_Text filter_text = Filter_Text (resource);
435
482
    filter_text.html_text_standard = new Html_Text ("");
438
485
    return filter_text.html_text_standard->get_inner_html ();
439
486
  }
440
487
  
441
 
  if (isSword) {
 
488
  if (is_sword) {
442
489
    // Fetch it from a SWORD module.
443
490
    string sword_module = sword_logic_get_remote_module (resource);
444
491
    string sword_source = sword_logic_get_source (resource);
445
492
    return sword_logic_get_text (sword_source, sword_module, book, chapter, verse);
446
493
  }
447
494
 
448
 
  if (isBibleGateway) {
 
495
  if (is_bible_gateway) {
449
496
    // The server fetches it from the web.
450
497
    return resource_logic_bible_gateway_get (resource, book, chapter, verse);
451
498
  }
452
499
 
453
 
  if (isStudyLight) {
 
500
  if (is_study_light) {
454
501
    // The server fetches it from the web.
455
502
    return resource_logic_study_light_get (resource, book, chapter, verse);
456
503
  }
457
504
 
458
 
  if (isComparative) {
 
505
  if (is_comparative) {
459
506
    // Handle a comparative resource.
460
507
    // This type of resource is special.
461
508
    // It is not one resource, but made out of two resources.
464
511
    return resource_logic_cloud_get_comparison (&request, resource, book, chapter, verse, false);
465
512
  }
466
513
  
 
514
  if (is_translated) {
 
515
    // Handle a translated resource.
 
516
    // This passes the resource title only
 
517
    Webserver_Request request;
 
518
    return resource_logic_cloud_get_translation (&request, resource, book, chapter, verse, false);
 
519
  }
 
520
  
467
521
  // Nothing found.
468
 
  return translate ("Bibledit Cloud could not localize this resource");
 
522
  return translate ("Bibledit Cloud could not locate this resource");
469
523
}
470
524
 
471
525
 
750
804
  if (resource_logic_create_cache_running) return;
751
805
  resource_logic_create_cache_running = true;
752
806
  
 
807
  // Get the signatures of the resources to cache.
 
808
  vector <string> signatures = Database_Config_General::getResourcesToCache ();
753
809
  // If there's nothing to cache, bail out.
754
 
  vector <string> signatures = Database_Config_General::getResourcesToCache ();
755
810
  if (signatures.empty ()) return;
756
811
 
757
 
  // Resource and book to cache.
 
812
  // A signature is the resource title, then a space, and then the book number.
 
813
  // Remove this signature and store the remainder back into the configuration.
758
814
  string signature = signatures [0];
759
815
  signatures.erase (signatures.begin ());
760
816
  Database_Config_General::setResourcesToCache (signatures);
1070
1126
{
1071
1127
  bool skip_next_text = false;
1072
1128
  bool parsing = true;
1073
 
  string text;
1074
 
  vector <string> footnotes;
 
1129
  string text {};
 
1130
  vector <string> footnotes {};
1075
1131
 
1076
1132
  virtual bool for_each (xml_node& node)
1077
1133
  {
1146
1202
        // The location where the mismatch occurs indicates the end of the relevant verses content.
1147
1203
        {
1148
1204
          xml_document document;
1149
 
          xml_parse_result result = document.load_string (html.c_str(), parse_default | parse_fragment);
1150
 
          if (result.offset > 10) {
1151
 
            size_t pos = result.offset - 2;
1152
 
            html.erase (pos);
 
1205
          xml_parse_result parse_result = document.load_string (html.c_str(), parse_default | parse_fragment);
 
1206
          if (parse_result.offset > 10) {
 
1207
            size_t pos2 = static_cast<size_t>(parse_result.offset - 2);
 
1208
            html.erase (pos2);
1153
1209
          }
1154
1210
        }
1155
1211
        // Parse the html fragment into a DOM.
1170
1226
        xml_node passage_text_node = document.first_child ();
1171
1227
        xml_node passage_wrap_node = passage_text_node.first_child ();
1172
1228
        xml_node passage_content_node = passage_wrap_node.first_child ();
1173
 
        bible_gateway_walker walker;
 
1229
        bible_gateway_walker walker {};
1174
1230
        passage_content_node.traverse (walker);
1175
1231
        result.append (walker.text);
1176
1232
        // Adding text of the footnote(s) if any.
1186
1242
          if (xpath) {
1187
1243
            stringstream ss;
1188
1244
            xpath.node().print (ss, "", format_raw);
1189
 
            string html = ss.str ();
1190
 
            string footnote_text = filter_string_html2text (html);
 
1245
            string selected_html = ss.str ();
 
1246
            string footnote_text = filter_string_html2text (selected_html);
1191
1247
            result.append ("<br>Note: ");
1192
1248
            result.append (footnote_text);
1193
1249
          }
1468
1524
 
1469
1525
struct easy_english_bible_walker: xml_tree_walker
1470
1526
{
1471
 
  string text;
 
1527
  string text {};
1472
1528
 
1473
1529
  virtual bool for_each (xml_node& node)
1474
1530
  {
1550
1606
    for (auto paragraph_node : div_node.children()) {
1551
1607
 
1552
1608
      // Assemble the text by iterating over all child text nodes.
1553
 
      easy_english_bible_walker tree_walker;
 
1609
      easy_english_bible_walker tree_walker {};
1554
1610
      paragraph_node.traverse(tree_walker);
1555
1611
 
1556
1612
      // Clean the text and skip empty text.
1721
1777
  int ending_chapter = starting_chapter;
1722
1778
  colon_pos = last_word.find(":");
1723
1779
  if (colon_pos != string::npos) {
1724
 
    string ch_fragment = last_word.substr(0, colon_pos);
1725
 
    ending_chapter = convert_to_int(ch_fragment);
1726
 
    string check = convert_to_string(ending_chapter);
1727
 
    if (ch_fragment != check) return false;
 
1780
    string chapter_fragment = last_word.substr(0, colon_pos);
 
1781
    ending_chapter = convert_to_int(chapter_fragment);
 
1782
    check = convert_to_string(ending_chapter);
 
1783
    if (chapter_fragment != check) return false;
1728
1784
    last_word.erase(0, colon_pos + 1);
1729
1785
  }
1730
1786
 
1909
1965
}
1910
1966
 
1911
1967
 
1912
 
bool resource_logic_is_comparative (string resource)
 
1968
bool resource_logic_is_comparative (const string & resource)
1913
1969
{
1914
1970
  return resource_logic_parse_comparative_resource(resource);
1915
1971
}
1921
1977
}
1922
1978
 
1923
1979
 
1924
 
bool resource_logic_parse_comparative_resource (string input,
 
1980
bool resource_logic_parse_comparative_resource (const string & input,
1925
1981
                                                string * title,
1926
1982
                                                string * base,
1927
1983
                                                string * update,
1977
2033
  vector <string> bits = {resource_logic_comparative_resource() + title, base, update, remove, replace, convert_to_true_false(diacritics), convert_to_true_false(casefold), convert_to_true_false(cache)};
1978
2034
  return filter_string_implode(bits, "|");
1979
2035
}
 
2036
 
 
2037
 
 
2038
bool resource_logic_is_translated (const string & resource)
 
2039
{
 
2040
  return resource_logic_parse_translated_resource(resource);
 
2041
}
 
2042
 
 
2043
 
 
2044
string resource_logic_translated_resource ()
 
2045
{
 
2046
  return "Translated ";
 
2047
}
 
2048
 
 
2049
 
 
2050
bool resource_logic_parse_translated_resource (const string & input,
 
2051
                                               string * title,
 
2052
                                               string * original_resource,
 
2053
                                               string * source_language,
 
2054
                                               string * target_language,
 
2055
                                               bool * cache)
 
2056
{
 
2057
  // The definite check whether this is a translated resource
 
2058
  // is to check that "Translated " is the first part of the input.
 
2059
  if (input.find(resource_logic_translated_resource()) != 0) return false;
 
2060
  
 
2061
  // Do a forgiving parsing of the properties of this resource.
 
2062
  if (title) title->clear();
 
2063
  if (original_resource) original_resource->clear();
 
2064
  if (source_language) source_language->clear();
 
2065
  if (target_language) target_language->clear();
 
2066
  if (cache) * cache = false;
 
2067
  vector <string> bits = filter_string_explode(input, '|');
 
2068
  if (bits.size() > 0) if (title) title->assign (bits[0]);
 
2069
  if (bits.size() > 1) if (original_resource) original_resource->assign(bits[1]);
 
2070
  if (bits.size() > 2) if (source_language) source_language->assign(bits[2]);
 
2071
  if (bits.size() > 3) if (target_language) target_language->assign(bits[3]);
 
2072
  if (bits.size() > 4) if (cache) * cache = convert_to_bool(bits[4]);
 
2073
  
 
2074
  // Done.
 
2075
  return true;
 
2076
}
 
2077
 
 
2078
 
 
2079
string resource_logic_assemble_translated_resource (string title,
 
2080
                                                    string original_resource,
 
2081
                                                    string source_language,
 
2082
                                                    string target_language,
 
2083
                                                    bool cache)
 
2084
{
 
2085
  // Check whether the "Translated " flag already is included in the given $title.
 
2086
  size_t pos = title.find (resource_logic_translated_resource ());
 
2087
  if (pos != string::npos) {
 
2088
    title.erase (pos, resource_logic_translated_resource ().length());
 
2089
  }
 
2090
  // Ensure the "Translated " flag is always included right at the start.
 
2091
  vector <string> bits = {resource_logic_translated_resource() + title, original_resource, source_language, target_language, convert_to_true_false(cache)};
 
2092
  return filter_string_implode(bits, "|");
 
2093
}
 
2094
 
 
2095
 
 
2096
string resource_logic_translated_resources_list_path ()
 
2097
{
 
2098
  return filter_url_create_root_path ({database_logic_databases (), "client", "translated_resources.txt"});
 
2099
}
 
2100
 
 
2101
 
 
2102
// Get the list of Translated resources on a client device.
 
2103
vector <string> resource_logic_translated_resources_get_list_on_client ()
 
2104
{
 
2105
  string path = resource_logic_translated_resources_list_path ();
 
2106
  string contents = filter_url_file_get_contents (path);
 
2107
  return filter_string_explode (contents, '\n');
 
2108
}