stuff
This commit is contained in:
parent
7b512e78d5
commit
305b2bed4a
|
@ -1,4 +1,6 @@
|
||||||
using Dalamud.Game.Command;
|
using Dalamud.Game.Command;
|
||||||
|
using Dalamud.Utility;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
|
||||||
namespace OrangeGuidanceTomestone;
|
namespace OrangeGuidanceTomestone;
|
||||||
|
|
||||||
|
@ -19,16 +21,47 @@ internal class Commands : IDisposable {
|
||||||
|
|
||||||
private void OnCommand(string command, string arguments) {
|
private void OnCommand(string command, string arguments) {
|
||||||
switch (arguments) {
|
switch (arguments) {
|
||||||
case "ban":
|
case "ban": {
|
||||||
|
var name = this.Plugin.DataManager.GetExcelSheet<TerritoryType>()?.GetRow(this.Plugin.ClientState.TerritoryType)
|
||||||
|
?.PlaceName
|
||||||
|
.Value
|
||||||
|
?.Name
|
||||||
|
?.ToDalamudString()
|
||||||
|
.TextValue;
|
||||||
|
|
||||||
|
if (this.Plugin.Config.BannedTerritories.Contains(this.Plugin.ClientState.TerritoryType)) {
|
||||||
|
this.Plugin.ChatGui.Print($"{name} is already on the ban list.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.Plugin.Config.BannedTerritories.Add(this.Plugin.ClientState.TerritoryType);
|
this.Plugin.Config.BannedTerritories.Add(this.Plugin.ClientState.TerritoryType);
|
||||||
this.Plugin.SaveConfig();
|
this.Plugin.SaveConfig();
|
||||||
|
this.Plugin.ChatGui.Print($"Added {name} to the ban list.");
|
||||||
|
|
||||||
this.Plugin.Messages.RemoveVfx();
|
this.Plugin.Messages.RemoveVfx();
|
||||||
|
this.Plugin.Messages.Clear();
|
||||||
break;
|
break;
|
||||||
case "unban":
|
}
|
||||||
|
case "unban": {
|
||||||
|
var name = this.Plugin.DataManager.GetExcelSheet<TerritoryType>()?.GetRow(this.Plugin.ClientState.TerritoryType)
|
||||||
|
?.PlaceName
|
||||||
|
.Value
|
||||||
|
?.Name
|
||||||
|
?.ToDalamudString()
|
||||||
|
.TextValue;
|
||||||
|
|
||||||
|
if (!this.Plugin.Config.BannedTerritories.Contains(this.Plugin.ClientState.TerritoryType)) {
|
||||||
|
this.Plugin.ChatGui.Print($"{name} is not on the ban list.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.Plugin.Config.BannedTerritories.Remove(this.Plugin.ClientState.TerritoryType);
|
this.Plugin.Config.BannedTerritories.Remove(this.Plugin.ClientState.TerritoryType);
|
||||||
this.Plugin.SaveConfig();
|
this.Plugin.SaveConfig();
|
||||||
|
this.Plugin.ChatGui.Print($"Removed {name} from the ban list.");
|
||||||
|
|
||||||
this.Plugin.Messages.SpawnVfx();
|
this.Plugin.Messages.SpawnVfx();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case "refresh":
|
case "refresh":
|
||||||
this.Plugin.Messages.SpawnVfx();
|
this.Plugin.Messages.SpawnVfx();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -8,4 +8,7 @@ public class Configuration : IPluginConfiguration {
|
||||||
|
|
||||||
public string ApiKey { get; set; } = string.Empty;
|
public string ApiKey { get; set; } = string.Empty;
|
||||||
public HashSet<uint> BannedTerritories { get; set; } = new();
|
public HashSet<uint> BannedTerritories { get; set; } = new();
|
||||||
|
public bool DisableTrials = true;
|
||||||
|
public bool DisableDeepDungeon = true;
|
||||||
|
public bool RemoveGlow = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Dalamud.Game;
|
using Dalamud.Game;
|
||||||
using Dalamud.Logging;
|
using Dalamud.Logging;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using OrangeGuidanceTomestone.Helpers;
|
using OrangeGuidanceTomestone.Helpers;
|
||||||
|
|
||||||
|
@ -15,9 +16,22 @@ internal class Messages : IDisposable {
|
||||||
private Dictionary<Guid, Message> Current { get; } = new();
|
private Dictionary<Guid, Message> Current { get; } = new();
|
||||||
private Queue<Message> SpawnQueue { get; } = new();
|
private Queue<Message> SpawnQueue { get; } = new();
|
||||||
|
|
||||||
|
private HashSet<uint> Trials { get; } = new();
|
||||||
|
private HashSet<uint> DeepDungeons { get; } = new();
|
||||||
|
|
||||||
internal Messages(Plugin plugin) {
|
internal Messages(Plugin plugin) {
|
||||||
this.Plugin = plugin;
|
this.Plugin = plugin;
|
||||||
|
|
||||||
|
foreach (var cfc in this.Plugin.DataManager.GetExcelSheet<ContentFinderCondition>()!) {
|
||||||
|
if (cfc.ContentType.Row == 4) {
|
||||||
|
this.Trials.Add(cfc.TerritoryType.Row);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfc.ContentType.Row == 21) {
|
||||||
|
this.DeepDungeons.Add(cfc.TerritoryType.Row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.Plugin.Config.ApiKey != string.Empty) {
|
if (this.Plugin.Config.ApiKey != string.Empty) {
|
||||||
this.SpawnVfx();
|
this.SpawnVfx();
|
||||||
}
|
}
|
||||||
|
@ -34,7 +48,7 @@ internal class Messages : IDisposable {
|
||||||
this.Plugin.ClientState.Login -= this.SpawnVfx;
|
this.Plugin.ClientState.Login -= this.SpawnVfx;
|
||||||
this.Plugin.Framework.Update -= this.HandleSpawnQueue;
|
this.Plugin.Framework.Update -= this.HandleSpawnQueue;
|
||||||
|
|
||||||
this.RemoveVfx(null, null);
|
this.RemoveVfx();
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void HandleSpawnQueue(Framework framework) {
|
private unsafe void HandleSpawnQueue(Framework framework) {
|
||||||
|
@ -42,10 +56,10 @@ internal class Messages : IDisposable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginLog.Log($"spawning vfx for {message.Id}");
|
PluginLog.Debug($"spawning vfx for {message.Id}");
|
||||||
var rotation = Quaternion.CreateFromYawPitchRoll(message.Yaw, 0, 0);
|
var rotation = Quaternion.CreateFromYawPitchRoll(message.Yaw, 0, 0);
|
||||||
if (this.Plugin.Vfx.SpawnStatic(message.Id, VfxPath, message.Position, rotation) == null) {
|
if (this.Plugin.Vfx.SpawnStatic(message.Id, VfxPath, message.Position, rotation) == null) {
|
||||||
PluginLog.Log("trying again");
|
PluginLog.Debug("trying again");
|
||||||
this.SpawnQueue.Enqueue(message);
|
this.SpawnQueue.Enqueue(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +78,14 @@ internal class Messages : IDisposable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.Plugin.Config.DisableTrials && this.Trials.Contains(territory)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.Plugin.Config.DisableDeepDungeon && this.DeepDungeons.Contains(territory)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.RemoveVfx(null, null);
|
this.RemoveVfx(null, null);
|
||||||
|
|
||||||
Task.Run(async () => {
|
Task.Run(async () => {
|
||||||
|
@ -95,6 +117,12 @@ internal class Messages : IDisposable {
|
||||||
this.Plugin.Vfx.RemoveAll();
|
this.Plugin.Vfx.RemoveAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void Clear() {
|
||||||
|
this.CurrentMutex.Wait();
|
||||||
|
this.Current.Clear();
|
||||||
|
this.CurrentMutex.Release();
|
||||||
|
}
|
||||||
|
|
||||||
internal IEnumerable<Message> Nearby() {
|
internal IEnumerable<Message> Nearby() {
|
||||||
if (this.Plugin.ClientState.LocalPlayer is not { } player) {
|
if (this.Plugin.ClientState.LocalPlayer is not { } player) {
|
||||||
return Array.Empty<Message>();
|
return Array.Empty<Message>();
|
||||||
|
|
|
@ -58,15 +58,15 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DalamudPackager" Version="2.1.8"/>
|
<PackageReference Include="DalamudPackager" Version="2.1.8" />
|
||||||
<PackageReference Include="Fody" Version="6.6.3" PrivateAssets="all"/>
|
<PackageReference Include="Fody" Version="6.6.3" PrivateAssets="all" />
|
||||||
<PackageReference Include="Resourcer.Fody" Version="1.8.0" PrivateAssets="all"/>
|
<PackageReference Include="Resourcer.Fody" Version="1.8.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="YamlDotNet" Version="12.0.0"/>
|
<PackageReference Include="YamlDotNet" Version="12.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="../server/packs/*.yaml" LinkBase="packs"/>
|
<EmbeddedResource Include="../server/packs/*.yaml" LinkBase="packs" />
|
||||||
<EmbeddedResource Remove="../server/packs/*_old*.yaml"/>
|
<EmbeddedResource Remove="../server/packs/*_old*.yaml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -3,6 +3,7 @@ using Dalamud.Game;
|
||||||
using Dalamud.Game.ClientState;
|
using Dalamud.Game.ClientState;
|
||||||
using Dalamud.Game.ClientState.Conditions;
|
using Dalamud.Game.ClientState.Conditions;
|
||||||
using Dalamud.Game.Command;
|
using Dalamud.Game.Command;
|
||||||
|
using Dalamud.Game.Gui;
|
||||||
using Dalamud.IoC;
|
using Dalamud.IoC;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
|
|
||||||
|
@ -14,6 +15,9 @@ public class Plugin : IDalamudPlugin {
|
||||||
[PluginService]
|
[PluginService]
|
||||||
internal DalamudPluginInterface Interface { get; init; }
|
internal DalamudPluginInterface Interface { get; init; }
|
||||||
|
|
||||||
|
[PluginService]
|
||||||
|
internal ChatGui ChatGui { get; init; }
|
||||||
|
|
||||||
[PluginService]
|
[PluginService]
|
||||||
internal ClientState ClientState { get; init; }
|
internal ClientState ClientState { get; init; }
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ internal class MainWindow {
|
||||||
this.Tabs = new List<ITab> {
|
this.Tabs = new List<ITab> {
|
||||||
new Write(this.Plugin),
|
new Write(this.Plugin),
|
||||||
new MessageList(this.Plugin),
|
new MessageList(this.Plugin),
|
||||||
|
new Settings(this.Plugin),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
31
client/Ui/MainWindowTabs/Settings.cs
Normal file
31
client/Ui/MainWindowTabs/Settings.cs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
using ImGuiNET;
|
||||||
|
|
||||||
|
namespace OrangeGuidanceTomestone.Ui.MainWindowTabs;
|
||||||
|
|
||||||
|
internal class Settings : ITab {
|
||||||
|
public string Name => "Settings";
|
||||||
|
|
||||||
|
private Plugin Plugin { get; }
|
||||||
|
|
||||||
|
internal Settings(Plugin plugin) {
|
||||||
|
this.Plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw() {
|
||||||
|
var anyChanged = false;
|
||||||
|
var vfx = false;
|
||||||
|
|
||||||
|
anyChanged |= vfx |= ImGui.Checkbox("Disable in trials", ref this.Plugin.Config.DisableTrials);
|
||||||
|
anyChanged |= vfx |= ImGui.Checkbox("Disable in Deep Dungeons", ref this.Plugin.Config.DisableDeepDungeon);
|
||||||
|
anyChanged |= vfx |= ImGui.Checkbox("Remove glow effect from signs", ref this.Plugin.Config.RemoveGlow);
|
||||||
|
|
||||||
|
if (anyChanged) {
|
||||||
|
this.Plugin.SaveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vfx) {
|
||||||
|
this.Plugin.Messages.RemoveVfx();
|
||||||
|
this.Plugin.Messages.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
server/Cargo.lock
generated
1
server/Cargo.lock
generated
|
@ -1035,6 +1035,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"rand",
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
base64 = "0.13"
|
base64 = "0.13"
|
||||||
|
bytes = "1"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
|
4
server/migrations/4_add_extra_tokens.sql
Normal file
4
server/migrations/4_add_extra_tokens.sql
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
create table extra_tokens (
|
||||||
|
id text not null primary key,
|
||||||
|
extra integer not null
|
||||||
|
);
|
|
@ -288,6 +288,7 @@ words:
|
||||||
- core
|
- core
|
||||||
- fingers
|
- fingers
|
||||||
- horns
|
- horns
|
||||||
|
- feet
|
||||||
|
|
||||||
- name: Affinities
|
- name: Affinities
|
||||||
words:
|
words:
|
||||||
|
|
|
@ -48,4 +48,6 @@ pub struct RetrievedMessageTerritory {
|
||||||
pub positive_votes: i32,
|
pub positive_votes: i32,
|
||||||
pub negative_votes: i32,
|
pub negative_votes: i32,
|
||||||
pub user_vote: i64,
|
pub user_vote: i64,
|
||||||
|
#[serde(skip)]
|
||||||
|
pub created: NaiveDateTime,
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ mod get_location;
|
||||||
mod vote;
|
mod vote;
|
||||||
mod get_mine;
|
mod get_mine;
|
||||||
mod get_message;
|
mod get_message;
|
||||||
|
mod claim;
|
||||||
|
|
||||||
pub fn routes(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
pub fn routes(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||||
register::register(Arc::clone(&state))
|
register::register(Arc::clone(&state))
|
||||||
|
@ -26,6 +27,7 @@ pub fn routes(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||||
.or(get_message::get_message(Arc::clone(&state)))
|
.or(get_message::get_message(Arc::clone(&state)))
|
||||||
.or(get_location::get_location(Arc::clone(&state)))
|
.or(get_location::get_location(Arc::clone(&state)))
|
||||||
.or(get_mine::get_mine(Arc::clone(&state)))
|
.or(get_mine::get_mine(Arc::clone(&state)))
|
||||||
|
.or(claim::claim(Arc::clone(&state)))
|
||||||
.recover(handle_rejection)
|
.recover(handle_rejection)
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
@ -62,6 +64,7 @@ pub enum WebError {
|
||||||
InvalidIndex,
|
InvalidIndex,
|
||||||
TooManyMessages,
|
TooManyMessages,
|
||||||
NoSuchMessage,
|
NoSuchMessage,
|
||||||
|
InvalidExtraCode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Reject for WebError {}
|
impl Reject for WebError {}
|
||||||
|
@ -72,21 +75,41 @@ pub struct AnyhowRejection(anyhow::Error);
|
||||||
impl Reject for AnyhowRejection {}
|
impl Reject for AnyhowRejection {}
|
||||||
|
|
||||||
async fn handle_rejection(err: Rejection) -> Result<impl Reply, Infallible> {
|
async fn handle_rejection(err: Rejection) -> Result<impl Reply, Infallible> {
|
||||||
let status = if let Some(AnyhowRejection(e)) = err.find::<AnyhowRejection>() {
|
let (status, name, desc) = if let Some(AnyhowRejection(e)) = err.find::<AnyhowRejection>() {
|
||||||
eprintln!("{:#?}", e);
|
eprintln!("{:#?}", e);
|
||||||
StatusCode::INTERNAL_SERVER_ERROR
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
"internal_error",
|
||||||
|
"an internal logic error occured",
|
||||||
|
)
|
||||||
} else if let Some(e) = err.find::<WebError>() {
|
} else if let Some(e) = err.find::<WebError>() {
|
||||||
match e {
|
match e {
|
||||||
WebError::InvalidAuthToken => StatusCode::BAD_REQUEST,
|
WebError::InvalidAuthToken => (StatusCode::BAD_REQUEST, "invalid_auth_token", "the auth token was not valid"),
|
||||||
WebError::InvalidPackId => StatusCode::NOT_FOUND,
|
WebError::InvalidPackId => (StatusCode::NOT_FOUND, "invalid_pack_id", "the server does not have a pack registered with that id"),
|
||||||
WebError::InvalidIndex => StatusCode::NOT_FOUND,
|
WebError::InvalidIndex => (StatusCode::NOT_FOUND, "invalid_index", "one of the provided indices was out of range"),
|
||||||
WebError::TooManyMessages => StatusCode::BAD_REQUEST,
|
WebError::TooManyMessages => (StatusCode::BAD_REQUEST, "too_many_messages", "you have run out of messages - delete one and try again"),
|
||||||
WebError::NoSuchMessage => StatusCode::NOT_FOUND,
|
WebError::NoSuchMessage => (StatusCode::NOT_FOUND, "no_such_message", "no message with that id was found"),
|
||||||
|
WebError::InvalidExtraCode => (StatusCode::BAD_REQUEST, "invalid_extra_code", "that extra code was not found"),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
eprintln!("{:#?}", err);
|
eprintln!("{:#?}", err);
|
||||||
StatusCode::INTERNAL_SERVER_ERROR
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
"internal_error",
|
||||||
|
"an unhandled error was encountered",
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(warp::reply::with_status(warp::reply(), status))
|
#[derive(serde::Serialize)]
|
||||||
|
struct ErrorMessage {
|
||||||
|
code: &'static str,
|
||||||
|
message: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
let message = ErrorMessage {
|
||||||
|
code: name,
|
||||||
|
message: desc,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(warp::reply::with_status(warp::reply::json(&message), status))
|
||||||
}
|
}
|
||||||
|
|
59
server/src/web/claim.rs
Normal file
59
server/src/web/claim.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use bytes::Bytes;
|
||||||
|
use uuid::Uuid;
|
||||||
|
use warp::{Filter, Rejection, Reply};
|
||||||
|
use warp::filters::BoxedFilter;
|
||||||
|
|
||||||
|
use crate::message::RetrievedMessageTerritory;
|
||||||
|
use crate::State;
|
||||||
|
use crate::web::{AnyhowRejection, WebError};
|
||||||
|
|
||||||
|
pub fn claim(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||||
|
warp::post()
|
||||||
|
.and(warp::path("claim"))
|
||||||
|
.and(warp::path::end())
|
||||||
|
.and(super::get_id(Arc::clone(&state)))
|
||||||
|
.and(warp::body::content_length_limit(256))
|
||||||
|
.and(warp::body::bytes())
|
||||||
|
.and_then(move |(id, _), code: Bytes| logic(Arc::clone(&state), id, code))
|
||||||
|
.boxed()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn logic(state: Arc<State>, id: i64, bytes: Bytes) -> Result<impl Reply, Rejection> {
|
||||||
|
let bytes: Vec<u8> = bytes.into_iter().collect();
|
||||||
|
let code = String::from_utf8(bytes)
|
||||||
|
.context("invalid utf8 for extra code")
|
||||||
|
.map_err(AnyhowRejection)
|
||||||
|
.map_err(warp::reject::custom)?;
|
||||||
|
|
||||||
|
let code = sqlx::query!(
|
||||||
|
// language=sqlite
|
||||||
|
r#"delete from extra_tokens where id = ? returning extra as "extra!: i64""#,
|
||||||
|
code,
|
||||||
|
)
|
||||||
|
.fetch_optional(&state.db)
|
||||||
|
.await
|
||||||
|
.context("could not get code from database")
|
||||||
|
.map_err(AnyhowRejection)
|
||||||
|
.map_err(warp::reject::custom)?;
|
||||||
|
|
||||||
|
if let Some(code) = code {
|
||||||
|
sqlx::query!(
|
||||||
|
// language=sqlite
|
||||||
|
"update users set extra = ? where id = ?",
|
||||||
|
code.extra,
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
.execute(&state.db)
|
||||||
|
.await
|
||||||
|
.context("could not update user")
|
||||||
|
.map_err(AnyhowRejection)
|
||||||
|
.map_err(warp::reject::custom)?;
|
||||||
|
|
||||||
|
return Ok(code.extra.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(warp::reject::custom(WebError::InvalidExtraCode))
|
||||||
|
}
|
|
@ -34,7 +34,8 @@ async fn logic(state: Arc<State>, id: i64, message_id: Uuid) -> Result<impl Repl
|
||||||
m.message,
|
m.message,
|
||||||
coalesce(sum(v.vote between 0 and 1), 0) as positive_votes,
|
coalesce(sum(v.vote between 0 and 1), 0) as positive_votes,
|
||||||
coalesce(sum(v.vote between -1 and 0), 0) as negative_votes,
|
coalesce(sum(v.vote between -1 and 0), 0) as negative_votes,
|
||||||
v2.vote as user_vote
|
v2.vote as user_vote,
|
||||||
|
m.created
|
||||||
from messages m
|
from messages m
|
||||||
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 = ?
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
@ -13,12 +14,18 @@ pub fn get_mine(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||||
.and(warp::path("messages"))
|
.and(warp::path("messages"))
|
||||||
.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 |(id, _)| logic(Arc::clone(&state), id))
|
.and(warp::query())
|
||||||
|
.and_then(move |(id, extra), query: HashMap<String, String>| logic(Arc::clone(&state), id, extra, query))
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn logic(state: Arc<State>, id: i64) -> Result<impl Reply, Rejection> {
|
async fn logic(state: Arc<State>, id: i64, extra: i64, mut query: HashMap<String, String>) -> Result<impl Reply, Rejection> {
|
||||||
let messages = sqlx::query_as!(
|
let version = query.remove("v")
|
||||||
|
.unwrap_or_else(|| "1".to_string())
|
||||||
|
.parse::<u8>()
|
||||||
|
.unwrap_or(1);
|
||||||
|
|
||||||
|
let mut messages = sqlx::query_as!(
|
||||||
RetrievedMessageTerritory,
|
RetrievedMessageTerritory,
|
||||||
// language=sqlite
|
// language=sqlite
|
||||||
r#"
|
r#"
|
||||||
|
@ -31,7 +38,8 @@ async fn logic(state: Arc<State>, id: i64) -> Result<impl Reply, Rejection> {
|
||||||
m.message,
|
m.message,
|
||||||
coalesce(sum(v.vote between 0 and 1), 0) as positive_votes,
|
coalesce(sum(v.vote between 0 and 1), 0) as positive_votes,
|
||||||
coalesce(sum(v.vote between -1 and 0), 0) as negative_votes,
|
coalesce(sum(v.vote between -1 and 0), 0) as negative_votes,
|
||||||
v2.vote as user_vote
|
v2.vote as user_vote,
|
||||||
|
m.created
|
||||||
from messages m
|
from messages m
|
||||||
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 = ?
|
||||||
|
@ -45,5 +53,24 @@ async fn logic(state: Arc<State>, id: i64) -> Result<impl Reply, Rejection> {
|
||||||
.context("could not get messages from database")
|
.context("could not get messages from database")
|
||||||
.map_err(AnyhowRejection)
|
.map_err(AnyhowRejection)
|
||||||
.map_err(warp::reject::custom)?;
|
.map_err(warp::reject::custom)?;
|
||||||
Ok(warp::reply::json(&messages))
|
|
||||||
|
messages.sort_by_key(|msg| msg.created);
|
||||||
|
messages.reverse();
|
||||||
|
|
||||||
|
if version == 1 {
|
||||||
|
return Ok(warp::reply::json(&messages));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize)]
|
||||||
|
struct Mine {
|
||||||
|
messages: Vec<RetrievedMessageTerritory>,
|
||||||
|
extra: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mine = Mine {
|
||||||
|
messages,
|
||||||
|
extra,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(warp::reply::json(&mine))
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ pub fn vote(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||||
.and(warp::path("votes"))
|
.and(warp::path("votes"))
|
||||||
.and(warp::path::end())
|
.and(warp::path::end())
|
||||||
.and(super::get_id(Arc::clone(&state)))
|
.and(super::get_id(Arc::clone(&state)))
|
||||||
|
.and(warp::body::content_length_limit(3))
|
||||||
.and(warp::body::json())
|
.and(warp::body::json())
|
||||||
.and_then(move |message_id: Uuid, (id, _), vote: i8| logic(Arc::clone(&state), id, message_id, vote))
|
.and_then(move |message_id: Uuid, (id, _), vote: i8| logic(Arc::clone(&state), id, message_id, vote))
|
||||||
.boxed()
|
.boxed()
|
||||||
|
|
|
@ -14,6 +14,7 @@ pub fn write(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||||
.and(warp::path("messages"))
|
.and(warp::path("messages"))
|
||||||
.and(warp::path::end())
|
.and(warp::path::end())
|
||||||
.and(super::get_id(Arc::clone(&state)))
|
.and(super::get_id(Arc::clone(&state)))
|
||||||
|
.and(warp::body::content_length_limit(1024))
|
||||||
.and(warp::body::json())
|
.and(warp::body::json())
|
||||||
.and_then(move |(id, extra), message: Message| logic(Arc::clone(&state), id, extra, message))
|
.and_then(move |(id, extra), message: Message| logic(Arc::clone(&state), id, extra, message))
|
||||||
.boxed()
|
.boxed()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user