forked from openlp/openlp
In this commit:
- Cleanup of the scripture reference error. (Now using full names, removed one un-needed line) - Added more comments - Removed def get_verses_combined, now triggering the error message on mediaitem based on search mode instead.
This commit is contained in:
parent
c0311ed8c9
commit
cb421a8fd7
@ -164,26 +164,22 @@ class UiStrings(object):
|
|||||||
'Please use the Import Wizard to install one or more Bibles.')
|
'Please use the Import Wizard to install one or more Bibles.')
|
||||||
# Scripture reference error combined from small translation stings by using itertools.
|
# Scripture reference error combined from small translation stings by using itertools.
|
||||||
book_chapter = translate('OpenLP.Ui', 'Book Chapter')
|
book_chapter = translate('OpenLP.Ui', 'Book Chapter')
|
||||||
bc = book_chapter
|
|
||||||
chapter = translate('OpenLP.Ui', 'Chapter')
|
chapter = translate('OpenLP.Ui', 'Chapter')
|
||||||
cha = chapter
|
|
||||||
verse = translate('OpenLP.Ui', 'Verse')
|
verse = translate('OpenLP.Ui', 'Verse')
|
||||||
ver = verse
|
|
||||||
gap = ' | '
|
gap = ' | '
|
||||||
psalm = translate('OpenLP.Ui', 'Psalm')
|
psalm = translate('OpenLP.Ui', 'Psalm')
|
||||||
may_shorten = translate('OpenLP.Ui', 'Book names may be shortened from full names, for an example Ps 23 = '
|
may_shorten = translate('OpenLP.Ui', 'Book names may be shortened from full names, for an example Ps 23 = '
|
||||||
'Psalm 23')
|
'Psalm 23')
|
||||||
bible_scripture_items = [bc, gap, psalm, ' 23<br>',
|
bible_scripture_items = \
|
||||||
bc, '%(range)s', cha, gap, psalm, ' 23%(range)s24<br>',
|
[book_chapter, gap, psalm, ' 23<br>',
|
||||||
bc, '%(verse)s', ver, '%(range)s', ver, gap, psalm, ' 23%(verse)s1%(range)s2<br>',
|
book_chapter, '%(range)s', chapter, gap, psalm, ' 23%(range)s24<br>',
|
||||||
bc, '%(verse)s', ver, '%(range)s', ver, '%(list)s', ver, '%(range)s', ver, gap, psalm,
|
book_chapter, '%(verse)s', verse, '%(range)s', verse, gap, psalm, ' 23%(verse)s1%(range)s2<br>',
|
||||||
' 23%(verse)s1%(range)s2%(list)s5%(range)s6<br>',
|
book_chapter, '%(verse)s', verse, '%(range)s', verse, '%(list)s', verse, '%(range)s', verse, gap, psalm,
|
||||||
bc, '%(verse)s', ver, '%(range)s', ver, '%(list)s', cha, '%(verse)s', ver, '%(range)s',
|
' 23%(verse)s1%(range)s2%(list)s5%(range)s6<br>',
|
||||||
ver, gap, psalm, ' 23%(verse)s1%(range)s2%(list)s24%(verse)s1%(range)s3<br>', bc,
|
book_chapter, '%(verse)s', verse, '%(range)s', verse, '%(list)s', chapter, '%(verse)s', verse, '%(range)s',
|
||||||
'%(verse)s', ver, '%(range)s', cha, '%(verse)s', ver, gap, psalm,
|
verse, gap, psalm, ' 23%(verse)s1%(range)s2%(list)s24%(verse)s1%(range)s3<br>',
|
||||||
' 23%(verse)s1%(range)s24%(verse)s1<br><br>', may_shorten]
|
book_chapter, '%(verse)s', verse, '%(range)s', chapter, '%(verse)s', verse, gap, psalm,
|
||||||
itertools.chain.from_iterable(itertools.repeat(strings, 1) if isinstance(strings, str) else strings for strings
|
' 23%(verse)s1%(range)s24%(verse)s1<br><br>', may_shorten]
|
||||||
in bible_scripture_items)
|
itertools.chain.from_iterable(itertools.repeat(strings, 1) if isinstance(strings, str)
|
||||||
bible_scripture_error_joined = ''.join(str(joined) for joined in bible_scripture_items)
|
else strings for strings in bible_scripture_items)
|
||||||
# This is what gets called to other files.
|
self.BibleScriptureError = ''.join(str(joined) for joined in bible_scripture_items)
|
||||||
self.BibleScriptureError = bible_scripture_error_joined
|
|
||||||
|
@ -240,6 +240,7 @@ class BibleManager(RegistryProperties):
|
|||||||
"""
|
"""
|
||||||
Parses a scripture reference, fetches the verses from the Bible
|
Parses a scripture reference, fetches the verses from the Bible
|
||||||
specified, and returns a list of ``Verse`` objects.
|
specified, and returns a list of ``Verse`` objects.
|
||||||
|
This function is called in \bibles\lib\mediaitem.py by def on_quick_search_button
|
||||||
|
|
||||||
:param bible: Unicode. The Bible to use.
|
:param bible: Unicode. The Bible to use.
|
||||||
:param verse_text:
|
:param verse_text:
|
||||||
@ -258,28 +259,20 @@ class BibleManager(RegistryProperties):
|
|||||||
:param show_error:
|
:param show_error:
|
||||||
"""
|
"""
|
||||||
log.debug('BibleManager.get_verses("%s", "%s")', bible, verse_text)
|
log.debug('BibleManager.get_verses("%s", "%s")', bible, verse_text)
|
||||||
|
# If no bibles are installed, message is given.
|
||||||
if not bible:
|
if not bible:
|
||||||
if show_error:
|
if show_error:
|
||||||
self.main_window.information_message(
|
self.main_window.information_message(
|
||||||
('%s' % UiStrings().BibleNoBiblesTitle),
|
('%s' % UiStrings().BibleNoBiblesTitle),
|
||||||
('%s' % UiStrings().BibleNoBibles))
|
('%s' % UiStrings().BibleNoBibles))
|
||||||
return None
|
return None
|
||||||
|
# Get the language for books.
|
||||||
language_selection = self.get_language_selection(bible)
|
language_selection = self.get_language_selection(bible)
|
||||||
ref_list = parse_reference(verse_text, self.db_cache[bible], language_selection, book_ref_id)
|
ref_list = parse_reference(verse_text, self.db_cache[bible], language_selection, book_ref_id)
|
||||||
if ref_list:
|
if ref_list:
|
||||||
return self.db_cache[bible].get_verses(ref_list, show_error)
|
return self.db_cache[bible].get_verses(ref_list, show_error)
|
||||||
|
# If nothing is found. Message is given if this is not combined search. (defined in mediaitem.py)
|
||||||
else:
|
else:
|
||||||
if show_error:
|
|
||||||
reference_separators = {
|
|
||||||
'verse': get_reference_separator('sep_v_display'),
|
|
||||||
'range': get_reference_separator('sep_r_display'),
|
|
||||||
'list': get_reference_separator('sep_l_display')}
|
|
||||||
self.main_window.information_message(
|
|
||||||
translate('BiblesPlugin.BibleManager', 'Scripture Reference Error'),
|
|
||||||
translate('BiblesPlugin.BibleManager', '<strong>OpenLP couldn’t find anything '
|
|
||||||
'with your search.<br><br>'
|
|
||||||
'Please make sure that your reference follows one of these patterns:</strong><br><br>%s'
|
|
||||||
% UiStrings().BibleScriptureError % reference_separators))
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_language_selection(self, bible):
|
def get_language_selection(self, bible):
|
||||||
@ -305,12 +298,14 @@ class BibleManager(RegistryProperties):
|
|||||||
def verse_search(self, bible, second_bible, text):
|
def verse_search(self, bible, second_bible, text):
|
||||||
"""
|
"""
|
||||||
Does a verse search for the given bible and text.
|
Does a verse search for the given bible and text.
|
||||||
|
This function is called in \bibles\lib\mediaitem.py by def on_quick_search_button.
|
||||||
|
|
||||||
:param bible: The bible to search in (unicode).
|
:param bible: The bible to search in (unicode).
|
||||||
:param second_bible: The second bible (unicode). We do not search in this bible.
|
:param second_bible: The second bible (unicode). We do not search in this bible.
|
||||||
:param text: The text to search for (unicode).
|
:param text: The text to search for (unicode).
|
||||||
"""
|
"""
|
||||||
log.debug('BibleManager.verse_search("%s", "%s")', bible, text)
|
log.debug('BibleManager.verse_search("%s", "%s")', bible, text)
|
||||||
|
# If no bibles are installed, message is given.
|
||||||
if not bible:
|
if not bible:
|
||||||
self.main_window.information_message(
|
self.main_window.information_message(
|
||||||
('%s' % UiStrings().BibleNoBiblesTitle),
|
('%s' % UiStrings().BibleNoBiblesTitle),
|
||||||
@ -322,6 +317,7 @@ class BibleManager(RegistryProperties):
|
|||||||
if second_bible:
|
if second_bible:
|
||||||
second_web_bible = self.db_cache[second_bible].get_object(BibleMeta, 'download_source')
|
second_web_bible = self.db_cache[second_bible].get_object(BibleMeta, 'download_source')
|
||||||
if web_bible or second_web_bible:
|
if web_bible or second_web_bible:
|
||||||
|
# If either Bible is Web, cursor is reset to normal and message is given.
|
||||||
self.application.set_normal_cursor()
|
self.application.set_normal_cursor()
|
||||||
self.main_window.information_message(
|
self.main_window.information_message(
|
||||||
translate('BiblesPlugin.BibleManager', 'Web Bible cannot be used'),
|
translate('BiblesPlugin.BibleManager', 'Web Bible cannot be used'),
|
||||||
@ -329,33 +325,18 @@ class BibleManager(RegistryProperties):
|
|||||||
'Please use the Scripture Reference Search instead.')
|
'Please use the Scripture Reference Search instead.')
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
# Shorter than 3 char searches break OpenLP with very long search times, thus they are blocked.
|
||||||
if len(text) - text.count(' ') < 3:
|
if len(text) - text.count(' ') < 3:
|
||||||
self.main_window.information_message(
|
self.main_window.information_message(
|
||||||
('%s' % UiStrings().BibleShortSearchTitle),
|
('%s' % UiStrings().BibleShortSearchTitle),
|
||||||
('%s' % UiStrings().BibleShortSearch))
|
('%s' % UiStrings().BibleShortSearch))
|
||||||
return None
|
return None
|
||||||
|
# Fetch the results from db. If no results are found, return None, no message is given for this.
|
||||||
elif text:
|
elif text:
|
||||||
return self.db_cache[bible].verse_search(text)
|
return self.db_cache[bible].verse_search(text)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_verses_combined(self, bible, verse_text, book_ref_id=False, show_error=True):
|
|
||||||
log.debug('BibleManager.get_verses("%s", "%s")', bible, verse_text)
|
|
||||||
if not bible:
|
|
||||||
if show_error:
|
|
||||||
if not bible:
|
|
||||||
self.main_window.information_message(
|
|
||||||
('%s' % UiStrings().BibleNoBiblesTitle),
|
|
||||||
('%s' % UiStrings().BibleNoBibles))
|
|
||||||
return None
|
|
||||||
return None
|
|
||||||
language_selection = self.get_language_selection(bible)
|
|
||||||
ref_list = parse_reference(verse_text, self.db_cache[bible], language_selection, book_ref_id)
|
|
||||||
if ref_list:
|
|
||||||
return self.db_cache[bible].get_verses(ref_list, show_error)
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def save_meta_data(self, bible, version, copyright, permissions, book_name_language=None):
|
def save_meta_data(self, bible, version, copyright, permissions, book_name_language=None):
|
||||||
"""
|
"""
|
||||||
Saves the bibles meta data.
|
Saves the bibles meta data.
|
||||||
|
@ -654,35 +654,57 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
|
|
||||||
def on_quick_reference_search(self):
|
def on_quick_reference_search(self):
|
||||||
# We are doing a 'Reference Search'.
|
# We are doing a 'Reference Search'.
|
||||||
|
# Set Bibles to use the text input from Quick search field.
|
||||||
bible = self.quickVersionComboBox.currentText()
|
bible = self.quickVersionComboBox.currentText()
|
||||||
second_bible = self.quickSecondComboBox.currentText()
|
second_bible = self.quickSecondComboBox.currentText()
|
||||||
# Get input from field and replace '. ' with ''
|
# Get input from field and replace '. ' with ''
|
||||||
# This will check if field has any '.' and removes them. Eg. Gen. 1 = Gen 1 = Genesis 1
|
# This will check if field has any '.' and removes them. Eg. Gen. 1 = Gen 1 = Genesis 1
|
||||||
text_direct = self.quick_search_edit.text()
|
text = self.quick_search_edit.text()
|
||||||
text = text_direct.replace('. ', ' ')
|
text = text.replace('. ', ' ')
|
||||||
# If we are doing "Reference" search, use the search from manager.py
|
# This is triggered on reference search, use the search from manager.py
|
||||||
if self.quick_search_edit.current_search_type() == BibleSearch.Reference:
|
if self.quick_search_edit.current_search_type() == BibleSearch.Reference:
|
||||||
self.search_results = self.plugin.manager.get_verses(bible, text)
|
self.search_results = self.plugin.manager.get_verses(bible, text)
|
||||||
# If we are doing "Combined Reference" search, use the get_verses_combined from manager.py (No error included)
|
if not self.search_results:
|
||||||
else:
|
# if nothing is found, message is given.
|
||||||
self.search_results = self.plugin.manager.get_verses_combined(bible, text)
|
# Get reference separators from settings.
|
||||||
|
reference_separators = {
|
||||||
|
'verse': get_reference_separator('sep_v_display'),
|
||||||
|
'range': get_reference_separator('sep_r_display'),
|
||||||
|
'list': get_reference_separator('sep_l_display')}
|
||||||
|
self.main_window.information_message(
|
||||||
|
translate('BiblesPlugin.BibleManager', 'Scripture Reference Error'),
|
||||||
|
translate('BiblesPlugin.BibleManager', '<strong>OpenLP couldn’t find anything '
|
||||||
|
'with your search.<br><br>'
|
||||||
|
'Please make sure that your reference follows one of these patterns:</strong><br><br>%s'
|
||||||
|
% UiStrings().BibleScriptureError % reference_separators))
|
||||||
|
elif self.quick_search_edit.current_search_type() == BibleSearch.Combined:
|
||||||
|
# In Combined Reference search no error is given if no results are found. (This would result in duplicate)
|
||||||
|
self.search_results = self.plugin.manager.get_verses(bible, text)
|
||||||
if second_bible and self.search_results:
|
if second_bible and self.search_results:
|
||||||
self.second_search_results = \
|
self.second_search_results = \
|
||||||
self.plugin.manager.get_verses(second_bible, text, self.search_results[0].book.book_reference_id)
|
self.plugin.manager.get_verses(second_bible, text, self.search_results[0].book.book_reference_id)
|
||||||
|
|
||||||
def on_quick_text_search(self):
|
def on_quick_text_search(self):
|
||||||
# We are doing a 'Text Search'.
|
# We are doing a 'Text Search'.
|
||||||
|
# Set Bibles to use the text input from Quick search field.
|
||||||
bible = self.quickVersionComboBox.currentText()
|
bible = self.quickVersionComboBox.currentText()
|
||||||
second_bible = self.quickSecondComboBox.currentText()
|
second_bible = self.quickSecondComboBox.currentText()
|
||||||
text = self.quick_search_edit.text()
|
text = self.quick_search_edit.text()
|
||||||
|
# This changes the curson to "Loading animation"
|
||||||
self.application.set_busy_cursor()
|
self.application.set_busy_cursor()
|
||||||
|
# Get Bibles list
|
||||||
bibles = self.plugin.manager.get_bibles()
|
bibles = self.plugin.manager.get_bibles()
|
||||||
|
# Add results to "search_results"
|
||||||
self.search_results = self.plugin.manager.verse_search(bible, second_bible, text)
|
self.search_results = self.plugin.manager.verse_search(bible, second_bible, text)
|
||||||
if second_bible and self.search_results:
|
if second_bible and self.search_results:
|
||||||
|
# Set up variables,
|
||||||
|
# new_search_results is needed to make sure 2nd bible contains all verses. (And counting them on error)
|
||||||
text = []
|
text = []
|
||||||
new_search_results = []
|
new_search_results = []
|
||||||
count = 0
|
count = 0
|
||||||
passage_not_found = False
|
passage_not_found = False
|
||||||
|
# Search second bible for results of search_results to make sure everythigns there.
|
||||||
|
# Count all the unfound passages.
|
||||||
for verse in self.search_results:
|
for verse in self.search_results:
|
||||||
db_book = bibles[second_bible].get_book_by_book_ref_id(verse.book.book_reference_id)
|
db_book = bibles[second_bible].get_book_by_book_ref_id(verse.book.book_reference_id)
|
||||||
if not db_book:
|
if not db_book:
|
||||||
@ -694,23 +716,27 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
new_search_results.append(verse)
|
new_search_results.append(verse)
|
||||||
text.append((verse.book.book_reference_id, verse.chapter, verse.verse, verse.verse))
|
text.append((verse.book.book_reference_id, verse.chapter, verse.verse, verse.verse))
|
||||||
if passage_not_found:
|
if passage_not_found:
|
||||||
|
# This is for the 2nd Bible.
|
||||||
self.main_window.information_message(
|
self.main_window.information_message(
|
||||||
translate('BiblesPlugin.MediaItem', 'Information'),
|
translate('BiblesPlugin.MediaItem', 'Information'),
|
||||||
translate('BiblesPlugin.MediaItem', 'The second Bible does not contain all the verses '
|
translate('BiblesPlugin.MediaItem', 'The second Bible does not contain all the verses '
|
||||||
'that are in the main Bible. Only verses found in both Bibles '
|
'that are in the main Bible. Only verses found in both Bibles '
|
||||||
'will be shown. %d verses have not been included '
|
'will be shown. %d verses have not been included '
|
||||||
'in the results.') % count)
|
'in the results.') % count)
|
||||||
|
# Join the searches so only verses that are found on both Bibles are shown.
|
||||||
self.search_results = new_search_results
|
self.search_results = new_search_results
|
||||||
self.second_search_results = bibles[second_bible].get_verses(text)
|
self.second_search_results = bibles[second_bible].get_verses(text)
|
||||||
|
|
||||||
def on_quick_search_button(self):
|
def on_quick_search_button(self):
|
||||||
"""
|
"""
|
||||||
Does a quick search and saves the search results. Quick search can be:
|
This triggers the proper Quick search based on which search type is used.
|
||||||
"Reference Search" or "Text Search" or Combined search.
|
"Eg. "Reference Search", "Text Search" or "Combined search".
|
||||||
"""
|
"""
|
||||||
log.debug('Quick Search Button clicked')
|
log.debug('Quick Search Button clicked')
|
||||||
|
# Disable the button while processing, get text from Quick search field.
|
||||||
self.quickSearchButton.setEnabled(False)
|
self.quickSearchButton.setEnabled(False)
|
||||||
self.application.process_events()
|
self.application.process_events()
|
||||||
|
# These need to be defined here too so the search results can be displayed.
|
||||||
bible = self.quickVersionComboBox.currentText()
|
bible = self.quickVersionComboBox.currentText()
|
||||||
second_bible = self.quickSecondComboBox.currentText()
|
second_bible = self.quickSecondComboBox.currentText()
|
||||||
text = self.quick_search_edit.text()
|
text = self.quick_search_edit.text()
|
||||||
@ -720,20 +746,21 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
elif self.quick_search_edit.current_search_type() == BibleSearch.Text:
|
elif self.quick_search_edit.current_search_type() == BibleSearch.Text:
|
||||||
# We are doing a 'Text Search'. (Get script from def on_quick_text_search)
|
# We are doing a 'Text Search'. (Get script from def on_quick_text_search)
|
||||||
self.on_quick_text_search()
|
self.on_quick_text_search()
|
||||||
# Combined search, starting with reference search.
|
|
||||||
elif self.quick_search_edit.current_search_type() == BibleSearch.Combined:
|
elif self.quick_search_edit.current_search_type() == BibleSearch.Combined:
|
||||||
|
# We are doing a 'Combined search'. Starting with reference search.
|
||||||
self.on_quick_reference_search()
|
self.on_quick_reference_search()
|
||||||
# If keyword is shorter than 3 (not including spaces), message is given and search is finalized.
|
# If results are found, search will be finalized.
|
||||||
# It's actually to find verses with less than 3 chars (Eg. G1 = Genesis 1) thus this error is not shown if
|
# This check needs to be here in order to avoid duplicate errors.
|
||||||
# any results are found. This check needs to be here in order to avoid duplicate errors.
|
# If keyword is shorter than 3 (not including spaces), message is given. It's actually possible to find
|
||||||
# if no Bibles are installed, this message is not shown - "No bibles" message is whon instead. (and bible)
|
# verses with less than 3 chars (Eg. G1 = Genesis 1) thus this error is not shown if any results are found.
|
||||||
|
# if no Bibles are installed, this message is not shown - "No bibles" message is shown instead. (and bible)
|
||||||
if not self.search_results and len(text) - text.count(' ') < 3 and bible:
|
if not self.search_results and len(text) - text.count(' ') < 3 and bible:
|
||||||
self.main_window.information_message(
|
self.main_window.information_message(
|
||||||
('%s' % UiStrings().BibleShortSearchTitle),
|
('%s' % UiStrings().BibleShortSearchTitle),
|
||||||
('%s' % UiStrings().BibleShortSearch))
|
('%s' % UiStrings().BibleShortSearch))
|
||||||
# Text search starts here if no reference was found and keyword is longer than 2.
|
|
||||||
# This is required in order to avoid duplicate error messages for short keywords.
|
|
||||||
if not self.search_results and len(text) - text.count(' ') > 2 and bible:
|
if not self.search_results and len(text) - text.count(' ') > 2 and bible:
|
||||||
|
# Text search starts here if no reference was found and keyword is longer than 2.
|
||||||
|
# > 2 check is required in order to avoid duplicate error messages for short keywords.
|
||||||
self.on_quick_text_search()
|
self.on_quick_text_search()
|
||||||
# If no Text or Reference is found, message is given.
|
# If no Text or Reference is found, message is given.
|
||||||
if not self.search_results and not \
|
if not self.search_results and not \
|
||||||
@ -744,23 +771,16 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
'range': get_reference_separator('sep_r_display'),
|
'range': get_reference_separator('sep_r_display'),
|
||||||
'list': get_reference_separator('sep_l_display')}
|
'list': get_reference_separator('sep_l_display')}
|
||||||
self.main_window.information_message(translate('BiblesPlugin.BibleManager', 'Nothing found'),
|
self.main_window.information_message(translate('BiblesPlugin.BibleManager', 'Nothing found'),
|
||||||
translate('BiblesPlugin.BibleManager', '<strong>OpenLP '
|
translate('BiblesPlugin.BibleManager',
|
||||||
'couldn’t find '
|
'<strong>OpenLP couldn’t find anything with your'
|
||||||
'anything with your'
|
' search.</strong><br><br>If you tried to search'
|
||||||
' search.</strong>'
|
' with Scripture Reference, please make<br> sure'
|
||||||
'<br><br>'
|
' that your reference follows one of these'
|
||||||
'If you tried to '
|
' patterns: <br><br>%s'
|
||||||
'search with '
|
|
||||||
'Scripture '
|
|
||||||
'Reference, please '
|
|
||||||
'make<br>sure that '
|
|
||||||
'your reference '
|
|
||||||
'follows one of '
|
|
||||||
'these patterns:'
|
|
||||||
'<br><br>%s'
|
|
||||||
% UiStrings().BibleScriptureError %
|
% UiStrings().BibleScriptureError %
|
||||||
reference_separators))
|
reference_separators))
|
||||||
# Finalizing the search
|
# Finalizing the search
|
||||||
|
# List is cleared if not locked, results are listed, button is set available, cursor is set to normal.
|
||||||
if not self.quickLockButton.isChecked():
|
if not self.quickLockButton.isChecked():
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
if self.list_view.count() != 0 and self.search_results:
|
if self.list_view.count() != 0 and self.search_results:
|
||||||
|
Loading…
Reference in New Issue
Block a user