mirror of
https://github.com/thelounge/thelounge.git
synced 2024-06-27 09:40:09 +02:00
search: add nick keyword search
- search messages by author with `from:nick` - add section to Help.vue - should be easy to adapt this into global keyword-based search https://github.com/thelounge/thelounge/issues/4209
This commit is contained in:
parent
2e3d9a6265
commit
27d69b00ff
|
@ -825,6 +825,23 @@
|
|||
<p>Retrieve information about the given user on the current network.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Search</h2>
|
||||
|
||||
<p>
|
||||
You can search messages simply by clicking the magnifying glass icon on the right
|
||||
side of a channel's titlebar and entering a search term. Here are some additional
|
||||
keywords you can use to fine-tune your search.
|
||||
</p>
|
||||
|
||||
<div class="help-item">
|
||||
<div class="subject">
|
||||
<code>from:<em>nick</em></code>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p>Search messages by author.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -208,9 +208,41 @@ class MessageStorage {
|
|||
// Using the '@' character to escape '%' and '_' in patterns.
|
||||
const escapedSearchTerm = query.searchTerm.replace(/([%_@])/g, "@$1");
|
||||
|
||||
// Additional filtering:
|
||||
// - "from:nick" to find messages sent by a given nick
|
||||
const keywords = ["from"];
|
||||
const joinedKeywords = keywords.map((kw) => kw + ":").join("|");
|
||||
const filterExp = RegExp(`((${joinedKeywords})(\\S+))+`, "g");
|
||||
|
||||
let filters;
|
||||
const filterMatch = escapedSearchTerm.match(filterExp);
|
||||
|
||||
if (filterMatch && filterMatch.length) {
|
||||
filters = filterMatch.reduce((params, filter) => {
|
||||
const [key, value] = filter.split(":");
|
||||
params[key] = value;
|
||||
return params;
|
||||
}, {});
|
||||
}
|
||||
|
||||
// strip "key:value" filter pairs out of search string
|
||||
const mainSearchTerm = escapedSearchTerm.replace(filterExp, "").trim();
|
||||
|
||||
let select =
|
||||
'SELECT msg, type, time, network, channel FROM messages WHERE type = "message" AND json_extract(msg, "$.text") LIKE ? ESCAPE \'@\'';
|
||||
const params = [`%${escapedSearchTerm}%`];
|
||||
'SELECT msg, type, time, network, channel FROM messages WHERE type = "message"';
|
||||
const params = [];
|
||||
|
||||
if (mainSearchTerm.length) {
|
||||
select += " AND json_extract(msg, \"$.text\") LIKE ? ESCAPE '@'";
|
||||
params.push(`%${mainSearchTerm}%`);
|
||||
}
|
||||
|
||||
if (filters && Object.keys(filters).length) {
|
||||
if (filters.from) {
|
||||
select += ' AND json_extract(msg, "$.from.nick") LIKE ?';
|
||||
params.push(filters.from);
|
||||
}
|
||||
}
|
||||
|
||||
if (query.networkUuid) {
|
||||
select += " AND network = ? ";
|
||||
|
|
|
@ -243,6 +243,83 @@ describe("SQLite Message Storage", function () {
|
|||
}
|
||||
});
|
||||
|
||||
it("should search messages with keyword queries", function () {
|
||||
function assertResults(query, expected) {
|
||||
return store
|
||||
.search({
|
||||
searchTerm: query,
|
||||
networkUuid: "this-is-a-network-guid3",
|
||||
})
|
||||
.then((messages) => {
|
||||
expect(messages.results.map((i) => i.text)).to.deep.equal(expected);
|
||||
});
|
||||
}
|
||||
|
||||
const originalMaxHistory = Config.values.maxHistory;
|
||||
|
||||
try {
|
||||
Config.values.maxHistory = 3;
|
||||
|
||||
store.index(
|
||||
{uuid: "this-is-a-network-guid3"},
|
||||
{name: "#channel"},
|
||||
new Msg({
|
||||
time: 123456793,
|
||||
text: "my first message",
|
||||
from: {
|
||||
mode: "",
|
||||
nick: "thelounge007",
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
store.index(
|
||||
{uuid: "this-is-a-network-guid3"},
|
||||
{name: "#channel"},
|
||||
new Msg({
|
||||
time: 123456794,
|
||||
text: "no, my first message!",
|
||||
from: {
|
||||
mode: "",
|
||||
nick: "thelounge008",
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
store.index(
|
||||
{uuid: "this-is-a-network-guid3"},
|
||||
{name: "#channel"},
|
||||
new Msg({
|
||||
time: 123456795,
|
||||
text: "another unrelated message",
|
||||
from: {
|
||||
mode: "",
|
||||
nick: "thelounge007",
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
return (
|
||||
store
|
||||
.getMessages({uuid: "this-is-a-network-guid3"}, {name: "#channel"})
|
||||
// .getMessages() waits for store.index() transactions to commit
|
||||
.then(() =>
|
||||
assertResults("from:thelounge007", [
|
||||
"my first message",
|
||||
"another unrelated message",
|
||||
])
|
||||
)
|
||||
.then(() => assertResults("from:thelounge007 first", ["my first message"]))
|
||||
.then(() =>
|
||||
assertResults("first", ["my first message", "no, my first message!"])
|
||||
)
|
||||
.then(() => assertResults("from:nobody", []))
|
||||
);
|
||||
} finally {
|
||||
Config.values.maxHistory = originalMaxHistory;
|
||||
}
|
||||
});
|
||||
|
||||
it("should close database", function (done) {
|
||||
store.close((err) => {
|
||||
expect(err).to.be.null;
|
||||
|
|
Loading…
Reference in a new issue