feat: use ward info
This commit is contained in:
parent
dc4fc02e71
commit
db2cfcfb94
|
@ -7,6 +7,7 @@ namespace OrangeGuidanceTomestone;
|
||||||
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
|
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
|
||||||
public class MessageRequest {
|
public class MessageRequest {
|
||||||
public uint Territory { get; set; }
|
public uint Territory { get; set; }
|
||||||
|
public uint? Ward { get; set; }
|
||||||
public float X { get; set; }
|
public float X { get; set; }
|
||||||
public float Y { get; set; }
|
public float Y { get; set; }
|
||||||
public float Z { get; set; }
|
public float Z { get; set; }
|
||||||
|
|
|
@ -153,6 +153,8 @@ internal class Messages : IDisposable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ward = this.Plugin.Common.Functions.Housing.Location?.Ward;
|
||||||
|
|
||||||
if (this.Plugin.Config.DisableTrials && this.Trials.Contains(territory)) {
|
if (this.Plugin.Config.DisableTrials && this.Trials.Contains(territory)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -173,18 +175,23 @@ internal class Messages : IDisposable {
|
||||||
|
|
||||||
Task.Run(async () => {
|
Task.Run(async () => {
|
||||||
try {
|
try {
|
||||||
await this.DownloadMessages(territory);
|
await this.DownloadMessages(territory, ward);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
PluginLog.LogError(ex, $"Failed to get messages for territory {territory}");
|
PluginLog.LogError(ex, $"Failed to get messages for territory {territory}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DownloadMessages(ushort territory) {
|
private async Task DownloadMessages(ushort territory, ushort? ward) {
|
||||||
|
var route = $"/messages/{territory}";
|
||||||
|
if (ward != null) {
|
||||||
|
route += $"?ward={ward}";
|
||||||
|
}
|
||||||
|
|
||||||
var resp = await ServerHelper.SendRequest(
|
var resp = await ServerHelper.SendRequest(
|
||||||
this.Plugin.Config.ApiKey,
|
this.Plugin.Config.ApiKey,
|
||||||
HttpMethod.Get,
|
HttpMethod.Get,
|
||||||
$"/messages/{territory}"
|
route
|
||||||
);
|
);
|
||||||
var json = await resp.Content.ReadAsStringAsync();
|
var json = await resp.Content.ReadAsStringAsync();
|
||||||
var messages = JsonConvert.DeserializeObject<Message[]>(json)!;
|
var messages = JsonConvert.DeserializeObject<Message[]>(json)!;
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
<PackageReference Include="DalamudPackager" Version="2.1.10"/>
|
<PackageReference Include="DalamudPackager" Version="2.1.10"/>
|
||||||
<PackageReference Include="Fody" Version="6.6.4" PrivateAssets="all"/>
|
<PackageReference Include="Fody" Version="6.6.4" PrivateAssets="all"/>
|
||||||
<PackageReference Include="Resourcer.Fody" Version="1.8.0" PrivateAssets="all"/>
|
<PackageReference Include="Resourcer.Fody" Version="1.8.0" PrivateAssets="all"/>
|
||||||
|
<PackageReference Include="XivCommon" Version="7.0.0-alpha.1" PrivateAssets="all"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -7,6 +7,7 @@ using Dalamud.Game.Gui;
|
||||||
using Dalamud.IoC;
|
using Dalamud.IoC;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using OrangeGuidanceTomestone.MiniPenumbra;
|
using OrangeGuidanceTomestone.MiniPenumbra;
|
||||||
|
using XivCommon;
|
||||||
|
|
||||||
namespace OrangeGuidanceTomestone;
|
namespace OrangeGuidanceTomestone;
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ public class Plugin : IDalamudPlugin {
|
||||||
internal GameGui GameGui { get; init; }
|
internal GameGui GameGui { get; init; }
|
||||||
|
|
||||||
internal Configuration Config { get; }
|
internal Configuration Config { get; }
|
||||||
|
internal XivCommonBase Common { get; }
|
||||||
internal Vfx Vfx { get; }
|
internal Vfx Vfx { get; }
|
||||||
internal PluginUi Ui { get; }
|
internal PluginUi Ui { get; }
|
||||||
internal Messages Messages { get; }
|
internal Messages Messages { get; }
|
||||||
|
@ -51,6 +53,7 @@ public class Plugin : IDalamudPlugin {
|
||||||
this.AvfxFilePath = this.CopyAvfxFile();
|
this.AvfxFilePath = this.CopyAvfxFile();
|
||||||
|
|
||||||
this.Config = this.Interface!.GetPluginConfig() as Configuration ?? new Configuration();
|
this.Config = this.Interface!.GetPluginConfig() as Configuration ?? new Configuration();
|
||||||
|
this.Common = new XivCommonBase();
|
||||||
this.Vfx = new Vfx();
|
this.Vfx = new Vfx();
|
||||||
this.Messages = new Messages(this);
|
this.Messages = new Messages(this);
|
||||||
this.Ui = new PluginUi(this);
|
this.Ui = new PluginUi(this);
|
||||||
|
@ -70,6 +73,7 @@ public class Plugin : IDalamudPlugin {
|
||||||
this.Ui.Dispose();
|
this.Ui.Dispose();
|
||||||
this.Messages.Dispose();
|
this.Messages.Dispose();
|
||||||
this.Vfx.Dispose();
|
this.Vfx.Dispose();
|
||||||
|
this.Common.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void SaveConfig() {
|
internal void SaveConfig() {
|
||||||
|
|
|
@ -231,6 +231,7 @@ internal class Write : ITab {
|
||||||
if (ImGui.Button("Write") && valid && !inAir && this.Plugin.ClientState.LocalPlayer is { } player) {
|
if (ImGui.Button("Write") && valid && !inAir && this.Plugin.ClientState.LocalPlayer is { } player) {
|
||||||
var req = new MessageRequest {
|
var req = new MessageRequest {
|
||||||
Territory = this.Plugin.ClientState.TerritoryType,
|
Territory = this.Plugin.ClientState.TerritoryType,
|
||||||
|
Ward = this.Plugin.Common.Functions.Housing.Location?.Ward,
|
||||||
X = player.Position.X,
|
X = player.Position.X,
|
||||||
Y = player.Position.Y,
|
Y = player.Position.Y,
|
||||||
Z = player.Position.Z,
|
Z = player.Position.Z,
|
||||||
|
|
|
@ -24,6 +24,12 @@
|
||||||
"NETStandard.Library": "1.6.1"
|
"NETStandard.Library": "1.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"XivCommon": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[7.0.0-alpha.1, )",
|
||||||
|
"resolved": "7.0.0-alpha.1",
|
||||||
|
"contentHash": "4Yy4Wg3bnI/g9BSEYAqOZALmVMJZS0wcP847VlUIThBqIS/47O6tw2BI84he4KuPSTfIsYOzrcz3vAia8+Pn3g=="
|
||||||
|
},
|
||||||
"Microsoft.NETCore.Platforms": {
|
"Microsoft.NETCore.Platforms": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "1.1.0",
|
"resolved": "1.1.0",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,7 +7,7 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
base64 = "0.13"
|
base64 = "0.21"
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
if_chain = "1"
|
if_chain = "1"
|
||||||
|
@ -16,7 +16,7 @@ serde = { version = "1", features = ["derive"] }
|
||||||
serde_yaml = "0.9"
|
serde_yaml = "0.9"
|
||||||
sha3 = "0.10"
|
sha3 = "0.10"
|
||||||
sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "sqlite", "chrono"] }
|
sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "sqlite", "chrono"] }
|
||||||
toml = "0.5"
|
toml = "0.7"
|
||||||
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
|
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
|
||||||
tokio-stream = { version = "0.1", default-features = false, features = ["net"] }
|
tokio-stream = { version = "0.1", default-features = false, features = ["net"] }
|
||||||
uuid = { version = "1", features = ["serde", "v4"] }
|
uuid = { version = "1", features = ["serde", "v4"] }
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
alter table messages
|
||||||
|
add column ward int;
|
||||||
|
create index messages_ward_idx on messages (ward);
|
|
@ -1,9 +1,7 @@
|
||||||
#![feature(drain_filter)]
|
#![feature(drain_filter)]
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::Permissions;
|
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::os::unix::fs::PermissionsExt;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -11,7 +9,6 @@ use anyhow::{Context, Result};
|
||||||
use sqlx::{Executor, Pool, Sqlite};
|
use sqlx::{Executor, Pool, Sqlite};
|
||||||
use sqlx::migrate::Migrator;
|
use sqlx::migrate::Migrator;
|
||||||
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
|
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
|
||||||
use tokio::fs::File;
|
|
||||||
use tokio::net::{TcpListener, UnixListener};
|
use tokio::net::{TcpListener, UnixListener};
|
||||||
use tokio::runtime::Handle;
|
use tokio::runtime::Handle;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
@ -54,7 +51,7 @@ impl State {
|
||||||
let text = match tokio::fs::read_to_string(entry.path()).await {
|
let text = match tokio::fs::read_to_string(entry.path()).await {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("error reading pack: {:#?}", e);
|
eprintln!("error reading pack: {e:#?}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -119,10 +116,10 @@ async fn main() -> Result<()> {
|
||||||
|
|
||||||
let address = state.config.address.clone();
|
let address = state.config.address.clone();
|
||||||
let server = warp::serve(web::routes(state));
|
let server = warp::serve(web::routes(state));
|
||||||
println!("listening at {}", address);
|
println!("listening at {address}");
|
||||||
|
|
||||||
if address.starts_with("unix:") {
|
if let Some(path) = address.strip_prefix("unix:") {
|
||||||
let listener = UnixListener::bind(&address[5..])?;
|
let listener = UnixListener::bind(path)?;
|
||||||
let stream = UnixListenerStream::new(listener);
|
let stream = UnixListenerStream::new(listener);
|
||||||
server.run_incoming(stream).await;
|
server.run_incoming(stream).await;
|
||||||
} else {
|
} else {
|
||||||
|
@ -141,16 +138,13 @@ fn spawn_command_reader(state: Arc<State>, handle: Handle) {
|
||||||
while let Ok(size) = std::io::stdin().read_line(&mut line) {
|
while let Ok(size) = std::io::stdin().read_line(&mut line) {
|
||||||
let read = line[..size].trim();
|
let read = line[..size].trim();
|
||||||
|
|
||||||
match read {
|
if read == "reload packs" {
|
||||||
"reload packs" => {
|
let state = Arc::clone(&state);
|
||||||
let state = Arc::clone(&state);
|
handle.spawn(async move {
|
||||||
handle.spawn(async move {
|
if let Err(e) = state.update_packs().await {
|
||||||
if let Err(e) = state.update_packs().await {
|
eprintln!("failed to update packs: {e:#?}");
|
||||||
eprintln!("failed to update packs: {:#?}", e);
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
line.clear();
|
line.clear();
|
||||||
|
|
|
@ -22,6 +22,9 @@ pub struct Message {
|
||||||
|
|
||||||
#[serde(default = "glyph_default")]
|
#[serde(default = "glyph_default")]
|
||||||
pub glyph: i8,
|
pub glyph: i8,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub ward: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn glyph_default() -> i8 {
|
fn glyph_default() -> i8 {
|
||||||
|
@ -52,6 +55,7 @@ pub struct RetrievedMessage {
|
||||||
pub struct RetrievedMessageTerritory {
|
pub struct RetrievedMessageTerritory {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub territory: i64,
|
pub territory: i64,
|
||||||
|
pub ward: Option<i64>,
|
||||||
pub x: f64,
|
pub x: f64,
|
||||||
pub y: f64,
|
pub y: f64,
|
||||||
pub z: f64,
|
pub z: f64,
|
||||||
|
@ -69,6 +73,7 @@ pub struct RetrievedMessageTerritory {
|
||||||
pub struct OwnMessage {
|
pub struct OwnMessage {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub territory: i64,
|
pub territory: i64,
|
||||||
|
pub ward: Option<i64>,
|
||||||
pub x: f64,
|
pub x: f64,
|
||||||
pub y: f64,
|
pub y: f64,
|
||||||
pub z: f64,
|
pub z: f64,
|
||||||
|
|
|
@ -1,8 +1,54 @@
|
||||||
|
use base64::Engine;
|
||||||
|
use base64::prelude::BASE64_STANDARD;
|
||||||
use sha3::{Digest, Sha3_384};
|
use sha3::{Digest, Sha3_384};
|
||||||
|
|
||||||
|
// TerritoryIntendedUse = 13 or 14
|
||||||
|
pub const HOUSING_ZONES: &[u32] = &[
|
||||||
|
282,
|
||||||
|
283,
|
||||||
|
284,
|
||||||
|
339,
|
||||||
|
340,
|
||||||
|
341,
|
||||||
|
342,
|
||||||
|
343,
|
||||||
|
344,
|
||||||
|
345,
|
||||||
|
346,
|
||||||
|
347,
|
||||||
|
384,
|
||||||
|
385,
|
||||||
|
386,
|
||||||
|
423,
|
||||||
|
424,
|
||||||
|
425,
|
||||||
|
573,
|
||||||
|
574,
|
||||||
|
575,
|
||||||
|
608,
|
||||||
|
609,
|
||||||
|
610,
|
||||||
|
641,
|
||||||
|
649,
|
||||||
|
650,
|
||||||
|
651,
|
||||||
|
652,
|
||||||
|
653,
|
||||||
|
654,
|
||||||
|
655,
|
||||||
|
979,
|
||||||
|
980,
|
||||||
|
981,
|
||||||
|
982,
|
||||||
|
983,
|
||||||
|
984,
|
||||||
|
985,
|
||||||
|
999,
|
||||||
|
];
|
||||||
|
|
||||||
pub fn hash(input: &str) -> String {
|
pub fn hash(input: &str) -> String {
|
||||||
let mut hasher = Sha3_384::default();
|
let mut hasher = Sha3_384::default();
|
||||||
hasher.update(input.as_bytes());
|
hasher.update(input.as_bytes());
|
||||||
let result = hasher.finalize();
|
let result = hasher.finalize();
|
||||||
base64::encode(result)
|
BASE64_STANDARD.encode(result)
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,8 @@ pub enum WebError {
|
||||||
TooManyMessages,
|
TooManyMessages,
|
||||||
NoSuchMessage,
|
NoSuchMessage,
|
||||||
InvalidExtraCode,
|
InvalidExtraCode,
|
||||||
|
MissingWard,
|
||||||
|
UnnecessaryWard,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Reject for WebError {}
|
impl Reject for WebError {}
|
||||||
|
@ -92,22 +94,24 @@ async fn handle_rejection(err: Rejection) -> Result<impl Reply, Infallible> {
|
||||||
WebError::TooManyMessages => (StatusCode::BAD_REQUEST, "too_many_messages", "you have run out of messages - delete one and try again".into()),
|
WebError::TooManyMessages => (StatusCode::BAD_REQUEST, "too_many_messages", "you have run out of messages - delete one and try again".into()),
|
||||||
WebError::NoSuchMessage => (StatusCode::NOT_FOUND, "no_such_message", "no message with that id was found".into()),
|
WebError::NoSuchMessage => (StatusCode::NOT_FOUND, "no_such_message", "no message with that id was found".into()),
|
||||||
WebError::InvalidExtraCode => (StatusCode::BAD_REQUEST, "invalid_extra_code", "that extra code was not found".into()),
|
WebError::InvalidExtraCode => (StatusCode::BAD_REQUEST, "invalid_extra_code", "that extra code was not found".into()),
|
||||||
|
WebError::MissingWard => (StatusCode::BAD_REQUEST, "missing_ward", "a ward was not provided - try updating the plugin".into()),
|
||||||
|
WebError::UnnecessaryWard => (StatusCode::BAD_REQUEST, "unnecessar_ward", "a ward was provided but not necessary - try updating the plugin".into()),
|
||||||
}
|
}
|
||||||
} else if err.is_not_found() {
|
} else if err.is_not_found() {
|
||||||
(StatusCode::NOT_FOUND, "not_found", "route was unknown to the server".into())
|
(StatusCode::NOT_FOUND, "not_found", "route was unknown to the server".into())
|
||||||
} else if let Some(e) = err.find::<BodyDeserializeError>() {
|
} else if let Some(e) = err.find::<BodyDeserializeError>() {
|
||||||
(StatusCode::BAD_REQUEST, "invalid_body", format!("invalid body: {}", e))
|
(StatusCode::BAD_REQUEST, "invalid_body", format!("invalid body: {e}"))
|
||||||
} else if let Some(_) = err.find::<MethodNotAllowed>() {
|
} else if err.find::<MethodNotAllowed>().is_some() {
|
||||||
(StatusCode::METHOD_NOT_ALLOWED, "method_not_allowed", "that http method is not allowed on that route".into())
|
(StatusCode::METHOD_NOT_ALLOWED, "method_not_allowed", "that http method is not allowed on that route".into())
|
||||||
} else if let Some(AnyhowRejection(e)) = err.find::<AnyhowRejection>() {
|
} else if let Some(AnyhowRejection(e)) = err.find::<AnyhowRejection>() {
|
||||||
eprintln!("{:#?}", e);
|
eprintln!("{e:#?}");
|
||||||
(
|
(
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
"internal_error",
|
"internal_error",
|
||||||
"an internal logic error occured".into(),
|
"an internal logic error occured".into(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
eprintln!("{:#?}", err);
|
eprintln!("{err:#?}");
|
||||||
(
|
(
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
"internal_error",
|
"internal_error",
|
||||||
|
|
|
@ -4,12 +4,14 @@ use anyhow::Context;
|
||||||
use chrono::{Duration, Utc};
|
use chrono::{Duration, Utc};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
|
use serde::Deserialize;
|
||||||
use warp::{Filter, Rejection, Reply};
|
use warp::{Filter, Rejection, Reply};
|
||||||
use warp::filters::BoxedFilter;
|
use warp::filters::BoxedFilter;
|
||||||
|
|
||||||
use crate::message::RetrievedMessage;
|
use crate::message::RetrievedMessage;
|
||||||
use crate::State;
|
use crate::State;
|
||||||
use crate::web::AnyhowRejection;
|
use crate::util::HOUSING_ZONES;
|
||||||
|
use crate::web::{AnyhowRejection, WebError};
|
||||||
|
|
||||||
pub fn get_location(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
pub fn get_location(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||||
warp::get()
|
warp::get()
|
||||||
|
@ -17,11 +19,27 @@ pub fn get_location(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||||
.and(warp::path::param())
|
.and(warp::path::param())
|
||||||
.and(warp::path::end())
|
.and(warp::path::end())
|
||||||
.and(super::get_id(Arc::clone(&state)))
|
.and(super::get_id(Arc::clone(&state)))
|
||||||
.and_then(move |location: u32, (id, _)| logic(Arc::clone(&state), id, location))
|
.and(warp::query::<GetLocationQuery>())
|
||||||
|
.and_then(move |location: u32, (id, _), query| logic(Arc::clone(&state), id, location, query))
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn logic(state: Arc<State>, id: i64, location: u32) -> Result<impl Reply, Rejection> {
|
#[derive(Deserialize)]
|
||||||
|
pub struct GetLocationQuery {
|
||||||
|
#[serde(default)]
|
||||||
|
ward: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn logic(state: Arc<State>, id: i64, location: u32, query: GetLocationQuery) -> Result<impl Reply, Rejection> {
|
||||||
|
let housing = HOUSING_ZONES.contains(&location);
|
||||||
|
if housing && query.ward.is_none() {
|
||||||
|
return Err(warp::reject::custom(WebError::MissingWard));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !housing && query.ward.is_some() {
|
||||||
|
return Err(warp::reject::custom(WebError::UnnecessaryWard));
|
||||||
|
}
|
||||||
|
|
||||||
let location = location as i64;
|
let location = location as i64;
|
||||||
let mut messages = sqlx::query_as!(
|
let mut messages = sqlx::query_as!(
|
||||||
RetrievedMessage,
|
RetrievedMessage,
|
||||||
|
@ -44,10 +62,11 @@ async fn logic(state: Arc<State>, id: i64, location: u32) -> Result<impl Reply,
|
||||||
left join votes v on m.id = v.message
|
left join votes v on m.id = v.message
|
||||||
left join votes v2 on m.id = v2.message and v2.user = ?
|
left join votes v2 on m.id = v2.message and v2.user = ?
|
||||||
inner join users u on m.user = u.id
|
inner join users u on m.user = u.id
|
||||||
where m.territory = ?
|
where m.territory = ? and m.ward = ?
|
||||||
group by m.id"#,
|
group by m.id"#,
|
||||||
id,
|
id,
|
||||||
location,
|
location,
|
||||||
|
query.ward,
|
||||||
)
|
)
|
||||||
.fetch_all(&state.db)
|
.fetch_all(&state.db)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -27,6 +27,7 @@ async fn logic(state: Arc<State>, id: i64, message_id: Uuid) -> Result<impl Repl
|
||||||
r#"
|
r#"
|
||||||
select m.id,
|
select m.id,
|
||||||
m.territory,
|
m.territory,
|
||||||
|
m.ward,
|
||||||
m.x,
|
m.x,
|
||||||
m.y,
|
m.y,
|
||||||
m.z,
|
m.z,
|
||||||
|
|
|
@ -31,6 +31,7 @@ async fn logic(state: Arc<State>, id: i64, extra: i64, mut query: HashMap<String
|
||||||
r#"
|
r#"
|
||||||
select m.id,
|
select m.id,
|
||||||
m.territory,
|
m.territory,
|
||||||
|
m.ward,
|
||||||
m.x,
|
m.x,
|
||||||
m.y,
|
m.y,
|
||||||
m.z,
|
m.z,
|
||||||
|
|
|
@ -7,6 +7,7 @@ use warp::filters::BoxedFilter;
|
||||||
|
|
||||||
use crate::message::Message;
|
use crate::message::Message;
|
||||||
use crate::State;
|
use crate::State;
|
||||||
|
use crate::util::HOUSING_ZONES;
|
||||||
use crate::web::{AnyhowRejection, WebError};
|
use crate::web::{AnyhowRejection, WebError};
|
||||||
|
|
||||||
pub fn write(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
pub fn write(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||||
|
@ -21,6 +22,15 @@ pub fn write(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn logic(state: Arc<State>, id: i64, extra: i64, message: Message) -> Result<impl Reply, Rejection> {
|
async fn logic(state: Arc<State>, id: i64, extra: i64, message: Message) -> Result<impl Reply, Rejection> {
|
||||||
|
let housing = HOUSING_ZONES.contains(&message.territory);
|
||||||
|
if housing && message.ward.is_none() {
|
||||||
|
return Err(warp::reject::custom(WebError::MissingWard));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !housing && message.ward.is_some() {
|
||||||
|
return Err(warp::reject::custom(WebError::UnnecessaryWard));
|
||||||
|
}
|
||||||
|
|
||||||
let text = {
|
let text = {
|
||||||
let packs = state.packs.read().await;
|
let packs = state.packs.read().await;
|
||||||
let pack = packs.get(&message.pack_id)
|
let pack = packs.get(&message.pack_id)
|
||||||
|
@ -57,10 +67,11 @@ async fn logic(state: Arc<State>, id: i64, extra: i64, message: Message) -> Resu
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
// language=sqlite
|
// language=sqlite
|
||||||
"insert into messages (id, user, territory, x, y, z, yaw, message, glyph) values (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
"insert into messages (id, user, territory, ward, x, y, z, yaw, message, glyph) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
message_id,
|
message_id,
|
||||||
id,
|
id,
|
||||||
territory,
|
territory,
|
||||||
|
message.ward,
|
||||||
message.x,
|
message.x,
|
||||||
message.y,
|
message.y,
|
||||||
message.z,
|
message.z,
|
||||||
|
|
Loading…
Reference in New Issue