forked from openlp/openlp
Fixed up the Bible plugin's media manager item.
Removed the unnecessarily hardcoded path in the Bible Manager. Changed the SongFormat file to reflect what's really gonna happen in the song database. Added the first sentence of the Plugin Developer's Guide. bzr-revno: 186
This commit is contained in:
parent
bccd03b4df
commit
843774aa1d
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE UserProject SYSTEM "UserProject-4.0.dtd">
|
||||
<!-- eric4 user project file for project openlp.org 2.0 -->
|
||||
<!-- Saved: 2008-12-03, 23:36:03 -->
|
||||
<!-- Saved: 2008-12-05, 23:55:48 -->
|
||||
<!-- Copyright (C) 2008 Raoul Snyman, raoulsnyman@openlp.org -->
|
||||
<UserProject version="4.0">
|
||||
</UserProject>
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Tasks SYSTEM "Tasks-4.2.dtd">
|
||||
<!-- eric4 tasks file for project openlp.org 2.0 -->
|
||||
<!-- Saved: 2008-12-03, 15:55:19 -->
|
||||
<!-- Saved: 2008-12-05, 23:55:48 -->
|
||||
<Tasks version="4.2">
|
||||
<Task priority="1" completed="False" bugfix="False">
|
||||
<Summary>TODO: what is the tags for bridge, pre-chorus?</Summary>
|
||||
|
8
documentation/PluginDevelopersGuide.txt
Normal file
8
documentation/PluginDevelopersGuide.txt
Normal file
@ -0,0 +1,8 @@
|
||||
openlp.org 2.x Plugin Developer's Guide
|
||||
========================================================================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
This document will show you how to write your own module for openlp.org.
|
||||
openlp.org has been written in plugins so that you can add your own
|
||||
functionality to openlp.org.
|
@ -1,60 +1,124 @@
|
||||
This file documents the OpenLP2 song format.
|
||||
|
||||
All fields are strings to ease reading and writing of SQLITE files.
|
||||
|
||||
A Song has the following fields
|
||||
title
|
||||
searchableTitle - no hyphens, commas, punctuation etc
|
||||
authorList - like "A. Williams, B C Dee"
|
||||
songCcliNo
|
||||
copyright - like authorList
|
||||
showTitle - 0: dont show, 1: do show
|
||||
showAuthorList - 0: dont show, 1: do show
|
||||
showSongCcli - 0: dont show, 1: do show
|
||||
showCopyright - 0: dont show, 1: do show
|
||||
theme - name of theme or blank
|
||||
categoryArray - list of categories "Hymn, Traditional ..."
|
||||
songBook -
|
||||
songNumber -
|
||||
comments - any comment you may have
|
||||
verseOrder - like "V1 C V2 C V3 B V4 C"
|
||||
lyrics - formatted as XML - see below
|
||||
searchableLyrics -- the lyrics without any xml formatting; the raw song text
|
||||
|
||||
|
||||
|
||||
The lyrics definition (more or less similar to interformat to/from ChangingSong
|
||||
The tags <i></i><b></b><u></u> can also be used within the lyrics test.
|
||||
|
||||
! Please note that this format has been checked at http://validator.w3.org/#validate_by_upload
|
||||
|
||||
<lyrics lang="en_US">
|
||||
<title>Amazing Grace</title>
|
||||
<verse name="v1">
|
||||
<theme>name of verse specific theme (optional)</theme>
|
||||
<comment>any text (optional)</comment>
|
||||
<part name="men">
|
||||
Amazing grace, how ...
|
||||
</part>
|
||||
<part name="women">
|
||||
A b c
|
||||
D e f
|
||||
</part>
|
||||
...
|
||||
</verse>
|
||||
<verse name="c">
|
||||
<theme>name of verse specific theme (optional)</theme>
|
||||
<comment>any text (optional)</comment>
|
||||
...
|
||||
</verse>
|
||||
</lyrics>
|
||||
<lyrics lang="de_DE">
|
||||
<title>Erstaunliche Anmut</title>
|
||||
<verse name="v1">
|
||||
Erstaunliche Anmut, wie
|
||||
...
|
||||
</verse>
|
||||
<verse name="c">
|
||||
...
|
||||
</verse>
|
||||
</lyrics>
|
||||
openlp.org 2.x Song Database Structure
|
||||
========================================================================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
The song database in openlp.org 2.x is similar to the 1.x format. The
|
||||
biggest differences are the addition of extra tables, and the use of
|
||||
SQLite version 3.
|
||||
|
||||
The song database contains the following tables:
|
||||
- authors
|
||||
- authors_songs
|
||||
- song_books
|
||||
- songs
|
||||
- songs_topics
|
||||
- topics
|
||||
|
||||
|
||||
"authors" Table
|
||||
---------------
|
||||
This table holds the names of all the authors. It has the following
|
||||
columns:
|
||||
|
||||
* id
|
||||
* first_name
|
||||
* last_name
|
||||
* display_name
|
||||
|
||||
|
||||
"authors_songs" Table
|
||||
---------------------
|
||||
This is a bridging table between the "authors" and "songs" tables, which
|
||||
serves to create a many-to-many relationship between the two tables. It
|
||||
has the following columns:
|
||||
|
||||
* author_id
|
||||
* song_id
|
||||
|
||||
|
||||
"song_books" Table
|
||||
------------------
|
||||
The "song_books" table holds a list of books that a congregation gets
|
||||
their songs from, or old hymnals now no longer used. This table has the
|
||||
following columns:
|
||||
|
||||
* id
|
||||
* name
|
||||
* publisher
|
||||
|
||||
|
||||
"songs" Table
|
||||
-------------
|
||||
This table contains the songs, and each song has a list of attributes.
|
||||
The "songs" table has the following columns:
|
||||
|
||||
* id
|
||||
* song_book_id
|
||||
* title
|
||||
* lyrics
|
||||
* verse_order
|
||||
* copyright
|
||||
* comments
|
||||
* ccli_number
|
||||
* song_number
|
||||
* theme
|
||||
* search_title
|
||||
* search_lyrics
|
||||
|
||||
|
||||
"songs_topics" Table
|
||||
--------------------
|
||||
This is a bridging table between the "songs" and "topics" tables, which
|
||||
serves to create a many-to-many relationship between the two tables. It
|
||||
has the following columns:
|
||||
|
||||
* song_id
|
||||
* topic_id
|
||||
|
||||
|
||||
"topics" Table
|
||||
--------------
|
||||
The topics table holds a selection of topics that songs can cover. This
|
||||
is useful when a worship leader wants to select songs with a certain
|
||||
theme. This table has the following columns:
|
||||
|
||||
* id
|
||||
* name
|
||||
|
||||
|
||||
The lyrics definition (more or less similar to interformat to/from ChangingSong
|
||||
The tags <i></i><b></b><u></u> can also be used within the lyrics test.
|
||||
|
||||
! Please note that this format has been checked at http://validator.w3.org/#validate_by_upload
|
||||
|
||||
<lyrics lang="en_US">
|
||||
<title>Amazing Grace</title>
|
||||
<verse name="v1">
|
||||
<theme>name of verse specific theme (optional)</theme>
|
||||
<comment>any text (optional)</comment>
|
||||
<part name="men">
|
||||
Amazing grace, how ...
|
||||
</part>
|
||||
<part name="women">
|
||||
A b c
|
||||
D e f
|
||||
</part>
|
||||
...
|
||||
</verse>
|
||||
<verse name="c">
|
||||
<theme>name of verse specific theme (optional)</theme>
|
||||
<comment>any text (optional)</comment>
|
||||
...
|
||||
</verse>
|
||||
</lyrics>
|
||||
<lyrics lang="de_DE">
|
||||
<title>Erstaunliche Anmut</title>
|
||||
<verse name="v1">
|
||||
Erstaunliche Anmut, wie
|
||||
...
|
||||
</verse>
|
||||
<verse name="c">
|
||||
...
|
||||
</verse>
|
||||
</lyrics>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Project SYSTEM "Project-4.4.dtd">
|
||||
<!-- eric4 project file for project openlp.org 2.0 -->
|
||||
<!-- Saved: 2008-12-03, 15:55:06 -->
|
||||
<!-- Saved: 2008-12-05, 23:55:48 -->
|
||||
<!-- Copyright (C) 2008 Raoul Snyman, raoulsnyman@openlp.org -->
|
||||
<Project version="4.4">
|
||||
<ProgLanguage mixed="0">Python</ProgLanguage>
|
||||
@ -25,15 +25,10 @@
|
||||
<Source>openlp/plugins/biblemanager/test/__init__.py</Source>
|
||||
<Source>openlp/plugins/biblemanager/test/test_bibleManager.py</Source>
|
||||
<Source>openlp/plugins/__init__.py</Source>
|
||||
<Source>openlp/plugins/testplugin1.py</Source>
|
||||
<Source>openlp/plugins/testplugin2/__init__.py</Source>
|
||||
<Source>openlp/plugins/testplugin2/testplugin2.py</Source>
|
||||
<Source>openlp/plugins/test/test_plugin_manager.py</Source>
|
||||
<Source>openlp/libraries/pptviewlib/ppttest.py</Source>
|
||||
<Source>openlp/plugins/biblemanager/test/test_bibleManagerAPI.py</Source>
|
||||
<Source>openlp/plugins/biblemanager/test/test_bibleManagerCSV.py</Source>
|
||||
<Source>openlp/plugins/mediamanageritem.py</Source>
|
||||
<Source>openlp/plugins/test/test_mediamanageritem.py</Source>
|
||||
<Source>openlp/plugins/biblemanager/test/test_bibleManagerOSIS.py</Source>
|
||||
<Source>openlp/core/pluginmanager.py</Source>
|
||||
<Source>openlp/core/ui/__init__.py</Source>
|
||||
@ -84,6 +79,11 @@
|
||||
<Source>openlp/core/utils/linregistry.py</Source>
|
||||
<Source>setup.py</Source>
|
||||
<Source>openlp/core/lib/pluginconfig.py</Source>
|
||||
<Source>openlp/core/test/test_plugin_manager.py</Source>
|
||||
<Source>openlp/core/test/test_mediamanageritem.py</Source>
|
||||
<Source>openlp/core/test/testplugins/testplugin1.py</Source>
|
||||
<Source>openlp/core/test/testplugins/testplugin2/__init__.py</Source>
|
||||
<Source>openlp/core/test/testplugins/testplugin2/testplugin2.py</Source>
|
||||
</Sources>
|
||||
<Forms>
|
||||
<Form>resources/forms/bibleimport.ui</Form>
|
||||
@ -110,6 +110,9 @@
|
||||
</Interfaces>
|
||||
<Others>
|
||||
<Other>copyright.txt</Other>
|
||||
<Other>documentation/SongFormat.txt</Other>
|
||||
<Other>documentation/pyqt-sql-py2exe.txt</Other>
|
||||
<Other>documentation/PluginDevelopersGuide.txt</Other>
|
||||
</Others>
|
||||
<MainScript>openlp.pyw</MainScript>
|
||||
<Vcs>
|
||||
|
@ -50,7 +50,7 @@ class BibleManager():
|
||||
log.debug( "Bible Initialising")
|
||||
self.bibleDBCache = {} # dict of bible database classes
|
||||
self.bibleHTTPCache = {} # dict of bible http readers
|
||||
self.biblePath = path +"/Data/Bibles" #ConfigHelper.getBiblePath()
|
||||
self.biblePath = path #+"/Data/Bibles" #ConfigHelper.getBiblePath()
|
||||
print self.biblePath
|
||||
self.dialogobject = None
|
||||
#log.debug( self.biblePath )
|
||||
|
@ -31,8 +31,7 @@ class BiblePlugin(Plugin):
|
||||
Plugin.__init__(self, 'Bible', '1.9.0')
|
||||
self.Weight = -9
|
||||
#Register the bible Manager
|
||||
print self.config.get_data_path()
|
||||
# self.biblemanager = BibleManager(self.config.get_data_path())
|
||||
self.biblemanager = BibleManager(self.config.get_data_path())
|
||||
self.textsearch = True
|
||||
|
||||
def getMediaManagerItem(self):
|
||||
@ -60,16 +59,110 @@ class BiblePlugin(Plugin):
|
||||
self.MediaManagerItem.addToolbarButton('Add Bible Verse(s) To Service',
|
||||
'Add the selected Bible(s) to the service', ':/system/system_add.png',
|
||||
self.onBibleAddClick, 'BibleAddItem')
|
||||
## Separator Line ##
|
||||
self.MediaManagerItem.addToolbarSeparator()
|
||||
## Separator Line ##
|
||||
#self.MediaManagerItem.addToolbarSeparator()
|
||||
## Add Bible Button ##
|
||||
self.MediaManagerItem.addToolbarButton('Change Search Style',
|
||||
'Swap between the Bible search styles', ':/system/system_add.png',
|
||||
self.onBibleSearchChangeClick, 'BibleSearchChange')
|
||||
#self.MediaManagerItem.addToolbarButton('Change Search Style',
|
||||
# 'Swap between the Bible search styles', ':/system/system_add.png',
|
||||
# self.onBibleSearchChangeClick, 'BibleSearchChange')
|
||||
# Add the Biblelist Tables
|
||||
self.groupBox = QtGui.QGroupBox(self.MediaManagerItem)
|
||||
self.groupBox.setGeometry(QtCore.QRect(5, 5, 271, 391))
|
||||
|
||||
# Create the tab widget
|
||||
self.SearchTabWidget = QtGui.QTabWidget(self.MediaManagerItem)
|
||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.SearchTabWidget.sizePolicy().hasHeightForWidth())
|
||||
self.SearchTabWidget.setSizePolicy(sizePolicy)
|
||||
self.SearchTabWidget.setObjectName('SearchTabWidget')
|
||||
# Add the Quick Search tab
|
||||
self.QuickTab = QtGui.QWidget()
|
||||
self.QuickTab.setObjectName('QuickTab')
|
||||
self.QuickLayout = QtGui.QGridLayout(self.QuickTab)
|
||||
self.QuickLayout.setObjectName('QuickLayout')
|
||||
self.QuickVersionComboBox = QtGui.QComboBox(self.QuickTab)
|
||||
self.QuickVersionComboBox.setObjectName('VersionComboBox')
|
||||
self.QuickLayout.addWidget(self.QuickVersionComboBox, 0, 1, 1, 2)
|
||||
self.QuickVersionLabel = QtGui.QLabel(self.QuickTab)
|
||||
self.QuickVersionLabel.setObjectName('QuickVersionLabel')
|
||||
self.QuickVersionLabel.setText('Version:')
|
||||
self.QuickLayout.addWidget(self.QuickVersionLabel, 0, 0, 1, 1)
|
||||
self.QuickSearchLabel = QtGui.QLabel(self.QuickTab)
|
||||
self.QuickSearchLabel.setObjectName('QuickSearchLabel')
|
||||
self.QuickSearchLabel.setText('Find:')
|
||||
self.QuickLayout.addWidget(self.QuickSearchLabel, 2, 0, 1, 1)
|
||||
self.QuickSearchEdit = QtGui.QLineEdit(self.QuickTab)
|
||||
self.QuickSearchEdit.setObjectName('QuickSearchEdit')
|
||||
self.QuickLayout.addWidget(self.QuickSearchEdit, 2, 1, 1, 2)
|
||||
self.QuickSearchButton = QtGui.QPushButton(self.QuickTab)
|
||||
self.QuickSearchButton.setObjectName('QuickSearchButton')
|
||||
self.QuickSearchButton.setText('Search')
|
||||
self.QuickLayout.addWidget(self.QuickSearchButton, 3, 2, 1, 1)
|
||||
QuickSpacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
||||
self.QuickLayout.addItem(QuickSpacerItem, 4, 2, 1, 1)
|
||||
self.SearchTabWidget.addTab(self.QuickTab, 'Quick Search')
|
||||
# Add the Advanced Search tab
|
||||
self.AdvancedTab = QtGui.QWidget()
|
||||
self.AdvancedTab.setObjectName('AdvancedTab')
|
||||
self.AdvancedLayout = QtGui.QGridLayout(self.AdvancedTab)
|
||||
self.AdvancedLayout.setObjectName('AdvancedLayout')
|
||||
self.AdvancedVersionLabel = QtGui.QLabel(self.AdvancedTab)
|
||||
self.AdvancedVersionLabel.setObjectName('AdvancedVersionLabel')
|
||||
self.AdvancedVersionLabel.setText('Version:')
|
||||
self.AdvancedLayout.addWidget(self.AdvancedVersionLabel, 0, 0, 1, 1)
|
||||
self.AdvancedVersionComboBox = QtGui.QComboBox(self.AdvancedTab)
|
||||
self.AdvancedVersionComboBox.setObjectName('AdvancedVersionComboBox')
|
||||
self.AdvancedLayout.addWidget(self.AdvancedVersionComboBox, 0, 2, 1, 2)
|
||||
self.AdvancedBookLabel = QtGui.QLabel(self.AdvancedTab)
|
||||
self.AdvancedBookLabel.setObjectName('AdvancedBookLabel')
|
||||
self.AdvancedBookLabel.setText('Book:')
|
||||
self.AdvancedLayout.addWidget(self.AdvancedBookLabel, 1, 0, 1, 1)
|
||||
self.AdvancedBookComboBox = QtGui.QComboBox(self.AdvancedTab)
|
||||
self.AdvancedBookComboBox.setObjectName('AdvancedBookComboBox')
|
||||
self.AdvancedLayout.addWidget(self.AdvancedBookComboBox, 1, 2, 1, 2)
|
||||
self.AdvancedChapterLabel = QtGui.QLabel(self.AdvancedTab)
|
||||
self.AdvancedChapterLabel.setObjectName('AdvancedChapterLabel')
|
||||
self.AdvancedChapterLabel.setText('Chapter:')
|
||||
self.AdvancedLayout.addWidget(self.AdvancedChapterLabel, 2, 2, 1, 1)
|
||||
self.AdvancedVerseLabel = QtGui.QLabel(self.AdvancedTab)
|
||||
self.AdvancedVerseLabel.setObjectName('AdvancedVerseLabel')
|
||||
self.AdvancedVerseLabel.setText('Verse:')
|
||||
self.AdvancedLayout.addWidget(self.AdvancedVerseLabel, 2, 3, 1, 1)
|
||||
self.AdvancedFromLabel = QtGui.QLabel(self.AdvancedTab)
|
||||
self.AdvancedFromLabel.setObjectName('AdvancedFromLabel')
|
||||
self.AdvancedFromLabel.setText('From:')
|
||||
self.AdvancedLayout.addWidget(self.AdvancedFromLabel, 3, 0, 1, 1)
|
||||
self.AdvancedToLabel = QtGui.QLabel(self.AdvancedTab)
|
||||
self.AdvancedToLabel.setObjectName('AdvancedToLabel')
|
||||
self.AdvancedToLabel.setText('To:')
|
||||
self.AdvancedLayout.addWidget(self.AdvancedToLabel, 4, 0, 1, 1)
|
||||
self.AdvancedFromChapter = QtGui.QComboBox(self.AdvancedTab)
|
||||
self.AdvancedFromChapter.setObjectName('AdvancedFromChapter')
|
||||
self.AdvancedLayout.addWidget(self.AdvancedFromChapter, 3, 3, 1, 1)
|
||||
self.AdvancedFromVerse = QtGui.QComboBox(self.AdvancedTab)
|
||||
self.AdvancedFromVerse.setObjectName('AdvancedFromVerse')
|
||||
self.AdvancedLayout.addWidget(self.AdvancedFromVerse, 3, 2, 1, 1)
|
||||
self.AdvancedToChapter = QtGui.QComboBox(self.AdvancedTab)
|
||||
self.AdvancedToChapter.setObjectName('AdvancedToChapter')
|
||||
self.AdvancedLayout.addWidget(self.AdvancedToChapter, 4, 2, 1, 1)
|
||||
self.AdvancedToVerse = QtGui.QComboBox(self.AdvancedTab)
|
||||
self.AdvancedToVerse.setObjectName('AdvancedToVerse')
|
||||
self.AdvancedLayout.addWidget(self.AdvancedToVerse, 4, 3, 1, 1)
|
||||
self.AdvancedSearchButton = QtGui.QPushButton(self.AdvancedTab)
|
||||
self.AdvancedSearchButton.setObjectName('AdvancedSearchButton')
|
||||
self.AdvancedSearchButton.setText('Search')
|
||||
self.AdvancedLayout.addWidget(self.AdvancedSearchButton, 5, 3, 1, 1)
|
||||
self.SearchTabWidget.addTab(self.AdvancedTab, 'Advanced Search')
|
||||
|
||||
# Add the search tab widget to the page layout
|
||||
self.MediaManagerItem.PageLayout.addWidget(self.SearchTabWidget)
|
||||
|
||||
"""self.groupBox = QtGui.QGroupBox(self.MediaManagerItem)
|
||||
self.groupBox.setGeometry(QtCore.QRect(0, 0, 271, 391))
|
||||
self.groupBox.setMinimumSize(QtCore.QSize(0, 271))
|
||||
self.groupBox.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum))
|
||||
self.groupBox.setObjectName("groupBox")
|
||||
self.MediaManagerItem.PageLayout.addWidget(self.groupBox)
|
||||
|
||||
self.biblelabel = QtGui.QLabel(self.groupBox)
|
||||
self.biblelabel.setGeometry(QtCore.QRect(10, 20, 80, 25))
|
||||
@ -140,15 +233,14 @@ class BiblePlugin(Plugin):
|
||||
self.searchButton.setGeometry(QtCore.QRect(170, 170, 75, 27))
|
||||
self.searchButton.setObjectName("searchButton")
|
||||
self.searchButton.setText("Search")
|
||||
QtCore.QObject.connect(self.searchButton, QtCore.SIGNAL("pressed()"), self.onBibleSearchClick)
|
||||
QtCore.QObject.connect(self.searchButton, QtCore.SIGNAL("pressed()"), self.onBibleSearchClick)"""
|
||||
|
||||
|
||||
self.listView = QtGui.QListView(self.groupBox)
|
||||
self.listView = QtGui.QListView()
|
||||
self.listView.setGeometry(QtCore.QRect(10, 200, 256, 391))
|
||||
self.listView.setObjectName("listView")
|
||||
|
||||
self.MediaManagerItem.PageLayout.addWidget(self.groupBox)
|
||||
self.textsearchmode()
|
||||
self.MediaManagerItem.PageLayout.addWidget(self.listView)
|
||||
|
||||
#self.textsearchmode()
|
||||
return self.MediaManagerItem
|
||||
|
||||
def onBibleNewClick(self):
|
||||
@ -166,17 +258,19 @@ class BiblePlugin(Plugin):
|
||||
pass
|
||||
|
||||
def onBibleSearchClick(self):
|
||||
if self.textsearch == True:
|
||||
print "Text / Verse Search"
|
||||
else:
|
||||
print "Combo Search"
|
||||
#if self.textsearch == True:
|
||||
# print "Text / Verse Search"
|
||||
#else:
|
||||
# print "Combo Search"
|
||||
pass
|
||||
|
||||
|
||||
def onBibleSearchChangeClick(self):
|
||||
self.textsearchmode()
|
||||
#self.textsearchmode()
|
||||
pass
|
||||
|
||||
def textsearchmode(self):
|
||||
if self.textsearch == True:
|
||||
"""if self.textsearch == True:
|
||||
self.textsearch = False
|
||||
self.searchcomboBox.hide()
|
||||
self.searchEdit.hide()
|
||||
@ -203,5 +297,6 @@ class BiblePlugin(Plugin):
|
||||
self.chapterlabel.hide()
|
||||
self.verselabel.hide()
|
||||
self.fromlabel.hide()
|
||||
self.tolabel.hide()
|
||||
self.tolabel.hide()"""
|
||||
pass
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user