Compare commits
No commits in common. "02dd7b64b505c130fc17847ebc085ff55f0150b4" and "02a371b81e966238345edcaed80c4263d8dd7266" have entirely different histories.
02dd7b64b5
...
02a371b81e
@ -46,8 +46,6 @@ packagesExist(quazip1-qt5) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
INCLUDEPATH += $$PWD/../shared
|
INCLUDEPATH += $$PWD/../shared
|
||||||
INCLUDEPATH += /usr/include/poppler/qt5/
|
|
||||||
|
|
||||||
DEPENDPATH += $$PWD/../shared
|
DEPENDPATH += $$PWD/../shared
|
||||||
|
|
||||||
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../shared/release/libshared.a
|
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../shared/release/libshared.a
|
||||||
|
@ -24,7 +24,7 @@ QSharedPointer<PreviewResult> PreviewGeneratorOdt::generate(RenderConfig config,
|
|||||||
throw LooqsGeneralException("Error while reading content.xml of " + documentPath);
|
throw LooqsGeneralException("Error while reading content.xml of " + documentPath);
|
||||||
}
|
}
|
||||||
TagStripperProcessor tsp;
|
TagStripperProcessor tsp;
|
||||||
QString content = tsp.process(entireContent).pages.constFirst().content;
|
QString content = tsp.process(entireContent).constFirst().content;
|
||||||
|
|
||||||
PreviewGeneratorPlainText plainTextGenerator;
|
PreviewGeneratorPlainText plainTextGenerator;
|
||||||
result->setText(plainTextGenerator.generatePreviewText(content, config, info.fileName()));
|
result->setText(plainTextGenerator.generatePreviewText(content, config, info.fileName()));
|
||||||
|
@ -110,7 +110,7 @@ int FileSaver::processFiles(const QVector<QString> paths, std::function<SaveFile
|
|||||||
|
|
||||||
SaveFileResult FileSaver::saveFile(const QFileInfo &fileInfo)
|
SaveFileResult FileSaver::saveFile(const QFileInfo &fileInfo)
|
||||||
{
|
{
|
||||||
DocumentProcessResult processResult;
|
QVector<PageData> pageData;
|
||||||
QString canonicalPath = fileInfo.canonicalFilePath();
|
QString canonicalPath = fileInfo.canonicalFilePath();
|
||||||
|
|
||||||
int processorReturnCode = -1;
|
int processorReturnCode = -1;
|
||||||
@ -169,10 +169,11 @@ SaveFileResult FileSaver::saveFile(const QFileInfo &fileInfo)
|
|||||||
* finishes.
|
* finishes.
|
||||||
*/
|
*/
|
||||||
QDataStream in(process.readAllStandardOutput());
|
QDataStream in(process.readAllStandardOutput());
|
||||||
|
while(!in.atEnd())
|
||||||
if(!in.atEnd())
|
|
||||||
{
|
{
|
||||||
in >> processResult;
|
PageData pd;
|
||||||
|
in >> pd;
|
||||||
|
pageData.append(pd);
|
||||||
}
|
}
|
||||||
processorReturnCode = process.exitCode();
|
processorReturnCode = process.exitCode();
|
||||||
if(processorReturnCode != OK && processorReturnCode != OK_WASEMPTY)
|
if(processorReturnCode != OK && processorReturnCode != OK_WASEMPTY)
|
||||||
@ -184,7 +185,7 @@ SaveFileResult FileSaver::saveFile(const QFileInfo &fileInfo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SaveFileResult result = this->dbService->saveFile(fileInfo, processResult, this->fileSaverOptions.metadataOnly);
|
SaveFileResult result = this->dbService->saveFile(fileInfo, pageData, this->fileSaverOptions.metadataOnly);
|
||||||
if(result == OK && processorReturnCode == OK_WASEMPTY)
|
if(result == OK && processorReturnCode == OK_WASEMPTY)
|
||||||
{
|
{
|
||||||
return OK_WASEMPTY;
|
return OK_WASEMPTY;
|
||||||
|
@ -29,11 +29,6 @@ bool LooqsQuery::hasContentSearch() const
|
|||||||
return (this->getTokensMask() & FILTER_CONTENT) == FILTER_CONTENT;
|
return (this->getTokensMask() & FILTER_CONTENT) == FILTER_CONTENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LooqsQuery::hasOutlineSearch() const
|
|
||||||
{
|
|
||||||
return (this->getTokensMask() & FILTER_OUTLINE_CONTAINS) == FILTER_OUTLINE_CONTAINS;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LooqsQuery::hasPathSearch() const
|
bool LooqsQuery::hasPathSearch() const
|
||||||
{
|
{
|
||||||
return (this->getTokensMask() & FILTER_PATH) == FILTER_PATH;
|
return (this->getTokensMask() & FILTER_PATH) == FILTER_PATH;
|
||||||
@ -294,10 +289,6 @@ LooqsQuery LooqsQuery::build(QString expression, TokenType loneWordsTokenType, b
|
|||||||
{
|
{
|
||||||
tokenType = FILTER_TAG_ASSIGNED;
|
tokenType = FILTER_TAG_ASSIGNED;
|
||||||
}
|
}
|
||||||
else if(filtername == "toc" || filtername == "outline")
|
|
||||||
{
|
|
||||||
tokenType = FILTER_OUTLINE_CONTAINS;
|
|
||||||
}
|
|
||||||
// TODO: given this is not really a "filter", this feels slightly misplaced here
|
// TODO: given this is not really a "filter", this feels slightly misplaced here
|
||||||
else if(filtername == "sort")
|
else if(filtername == "sort")
|
||||||
{
|
{
|
||||||
|
@ -68,7 +68,6 @@ class LooqsQuery
|
|||||||
this->limit = limit;
|
this->limit = limit;
|
||||||
}
|
}
|
||||||
bool hasContentSearch() const;
|
bool hasContentSearch() const;
|
||||||
bool hasOutlineSearch() const;
|
|
||||||
bool hasPathSearch() const;
|
bool hasPathSearch() const;
|
||||||
|
|
||||||
void addSortCondition(SortCondition sc);
|
void addSortCondition(SortCondition sc);
|
||||||
|
@ -10,7 +10,7 @@ class NothingProcessor : public Processor
|
|||||||
NothingProcessor();
|
NothingProcessor();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DocumentProcessResult process(const QByteArray & /*data*/) const override
|
QVector<PageData> process(const QByteArray & /*data*/) const override
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -5,30 +5,9 @@ PdfProcessor::PdfProcessor()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<DocumentOutlineEntry> PdfProcessor::createOutline(const QVector<Poppler::OutlineItem> &outlineItems) const
|
QVector<PageData> PdfProcessor::process(const QByteArray &data) const
|
||||||
{
|
{
|
||||||
QVector<DocumentOutlineEntry> result;
|
QVector<PageData> result;
|
||||||
for(const Poppler::OutlineItem &outlineItem : outlineItems)
|
|
||||||
{
|
|
||||||
DocumentOutlineEntry documentOutlineEntry;
|
|
||||||
documentOutlineEntry.text = outlineItem.name();
|
|
||||||
documentOutlineEntry.type = OUTLINE_DESTINATION_TYPE_PAGE;
|
|
||||||
if(!outlineItem.destination().isNull())
|
|
||||||
{
|
|
||||||
documentOutlineEntry.destinationPage = outlineItem.destination()->pageNumber();
|
|
||||||
}
|
|
||||||
if(outlineItem.hasChildren())
|
|
||||||
{
|
|
||||||
documentOutlineEntry.children = createOutline(outlineItem.children());
|
|
||||||
}
|
|
||||||
result.append(documentOutlineEntry);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
DocumentProcessResult PdfProcessor::process(const QByteArray &data) const
|
|
||||||
{
|
|
||||||
DocumentProcessResult result;
|
|
||||||
QScopedPointer<Poppler::Document> doc(Poppler::Document::loadFromData(data));
|
QScopedPointer<Poppler::Document> doc(Poppler::Document::loadFromData(data));
|
||||||
if(doc.isNull())
|
if(doc.isNull())
|
||||||
{
|
{
|
||||||
@ -47,13 +26,12 @@ DocumentProcessResult PdfProcessor::process(const QByteArray &data) const
|
|||||||
for(auto i = 0; i < pagecount; i++)
|
for(auto i = 0; i < pagecount; i++)
|
||||||
{
|
{
|
||||||
QString text = doc->page(i)->text(entirePage);
|
QString text = doc->page(i)->text(entirePage);
|
||||||
result.pages.append({static_cast<unsigned int>(i + 1), text});
|
result.append({static_cast<unsigned int>(i + 1), text});
|
||||||
/*TODO: hack, so we can fts search several words over the whole document, not just pages.
|
/*TODO: hack, so we can fts search several words over the whole document, not just pages.
|
||||||
* this of course uses more space and should be solved differently.
|
* this of course uses more space and should be solved differently.
|
||||||
*/
|
*/
|
||||||
entire += text;
|
entire += text;
|
||||||
}
|
}
|
||||||
result.pages.append({0, entire});
|
result.append({0, entire});
|
||||||
result.outlines = createOutline(doc->outline());
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#ifndef PDFPROCESSOR_H
|
#ifndef PDFPROCESSOR_H
|
||||||
#define PDFPROCESSOR_H
|
#define PDFPROCESSOR_H
|
||||||
#include <poppler-qt5.h>
|
|
||||||
#include "processor.h"
|
#include "processor.h"
|
||||||
class PdfProcessor : public Processor
|
class PdfProcessor : public Processor
|
||||||
{
|
{
|
||||||
@ -8,8 +7,7 @@ class PdfProcessor : public Processor
|
|||||||
PdfProcessor();
|
PdfProcessor();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QVector<DocumentOutlineEntry> createOutline(const QVector<Poppler::OutlineItem> &outlineItems) const;
|
QVector<PageData> process(const QByteArray &data) const override;
|
||||||
DocumentProcessResult process(const QByteArray &data) const override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PDFPROCESSOR_H
|
#endif // PDFPROCESSOR_H
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
#define PROCESSOR_H
|
#define PROCESSOR_H
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include "pagedata.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "documentprocessresult.h"
|
|
||||||
enum DataSource
|
enum DataSource
|
||||||
{
|
{
|
||||||
FILEPATH,
|
FILEPATH,
|
||||||
@ -18,8 +18,8 @@ class Processor
|
|||||||
* a single file */
|
* a single file */
|
||||||
DataSource PREFERED_DATA_SOURCE = ARRAY;
|
DataSource PREFERED_DATA_SOURCE = ARRAY;
|
||||||
Processor();
|
Processor();
|
||||||
virtual DocumentProcessResult process(const QByteArray &data) const = 0;
|
virtual QVector<PageData> process(const QByteArray &data) const = 0;
|
||||||
virtual DocumentProcessResult process(QString path) const
|
virtual QVector<PageData> process(QString path) const
|
||||||
{
|
{
|
||||||
return process(Utils::readFile(path));
|
return process(Utils::readFile(path));
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,6 @@ SOURCES += sqlitesearch.cpp \
|
|||||||
dbmigrator.cpp \
|
dbmigrator.cpp \
|
||||||
defaulttextprocessor.cpp \
|
defaulttextprocessor.cpp \
|
||||||
dirscanworker.cpp \
|
dirscanworker.cpp \
|
||||||
documentoutlineentry.cpp \
|
|
||||||
documentprocessresult.cpp \
|
|
||||||
encodingdetector.cpp \
|
encodingdetector.cpp \
|
||||||
filesaver.cpp \
|
filesaver.cpp \
|
||||||
filescanworker.cpp \
|
filescanworker.cpp \
|
||||||
@ -74,8 +72,6 @@ HEADERS += sqlitesearch.h \
|
|||||||
dbmigrator.h \
|
dbmigrator.h \
|
||||||
defaulttextprocessor.h \
|
defaulttextprocessor.h \
|
||||||
dirscanworker.h \
|
dirscanworker.h \
|
||||||
documentoutlineentry.h \
|
|
||||||
documentprocessresult.h \
|
|
||||||
encodingdetector.h \
|
encodingdetector.h \
|
||||||
filedata.h \
|
filedata.h \
|
||||||
filesaver.h \
|
filesaver.h \
|
||||||
|
@ -253,29 +253,6 @@ bool SqliteDbService::insertToFTS(bool useTrigrams, QSqlDatabase &db, int fileid
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SqliteDbService::insertOutline(QSqlDatabase &db, int fileid, const QVector<DocumentOutlineEntry> &outlines)
|
|
||||||
{
|
|
||||||
QSqlQuery outlineQuery(db);
|
|
||||||
outlineQuery.prepare("INSERT INTO outline(fileid, text, page) VALUES(?,?,?)");
|
|
||||||
outlineQuery.addBindValue(fileid);
|
|
||||||
for(const DocumentOutlineEntry &outline : outlines)
|
|
||||||
{
|
|
||||||
outlineQuery.bindValue(1, outline.text.toLower());
|
|
||||||
outlineQuery.bindValue(2, outline.destinationPage);
|
|
||||||
if(!outlineQuery.exec())
|
|
||||||
{
|
|
||||||
Logger::error() << "Failed outline insertion " << outlineQuery.lastError() << Qt::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(!insertOutline(db, fileid, outline.children))
|
|
||||||
{
|
|
||||||
Logger::error() << "Failed outline insertion (children)) " << outlineQuery.lastError() << Qt::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QSqlQuery SqliteDbService::exec(QString querystr, std::initializer_list<QVariant> args)
|
QSqlQuery SqliteDbService::exec(QString querystr, std::initializer_list<QVariant> args)
|
||||||
{
|
{
|
||||||
auto query = QSqlQuery(dbFactory->forCurrentThread());
|
auto query = QSqlQuery(dbFactory->forCurrentThread());
|
||||||
@ -301,7 +278,7 @@ bool SqliteDbService::execBool(QString querystr, std::initializer_list<QVariant>
|
|||||||
return query.value(0).toBool();
|
return query.value(0).toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveFileResult SqliteDbService::saveFile(QFileInfo fileInfo, DocumentProcessResult &processResult, bool pathsOnly)
|
SaveFileResult SqliteDbService::saveFile(QFileInfo fileInfo, QVector<PageData> &pageData, bool pathsOnly)
|
||||||
{
|
{
|
||||||
QString absPath = fileInfo.absoluteFilePath();
|
QString absPath = fileInfo.absoluteFilePath();
|
||||||
auto mtime = fileInfo.lastModified().toSecsSinceEpoch();
|
auto mtime = fileInfo.lastModified().toSecsSinceEpoch();
|
||||||
@ -346,24 +323,18 @@ SaveFileResult SqliteDbService::saveFile(QFileInfo fileInfo, DocumentProcessResu
|
|||||||
if(!pathsOnly)
|
if(!pathsOnly)
|
||||||
{
|
{
|
||||||
int lastid = inserterQuery.lastInsertId().toInt();
|
int lastid = inserterQuery.lastInsertId().toInt();
|
||||||
if(!insertToFTS(false, db, lastid, processResult.pages))
|
if(!insertToFTS(false, db, lastid, pageData))
|
||||||
{
|
{
|
||||||
db.rollback();
|
db.rollback();
|
||||||
Logger::error() << "Failed to insert data to FTS index " << Qt::endl;
|
Logger::error() << "Failed to insert data to FTS index " << Qt::endl;
|
||||||
return DBFAIL;
|
return DBFAIL;
|
||||||
}
|
}
|
||||||
if(!insertToFTS(true, db, lastid, processResult.pages))
|
if(!insertToFTS(true, db, lastid, pageData))
|
||||||
{
|
{
|
||||||
db.rollback();
|
db.rollback();
|
||||||
Logger::error() << "Failed to insert data to FTS index " << Qt::endl;
|
Logger::error() << "Failed to insert data to FTS index " << Qt::endl;
|
||||||
return DBFAIL;
|
return DBFAIL;
|
||||||
}
|
}
|
||||||
if(!insertOutline(db, lastid, processResult.outlines))
|
|
||||||
{
|
|
||||||
db.rollback();
|
|
||||||
Logger::error() << "Failed to insert outline data " << Qt::endl;
|
|
||||||
return DBFAIL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!db.commit())
|
if(!db.commit())
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include "databasefactory.h"
|
#include "databasefactory.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "documentprocessresult.h"
|
#include "pagedata.h"
|
||||||
#include "filedata.h"
|
#include "filedata.h"
|
||||||
#include "../shared/sqlitesearch.h"
|
#include "../shared/sqlitesearch.h"
|
||||||
#include "../shared/token.h"
|
#include "../shared/token.h"
|
||||||
@ -22,7 +22,7 @@ class SqliteDbService
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
SqliteDbService(DatabaseFactory &dbFactory);
|
SqliteDbService(DatabaseFactory &dbFactory);
|
||||||
SaveFileResult saveFile(QFileInfo fileInfo, DocumentProcessResult &pageData, bool pathsOnly);
|
SaveFileResult saveFile(QFileInfo fileInfo, QVector<PageData> &pageData, bool pathsOnly);
|
||||||
|
|
||||||
bool deleteFile(QString path);
|
bool deleteFile(QString path);
|
||||||
bool fileExistsInDatabase(QString path);
|
bool fileExistsInDatabase(QString path);
|
||||||
@ -42,7 +42,6 @@ class SqliteDbService
|
|||||||
QVector<SearchResult> search(const LooqsQuery &query);
|
QVector<SearchResult> search(const LooqsQuery &query);
|
||||||
|
|
||||||
std::optional<QChar> queryFileType(QString absPath);
|
std::optional<QChar> queryFileType(QString absPath);
|
||||||
bool insertOutline(QSqlDatabase &db, int fileid, const QVector<DocumentOutlineEntry> &outlines);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SQLITEDBSERVICE_H
|
#endif // SQLITEDBSERVICE_H
|
||||||
|
@ -148,11 +148,6 @@ QPair<QString, QVector<QString>> SqliteSearch::createSql(const Token &token)
|
|||||||
return {" file.id IN (SELECT fileid FROM filetag WHERE tagid = (SELECT id FROM tag WHERE name = ?)) ",
|
return {" file.id IN (SELECT fileid FROM filetag WHERE tagid = (SELECT id FROM tag WHERE name = ?)) ",
|
||||||
{value.toLower()}};
|
{value.toLower()}};
|
||||||
}
|
}
|
||||||
if(token.type == FILTER_OUTLINE_CONTAINS)
|
|
||||||
{
|
|
||||||
return {" outline.text LIKE '%' || ? || '%' ", {value.toLower()}};
|
|
||||||
}
|
|
||||||
|
|
||||||
throw LooqsGeneralException("Unknown token passed (should not happen)");
|
throw LooqsGeneralException("Unknown token passed (should not happen)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +156,6 @@ QSqlQuery SqliteSearch::makeSqlQuery(const LooqsQuery &query)
|
|||||||
QString whereSql;
|
QString whereSql;
|
||||||
QVector<QString> bindValues;
|
QVector<QString> bindValues;
|
||||||
bool isContentSearch = (query.getTokensMask() & FILTER_CONTENT) == FILTER_CONTENT;
|
bool isContentSearch = (query.getTokensMask() & FILTER_CONTENT) == FILTER_CONTENT;
|
||||||
bool isOutlineSearch = query.hasOutlineSearch();
|
|
||||||
if(query.getTokens().isEmpty())
|
if(query.getTokens().isEmpty())
|
||||||
{
|
{
|
||||||
throw LooqsGeneralException("Nothing to search for supplied");
|
throw LooqsGeneralException("Nothing to search for supplied");
|
||||||
@ -206,22 +200,15 @@ QSqlQuery SqliteSearch::makeSqlQuery(const LooqsQuery &query)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QString pageColumn = "'0' as page";
|
|
||||||
QString joiners = "";
|
|
||||||
if(isOutlineSearch)
|
|
||||||
{
|
|
||||||
pageColumn = "outline.page as page";
|
|
||||||
joiners = " INNER JOIN outline ON outline.fileid = file.id ";
|
|
||||||
}
|
|
||||||
if(sortSql.isEmpty())
|
if(sortSql.isEmpty())
|
||||||
{
|
{
|
||||||
sortSql = "ORDER BY file.mtime DESC";
|
sortSql = "ORDER BY file.mtime DESC";
|
||||||
}
|
}
|
||||||
prepSql = "SELECT DISTINCT file.path AS path, " + pageColumn +
|
prepSql = "SELECT file.path AS path, '0' as page, file.mtime AS mtime, file.size AS size, file.filetype AS "
|
||||||
",file.mtime AS mtime, file.size AS size, "
|
"filetype FROM file WHERE 1=1 AND " +
|
||||||
"file.filetype AS filetype FROM file" +
|
whereSql + " " + sortSql;
|
||||||
joiners + " WHERE 1=1 AND " + whereSql + " " + sortSql;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(query.getLimit() > 0)
|
if(query.getLimit() > 0)
|
||||||
{
|
{
|
||||||
prepSql += " LIMIT " + QString::number(query.getLimit());
|
prepSql += " LIMIT " + QString::number(query.getLimit());
|
||||||
@ -255,7 +242,7 @@ QVector<SearchResult> SqliteSearch::search(const LooqsQuery &query)
|
|||||||
throw LooqsGeneralException("SQL Error: " + dbQuery.lastError().text());
|
throw LooqsGeneralException("SQL Error: " + dbQuery.lastError().text());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool contentSearch = query.hasContentSearch() || query.hasOutlineSearch();
|
bool contentSearch = query.hasContentSearch();
|
||||||
while(dbQuery.next())
|
while(dbQuery.next())
|
||||||
{
|
{
|
||||||
SearchResult result;
|
SearchResult result;
|
||||||
|
@ -20,7 +20,6 @@ enum TokenType
|
|||||||
FILTER_PATH_ENDS,
|
FILTER_PATH_ENDS,
|
||||||
FILTER_PATH_STARTS,
|
FILTER_PATH_STARTS,
|
||||||
FILTER_TAG_ASSIGNED,
|
FILTER_TAG_ASSIGNED,
|
||||||
FILTER_OUTLINE_CONTAINS,
|
|
||||||
FILTER_CONTENT = 512, /* Everything below here is content search (except LIMIT) */
|
FILTER_CONTENT = 512, /* Everything below here is content search (except LIMIT) */
|
||||||
FILTER_CONTENT_CONTAINS,
|
FILTER_CONTENT_CONTAINS,
|
||||||
FILTER_CONTENT_PAGE,
|
FILTER_CONTENT_PAGE,
|
||||||
|
Loading…
Reference in New Issue
Block a user