Feature: W.I.P. search route

This commit is contained in:
Paul
2021-07-09 14:34:01 +01:00
parent fe821b8283
commit 6f8802ab5f
6 changed files with 165 additions and 3 deletions

View File

@@ -1,3 +1,3 @@
#!/bin/bash
export version=0.5.1-alpha.6
export version=0.5.1-alpha.7
echo "pub const VERSION: &str = \"${version}\";" > src/version.rs

View File

@@ -122,6 +122,23 @@ pub async fn create_database() {
.await
.expect("Failed to create username index.");
db.run_command(
doc! {
"createIndexes": "messages",
"indexes": [
{
"key": {
"content": "text"
},
"name": "content"
}
]
},
None,
)
.await
.expect("Failed to create message index.");
db.collection("migrations")
.insert_one(
doc! {

View File

@@ -11,7 +11,7 @@ struct MigrationInfo {
revision: i32,
}
pub const LATEST_REVISION: i32 = 6;
pub const LATEST_REVISION: i32 = 7;
pub async fn migrate_database() {
let migrations = get_collection("migrations");
@@ -181,6 +181,28 @@ pub async fn run_migrations(revision: i32) -> i32 {
.expect("Failed to migrate servers.");
}
if revision <= 6 {
info!("Running migration [revision 6 / 2021-07-09]: Add message text index.");
get_db()
.run_command(
doc! {
"createIndexes": "messages",
"indexes": [
{
"key": {
"content": "text"
},
"name": "content"
}
]
},
None,
)
.await
.expect("Failed to create message index.");
}
// Reminder to update LATEST_REVISION when adding new migrations.
LATEST_REVISION
}

View File

@@ -0,0 +1,121 @@
use std::collections::HashSet;
use crate::database::*;
use crate::util::result::{Error, Result};
use futures::StreamExt;
use mongodb::{
bson::{doc, from_document},
options::FindOptions,
};
use rocket_contrib::json::{Json, JsonValue};
use serde::{Deserialize, Serialize};
use validator::Validate;
#[derive(Serialize, Deserialize, FromFormValue)]
pub enum Sort {
Relevance,
Latest,
Oldest,
}
#[derive(Validate, Serialize, Deserialize, FromForm)]
pub struct Options {
#[validate(length(min = 1, max = 64))]
query: String,
#[validate(range(min = 1, max = 100))]
limit: Option<i64>,
#[validate(length(min = 26, max = 26))]
before: Option<String>,
#[validate(length(min = 26, max = 26))]
after: Option<String>,
sort: Option<Sort>,
include_users: Option<bool>,
}
#[post("/<target>/search", data = "<options>")]
pub async fn req(user: User, target: Ref, options: Json<Options>) -> Result<JsonValue> {
options
.validate()
.map_err(|error| Error::FailedValidation { error })?;
let target = target.fetch_channel().await?;
target.has_messaging()?;
let perm = permissions::PermissionCalculator::new(&user)
.with_channel(&target)
.for_channel()
.await?;
if !perm.get_view() {
Err(Error::MissingPermission)?
}
let mut messages = vec![];
let limit = options.limit.unwrap_or(50);
let mut cursor = get_collection("messages")
.find(
doc! {
"channel": target.id(),
"$text": {
"$search": &options.query
}
},
FindOptions::builder()
.projection(doc! {
"score": {
"$meta": "textScore"
}
})
.limit(limit)
.sort(doc! {
"score": {
"$meta": "textScore"
}
})
.build(),
)
.await
.map_err(|_| Error::DatabaseError {
operation: "find",
with: "messages",
})?;
while let Some(result) = cursor.next().await {
if let Ok(doc) = result {
messages.push(
from_document::<Message>(doc).map_err(|_| Error::DatabaseError {
operation: "from_document",
with: "message",
})?,
);
}
}
if options.include_users.unwrap_or_else(|| false) {
let mut ids = HashSet::new();
for message in &messages {
ids.insert(message.author.clone());
}
ids.remove(&user.id);
let user_ids = ids.into_iter().collect();
let users = user.fetch_multiple_users(user_ids).await?;
if let Channel::TextChannel { server, .. } = target {
Ok(json!({
"messages": messages,
"users": users,
"members": Server::fetch_members(&server).await?
}))
} else {
Ok(json!({
"messages": messages,
"users": users,
}))
}
} else {
Ok(json!(messages))
}
}

View File

@@ -14,6 +14,7 @@ mod message_delete;
mod message_edit;
mod message_fetch;
mod message_query;
mod message_search;
mod message_query_stale;
mod message_send;
mod permissions_set;
@@ -29,6 +30,7 @@ pub fn routes() -> Vec<Route> {
invite_create::req,
message_send::req,
message_query::req,
message_search::req,
message_query_stale::req,
message_fetch::req,
message_edit::req,

View File

@@ -1 +1 @@
pub const VERSION: &str = "0.5.1-alpha.6";
pub const VERSION: &str = "0.5.1-alpha.7";