asadasd
This commit is contained in:
parent
6d6fc62af7
commit
2df42dfe17
|
@ -17,6 +17,7 @@ internal class Message {
|
||||||
|
|
||||||
public int PositiveVotes { get; init; }
|
public int PositiveVotes { get; init; }
|
||||||
public int NegativeVotes { get; init; }
|
public int NegativeVotes { get; init; }
|
||||||
|
public int UserVote { get; set; }
|
||||||
|
|
||||||
internal Vector3 Position => new(this.X, this.Y, this.Z);
|
internal Vector3 Position => new(this.X, this.Y, this.Z);
|
||||||
}
|
}
|
||||||
|
@ -35,6 +36,7 @@ internal class MessageWithTerritory {
|
||||||
|
|
||||||
public int PositiveVotes { get; init; }
|
public int PositiveVotes { get; init; }
|
||||||
public int NegativeVotes { get; init; }
|
public int NegativeVotes { get; init; }
|
||||||
|
public int UserVote { get; set; }
|
||||||
|
|
||||||
internal Vector3 Position => new(this.X, this.Y, this.Z);
|
internal Vector3 Position => new(this.X, this.Y, this.Z);
|
||||||
|
|
||||||
|
@ -48,6 +50,7 @@ internal class MessageWithTerritory {
|
||||||
Text = message.Text,
|
Text = message.Text,
|
||||||
PositiveVotes = message.PositiveVotes,
|
PositiveVotes = message.PositiveVotes,
|
||||||
NegativeVotes = message.NegativeVotes,
|
NegativeVotes = message.NegativeVotes,
|
||||||
|
UserVote = message.UserVote,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: Orange Guidance Tomestone
|
name: Orange Guidance Tomestone
|
||||||
author: ascclemes
|
author: ascclemes
|
||||||
punchline: Try finger, but hole
|
punchline: Leave messages like in Souls games. Great chest ahead.
|
||||||
description: |-
|
description: |-
|
||||||
Dark Souls-like messaging system.
|
Dark Souls-like messaging system.
|
||||||
repo_url: https://git.anna.lgbt/ascclemens/OrangeGuidanceTomestone
|
repo_url: https://git.anna.lgbt/ascclemens/OrangeGuidanceTomestone
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Dalamud.Game;
|
using Dalamud.Data;
|
||||||
|
using Dalamud.Game;
|
||||||
using Dalamud.Game.ClientState;
|
using Dalamud.Game.ClientState;
|
||||||
using Dalamud.Game.Command;
|
using Dalamud.Game.Command;
|
||||||
using Dalamud.IoC;
|
using Dalamud.IoC;
|
||||||
|
@ -18,6 +19,9 @@ public class Plugin : IDalamudPlugin {
|
||||||
[PluginService]
|
[PluginService]
|
||||||
internal CommandManager CommandManager { get; init; }
|
internal CommandManager CommandManager { get; init; }
|
||||||
|
|
||||||
|
[PluginService]
|
||||||
|
internal DataManager DataManager { get; init; }
|
||||||
|
|
||||||
[PluginService]
|
[PluginService]
|
||||||
internal Framework Framework { get; init; }
|
internal Framework Framework { get; init; }
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
using Dalamud.Utility;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using OrangeGuidanceTomestone.Helpers;
|
using OrangeGuidanceTomestone.Helpers;
|
||||||
|
|
||||||
|
@ -23,10 +25,14 @@ internal class MessageList : ITab {
|
||||||
this.MessagesMutex.Wait();
|
this.MessagesMutex.Wait();
|
||||||
|
|
||||||
foreach (var message in this.Messages) {
|
foreach (var message in this.Messages) {
|
||||||
|
var territory = this.Plugin.DataManager.GetExcelSheet<TerritoryType>()?.GetRow(message.Territory);
|
||||||
|
var territoryName = territory?.PlaceName.Value?.Name?.ToDalamudString().TextValue ?? "???";
|
||||||
|
|
||||||
ImGui.TextUnformatted(message.Text);
|
ImGui.TextUnformatted(message.Text);
|
||||||
ImGui.TreePush();
|
ImGui.TreePush();
|
||||||
ImGui.TextUnformatted($"Likes: {message.PositiveVotes}");
|
ImGui.TextUnformatted($"Location: {territoryName}");
|
||||||
ImGui.TextUnformatted($"Dislikes: {message.NegativeVotes}");
|
var appraisals = Math.Max(0, message.PositiveVotes - message.NegativeVotes);
|
||||||
|
ImGui.TextUnformatted($"Appraisals: {appraisals} ({message.PositiveVotes} - {message.NegativeVotes}");
|
||||||
if (ImGui.Button($"Delete##{message.Id}")) {
|
if (ImGui.Button($"Delete##{message.Id}")) {
|
||||||
this.Delete(message.Id);
|
this.Delete(message.Id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,32 +77,50 @@ internal class Viewer {
|
||||||
ImGui.TextUnformatted(message.Text);
|
ImGui.TextUnformatted(message.Text);
|
||||||
ImGui.PopTextWrapPos();
|
ImGui.PopTextWrapPos();
|
||||||
|
|
||||||
ImGui.TextUnformatted($"Appraisals: {message.PositiveVotes - message.NegativeVotes}");
|
var appraisals = Math.Max(0, message.PositiveVotes - message.NegativeVotes);
|
||||||
|
ImGui.TextUnformatted($"Appraisals: {appraisals:N0}");
|
||||||
|
|
||||||
if (ImGui.Button("Like")) {
|
void Vote(int way) {
|
||||||
Task.Run(async () => {
|
Task.Run(async () => {
|
||||||
await ServerHelper.SendRequest(
|
var resp = await ServerHelper.SendRequest(
|
||||||
this.Plugin.Config.ApiKey,
|
this.Plugin.Config.ApiKey,
|
||||||
HttpMethod.Patch,
|
HttpMethod.Patch,
|
||||||
$"/messages/{message.Id}/votes",
|
$"/messages/{message.Id}/votes",
|
||||||
"application/json",
|
"application/json",
|
||||||
new StringContent("1")
|
new StringContent(way.ToString())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (resp.IsSuccessStatusCode) {
|
||||||
|
message.UserVote = way;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var vote = message.UserVote;
|
||||||
|
if (vote == 1) {
|
||||||
|
ImGui.BeginDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.Button("Like")) {
|
||||||
|
Vote(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vote == 1) {
|
||||||
|
ImGui.EndDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
if (vote == -1) {
|
||||||
|
ImGui.BeginDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
if (ImGui.Button("Dislike")) {
|
if (ImGui.Button("Dislike")) {
|
||||||
Task.Run(async () => {
|
Vote(-1);
|
||||||
await ServerHelper.SendRequest(
|
}
|
||||||
this.Plugin.Config.ApiKey,
|
|
||||||
HttpMethod.Patch,
|
if (vote == -1) {
|
||||||
$"/messages/{message.Id}/votes",
|
ImGui.EndDisabled();
|
||||||
"application/json",
|
|
||||||
new StringContent("-1")
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,17 +18,6 @@ pub struct Message {
|
||||||
pub word_2_word: Option<usize>,
|
pub word_2_word: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct VoteMessage {
|
|
||||||
pub post_id: Uuid,
|
|
||||||
pub vote: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct DeleteMessage {
|
|
||||||
pub post_id: Uuid,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct RetrievedMessage {
|
pub struct RetrievedMessage {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
@ -38,6 +27,7 @@ pub struct RetrievedMessage {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
pub positive_votes: i32,
|
pub positive_votes: i32,
|
||||||
pub negative_votes: i32,
|
pub negative_votes: i32,
|
||||||
|
pub user_vote: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
|
@ -50,4 +40,5 @@ pub struct RetrievedMessageTerritory {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
pub positive_votes: i32,
|
pub positive_votes: i32,
|
||||||
pub negative_votes: i32,
|
pub negative_votes: i32,
|
||||||
|
pub user_vote: i64,
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ mod erase;
|
||||||
mod get_location;
|
mod get_location;
|
||||||
mod vote;
|
mod vote;
|
||||||
mod get_mine;
|
mod get_mine;
|
||||||
|
mod get_message;
|
||||||
|
|
||||||
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))
|
||||||
|
@ -22,6 +23,7 @@ pub fn routes(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||||
.or(write::write(Arc::clone(&state)))
|
.or(write::write(Arc::clone(&state)))
|
||||||
.or(erase::erase(Arc::clone(&state)))
|
.or(erase::erase(Arc::clone(&state)))
|
||||||
.or(vote::vote(Arc::clone(&state)))
|
.or(vote::vote(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)))
|
||||||
.recover(handle_rejection)
|
.recover(handle_rejection)
|
||||||
|
@ -59,6 +61,7 @@ pub enum WebError {
|
||||||
InvalidPackId,
|
InvalidPackId,
|
||||||
InvalidIndex,
|
InvalidIndex,
|
||||||
TooManyMessages,
|
TooManyMessages,
|
||||||
|
NoSuchMessage,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Reject for WebError {}
|
impl Reject for WebError {}
|
||||||
|
@ -78,6 +81,7 @@ async fn handle_rejection(err: Rejection) -> Result<impl Reply, Infallible> {
|
||||||
WebError::InvalidPackId => StatusCode::NOT_FOUND,
|
WebError::InvalidPackId => StatusCode::NOT_FOUND,
|
||||||
WebError::InvalidIndex => StatusCode::NOT_FOUND,
|
WebError::InvalidIndex => StatusCode::NOT_FOUND,
|
||||||
WebError::TooManyMessages => StatusCode::BAD_REQUEST,
|
WebError::TooManyMessages => StatusCode::BAD_REQUEST,
|
||||||
|
WebError::NoSuchMessage => StatusCode::NOT_FOUND,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
eprintln!("{:#?}", err);
|
eprintln!("{:#?}", err);
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub fn get_location(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||||
|
|
||||||
async fn logic(state: Arc<State>, id: i64, location: u32) -> Result<impl Reply, Rejection> {
|
async fn logic(state: Arc<State>, id: i64, location: u32) -> Result<impl Reply, Rejection> {
|
||||||
// TODO: when we're not just returning all results, make sure own messages are always present
|
// TODO: when we're not just returning all results, make sure own messages are always present
|
||||||
let id = location as i64;
|
let location = location as i64;
|
||||||
let messages = sqlx::query_as!(
|
let messages = sqlx::query_as!(
|
||||||
RetrievedMessage,
|
RetrievedMessage,
|
||||||
// language=sqlite
|
// language=sqlite
|
||||||
|
@ -31,12 +31,15 @@ async fn logic(state: Arc<State>, id: i64, location: u32) -> Result<impl Reply,
|
||||||
m.z,
|
m.z,
|
||||||
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
|
||||||
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 = ?
|
||||||
where m.territory = ?
|
where m.territory = ?
|
||||||
group by m.id"#,
|
group by m.id"#,
|
||||||
id,
|
id,
|
||||||
|
location,
|
||||||
)
|
)
|
||||||
.fetch_all(&state.db)
|
.fetch_all(&state.db)
|
||||||
.await
|
.await
|
||||||
|
|
53
server/src/web/get_message.rs
Normal file
53
server/src/web/get_message.rs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
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 get_message(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||||
|
warp::get()
|
||||||
|
.and(warp::path("messages"))
|
||||||
|
.and(warp::path::param())
|
||||||
|
.and(warp::path::end())
|
||||||
|
.and(super::get_id(Arc::clone(&state)))
|
||||||
|
.and_then(move |message_id: Uuid, id: i64| logic(Arc::clone(&state), id, message_id))
|
||||||
|
.boxed()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn logic(state: Arc<State>, id: i64, message_id: Uuid) -> Result<impl Reply, Rejection> {
|
||||||
|
let message_id = message_id.simple().to_string();
|
||||||
|
let message = sqlx::query_as!(
|
||||||
|
RetrievedMessageTerritory,
|
||||||
|
// language=sqlite
|
||||||
|
r#"
|
||||||
|
select m.id,
|
||||||
|
m.territory,
|
||||||
|
m.x,
|
||||||
|
m.y,
|
||||||
|
m.z,
|
||||||
|
m.message,
|
||||||
|
coalesce(sum(v.vote between 0 and 1), 0) as positive_votes,
|
||||||
|
coalesce(sum(v.vote between -1 and 0), 0) as negative_votes,
|
||||||
|
v2.vote as user_vote
|
||||||
|
from messages m
|
||||||
|
left join votes v on m.id = v.message
|
||||||
|
left join votes v2 on m.id = v2.message and v2.user = ?
|
||||||
|
where m.id = ?
|
||||||
|
group by m.id"#,
|
||||||
|
id,
|
||||||
|
message_id,
|
||||||
|
)
|
||||||
|
.fetch_optional(&state.db)
|
||||||
|
.await
|
||||||
|
.context("could not get message from database")
|
||||||
|
.map_err(AnyhowRejection)
|
||||||
|
.map_err(warp::reject::custom)?;
|
||||||
|
|
||||||
|
let message = message.ok_or_else(|| warp::reject::custom(WebError::NoSuchMessage))?;
|
||||||
|
Ok(warp::reply::json(&message))
|
||||||
|
}
|
|
@ -29,12 +29,15 @@ async fn logic(state: Arc<State>, id: i64) -> Result<impl Reply, Rejection> {
|
||||||
m.z,
|
m.z,
|
||||||
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
|
||||||
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 = ?
|
||||||
where m.user = ?
|
where m.user = ?
|
||||||
group by m.id"#,
|
group by m.id"#,
|
||||||
id,
|
id,
|
||||||
|
id,
|
||||||
)
|
)
|
||||||
.fetch_all(&state.db)
|
.fetch_all(&state.db)
|
||||||
.await
|
.await
|
||||||
|
|
Loading…
Reference in New Issue
Block a user