Support for deleting posts and comments

This commit is contained in:
Bnyro 2023-06-21 14:27:12 +02:00
parent 9748dc291e
commit e238beb3cf
15 changed files with 162 additions and 51 deletions

View File

@ -1,6 +1,6 @@
use lemmy_api_common::{comment::{CommentResponse, CreateComment, CreateCommentLike}, lemmy_db_schema::newtypes::{PostId, CommentId}}; use lemmy_api_common::{comment::{CommentResponse, CreateComment, CreateCommentLike, DeleteComment}, lemmy_db_schema::newtypes::{PostId, CommentId}};
use crate::util; use crate::settings;
pub fn create_comment( pub fn create_comment(
@ -12,7 +12,7 @@ pub fn create_comment(
post_id: PostId(post_id), post_id: PostId(post_id),
content, content,
parent_id: parent_id.map(CommentId), parent_id: parent_id.map(CommentId),
auth: util::get_auth_token().unwrap(), auth: settings::get_current_account().jwt.unwrap(),
..Default::default() ..Default::default()
}; };
super::post("/comment", &params) super::post("/comment", &params)
@ -23,7 +23,16 @@ pub fn like_comment(comment_id: CommentId, score: i16) -> Result<CommentResponse
let params = CreateCommentLike { let params = CreateCommentLike {
comment_id, comment_id,
score, score,
auth: util::get_auth_token().unwrap(), auth: settings::get_current_account().jwt.unwrap(),
}; };
super::post("/comment/like", &params) super::post("/comment/like", &params)
} }
pub fn delete_comment(comment_id: CommentId) -> Result<CommentResponse, reqwest::Error> {
let params = DeleteComment {
comment_id,
deleted: true,
auth: settings::get_current_account().jwt.unwrap(),
};
super::post("/comment/delete", &params)
}

View File

@ -1,7 +1,6 @@
use lemmy_api_common::{community::{ListCommunities, ListCommunitiesResponse}, lemmy_db_schema::{SortType, SearchType}, lemmy_db_views_actor::structs::CommunityView}; use lemmy_api_common::{community::{ListCommunities, ListCommunitiesResponse}, lemmy_db_schema::{SortType, SearchType}, lemmy_db_views_actor::structs::CommunityView};
use crate::util; use crate::settings;
use super::search; use super::search;
pub fn fetch_communities(page: i64, query: Option<String>) -> std::result::Result<Vec<CommunityView>, reqwest::Error> { pub fn fetch_communities(page: i64, query: Option<String>) -> std::result::Result<Vec<CommunityView>, reqwest::Error> {
@ -9,7 +8,7 @@ pub fn fetch_communities(page: i64, query: Option<String>) -> std::result::Resul
let params = ListCommunities { let params = ListCommunities {
sort: Some(SortType::TopMonth), sort: Some(SortType::TopMonth),
page: Some(page), page: Some(page),
auth: util::get_auth_token(), auth: settings::get_current_account().jwt,
..Default::default() ..Default::default()
}; };

View File

@ -1,11 +1,11 @@
use lemmy_api_common::{community::{GetCommunity, GetCommunityResponse, CommunityResponse, FollowCommunity}, lemmy_db_schema::newtypes::CommunityId}; use lemmy_api_common::{community::{GetCommunity, GetCommunityResponse, CommunityResponse, FollowCommunity}, lemmy_db_schema::newtypes::CommunityId};
use crate::util; use crate::settings;
pub fn get_community(name: String) -> std::result::Result<GetCommunityResponse, reqwest::Error> { pub fn get_community(name: String) -> std::result::Result<GetCommunityResponse, reqwest::Error> {
let params = GetCommunity { let params = GetCommunity {
name: Some(name), name: Some(name),
auth: util::get_auth_token(), auth: settings::get_current_account().jwt,
..Default::default() ..Default::default()
}; };
@ -19,7 +19,7 @@ pub fn follow_community(
let params = FollowCommunity { let params = FollowCommunity {
community_id: CommunityId(community_id), community_id: CommunityId(community_id),
follow, follow,
auth: util::get_auth_token().unwrap(), auth: settings::get_current_account().jwt.unwrap(),
}; };
super::post("/community/follow", &params) super::post("/community/follow", &params)
} }

View File

@ -1,6 +1,6 @@
use serde::{de::DeserializeOwned, Serialize}; use serde::{de::DeserializeOwned, Serialize};
use crate::settings::get_prefs; use crate::settings::get_current_account;
pub mod communities; pub mod communities;
pub mod community; pub mod community;
@ -11,6 +11,7 @@ pub mod user;
pub mod auth; pub mod auth;
pub mod moderation; pub mod moderation;
pub mod comment; pub mod comment;
pub mod site;
static API_VERSION: &str = "v3"; static API_VERSION: &str = "v3";
@ -22,7 +23,7 @@ pub static CLIENT: Lazy<Client> = Lazy::new(|| {
}); });
fn get_api_url() -> String { fn get_api_url() -> String {
format!("{}/api/{}", get_prefs().instance_url, API_VERSION).to_string() format!("{}/api/{}", get_current_account().instance_url, API_VERSION).to_string()
} }
fn get_url(path: &str) -> String { fn get_url(path: &str) -> String {

View File

@ -1,11 +1,11 @@
use lemmy_api_common::{post::{GetPost, GetPostResponse, PostResponse, CreatePost, CreatePostLike}, lemmy_db_schema::{newtypes::{PostId, CommunityId}, CommentSortType, ListingType}, comment::{GetComments, GetCommentsResponse}, lemmy_db_views::structs::CommentView}; use lemmy_api_common::{post::{GetPost, GetPostResponse, PostResponse, CreatePost, CreatePostLike, DeletePost}, lemmy_db_schema::{newtypes::{PostId, CommunityId}, CommentSortType, ListingType}, comment::{GetComments, GetCommentsResponse}, lemmy_db_views::structs::CommentView};
use crate::util; use crate::settings;
pub fn get_post(id: PostId) -> Result<GetPostResponse, reqwest::Error> { pub fn get_post(id: PostId) -> Result<GetPostResponse, reqwest::Error> {
let params = GetPost { let params = GetPost {
id: Some(id), id: Some(id),
auth: util::get_auth_token(), auth: settings::get_current_account().jwt,
..Default::default() ..Default::default()
}; };
@ -17,7 +17,7 @@ pub fn get_comments(post_id: PostId) -> Result<Vec<CommentView>, reqwest::Error>
post_id: Some(post_id), post_id: Some(post_id),
sort: Some(CommentSortType::Hot), sort: Some(CommentSortType::Hot),
type_: Some(ListingType::All), type_: Some(ListingType::All),
auth: util::get_auth_token(), auth: settings::get_current_account().jwt,
..Default::default() ..Default::default()
}; };
@ -42,7 +42,7 @@ pub fn create_post(
name, name,
body: Some(body), body: Some(body),
community_id: CommunityId(community_id), community_id: CommunityId(community_id),
auth: util::get_auth_token().unwrap(), auth: settings::get_current_account().jwt.unwrap(),
..Default::default() ..Default::default()
}; };
super::post("/post", &params) super::post("/post", &params)
@ -53,7 +53,16 @@ pub fn like_post(post_id: PostId, score: i16) -> Result<PostResponse, reqwest::E
let params = CreatePostLike { let params = CreatePostLike {
post_id, post_id,
score, score,
auth: util::get_auth_token().unwrap(), auth: settings::get_current_account().jwt.unwrap(),
}; };
super::post("/post/like", &params) super::post("/post/like", &params)
} }
pub fn delete_post(post_id: PostId) -> Result<PostResponse, reqwest::Error> {
let params = DeletePost {
post_id,
deleted: true,
auth: settings::get_current_account().jwt.unwrap(),
};
super::post("/post/delete", &params)
}

View File

@ -1,13 +1,13 @@
use lemmy_api_common::{post::{GetPostsResponse, GetPosts}, lemmy_db_views::structs::PostView, lemmy_db_schema::ListingType}; use lemmy_api_common::{post::{GetPostsResponse, GetPosts}, lemmy_db_views::structs::PostView, lemmy_db_schema::ListingType};
use crate::util; use crate::settings;
pub fn list_posts(page: i64, community_name: Option<String>, listing_type: Option<ListingType>) -> std::result::Result<Vec<PostView>, reqwest::Error> { pub fn list_posts(page: i64, community_name: Option<String>, listing_type: Option<ListingType>) -> std::result::Result<Vec<PostView>, reqwest::Error> {
let params = GetPosts { let params = GetPosts {
page: Some(page), page: Some(page),
type_: listing_type, type_: listing_type,
community_name, community_name,
auth: util::get_auth_token(), auth: settings::get_current_account().jwt,
..Default::default() ..Default::default()
}; };

View File

@ -1,6 +1,6 @@
use lemmy_api_common::{site::{SearchResponse, Search}, lemmy_db_schema::{SortType, SearchType}}; use lemmy_api_common::{site::{SearchResponse, Search}, lemmy_db_schema::{SortType, SearchType}};
use crate::util; use crate::settings;
pub fn fetch_search(page: i64, query: String, search_type: Option<SearchType>) -> std::result::Result<SearchResponse, reqwest::Error> { pub fn fetch_search(page: i64, query: String, search_type: Option<SearchType>) -> std::result::Result<SearchResponse, reqwest::Error> {
let params = Search { let params = Search {
@ -8,7 +8,7 @@ pub fn fetch_search(page: i64, query: String, search_type: Option<SearchType>) -
sort: Some(SortType::TopMonth), sort: Some(SortType::TopMonth),
page: Some(page), page: Some(page),
type_: search_type, type_: search_type,
auth: util::get_auth_token(), auth: settings::get_current_account().jwt,
..Default::default() ..Default::default()
}; };

10
src/api/site.rs Normal file
View File

@ -0,0 +1,10 @@
use lemmy_api_common::site::{GetSiteResponse, GetSite};
use crate::settings;
pub fn fetch_site() -> std::result::Result<GetSiteResponse, reqwest::Error> {
let params = GetSite {
auth: settings::get_current_account().jwt,
};
super::get("/site", &params)
}

View File

@ -1,12 +1,12 @@
use lemmy_api_common::{person::{GetPersonDetailsResponse, GetPersonDetails}}; use lemmy_api_common::{person::{GetPersonDetailsResponse, GetPersonDetails}};
use crate::util; use crate::settings;
pub fn get_user(username: String, page: i64) -> std::result::Result<GetPersonDetailsResponse, reqwest::Error> { pub fn get_user(username: String, page: i64) -> std::result::Result<GetPersonDetailsResponse, reqwest::Error> {
let params = GetPersonDetails { let params = GetPersonDetails {
page: Some(page), page: Some(page),
username: Some(username), username: Some(username),
auth: util::get_auth_token(), auth: settings::get_current_account().jwt,
..Default::default() ..Default::default()
}; };

View File

@ -3,8 +3,10 @@ use relm4::prelude::*;
use gtk::prelude::*; use gtk::prelude::*;
use relm4_components::web_image::WebImage; use relm4_components::web_image::WebImage;
use crate::api;
use crate::util::get_web_image_url; use crate::util::get_web_image_url;
use crate::util::markdown_to_pango_markup; use crate::util::markdown_to_pango_markup;
use crate::settings;
use super::voting_row::VotingRowModel; use super::voting_row::VotingRowModel;
use super::voting_row::VotingStats; use super::voting_row::VotingStats;
@ -19,6 +21,7 @@ pub struct CommentRow {
#[derive(Debug)] #[derive(Debug)]
pub enum CommentRowMsg { pub enum CommentRowMsg {
OpenPerson, OpenPerson,
DeleteComment,
} }
#[relm4::factory(pub)] #[relm4::factory(pub)]
@ -66,8 +69,21 @@ impl FactoryComponent for CommentRow {
set_use_markup: true, set_use_markup: true,
}, },
#[local_ref] gtk::Box {
voting_row -> gtk::Box {}, set_orientation: gtk::Orientation::Vertical,
#[local_ref]
voting_row -> gtk::Box {},
if self.comment.creator.id.0 == settings::get_current_account().id {
gtk::Button {
set_icon_name: "edit-delete",
connect_clicked => CommentRowMsg::DeleteComment,
set_margin_start: 10,
}
} else {
gtk::Box {}
}
},
gtk::Separator {} gtk::Separator {}
} }
@ -102,6 +118,13 @@ impl FactoryComponent for CommentRow {
CommentRowMsg::OpenPerson => { CommentRowMsg::OpenPerson => {
sender.output(crate::AppMsg::OpenPerson(self.comment.creator.name.clone())) sender.output(crate::AppMsg::OpenPerson(self.comment.creator.name.clone()))
} }
CommentRowMsg::DeleteComment => {
let comment_id = self.comment.comment.id;
std::thread::spawn(move || {
let _ = api::comment::delete_comment(comment_id);
let _ = sender.output(crate::AppMsg::StartFetchPosts(None));
});
}
} }
} }
} }

View File

@ -3,7 +3,7 @@ use relm4::{prelude::*, factory::FactoryVecDeque};
use gtk::prelude::*; use gtk::prelude::*;
use relm4_components::web_image::WebImage; use relm4_components::web_image::WebImage;
use crate::{api, util::{get_web_image_msg, get_web_image_url, markdown_to_pango_markup}, dialogs::create_post::{CreatePostDialog, CreatePostDialogOutput, DialogMsg, CREATE_COMMENT_DIALOG_BROKER, DialogType}}; use crate::{api, util::{get_web_image_msg, get_web_image_url, markdown_to_pango_markup}, dialogs::create_post::{CreatePostDialog, CreatePostDialogOutput, DialogMsg, CREATE_COMMENT_DIALOG_BROKER, DialogType}, settings};
use super::{comment_row::CommentRow, voting_row::{VotingRowModel, VotingStats, VotingRowInput}}; use super::{comment_row::CommentRow, voting_row::{VotingRowModel, VotingStats, VotingRowInput}};
@ -27,7 +27,9 @@ pub enum PostInput {
OpenLink, OpenLink,
OpenCreateCommentDialog, OpenCreateCommentDialog,
CreateCommentRequest(String), CreateCommentRequest(String),
CreatedComment(CommentView) CreatedComment(CommentView),
DeletePost,
EditPost,
} }
#[relm4::component(pub)] #[relm4::component(pub)]
@ -114,6 +116,16 @@ impl SimpleComponent for PostPage {
gtk::Button { gtk::Button {
set_label: "View", set_label: "View",
connect_clicked => PostInput::OpenLink, connect_clicked => PostInput::OpenLink,
},
if model.info.post_view.creator.id.0 == settings::get_current_account().id {
gtk::Button {
set_icon_name: "edit-delete",
connect_clicked => PostInput::DeletePost,
set_margin_start: 10,
}
} else {
gtk::Box {}
} }
}, },
@ -237,6 +249,16 @@ impl SimpleComponent for PostPage {
if message.is_some() { sender.input(message.unwrap()) }; if message.is_some() { sender.input(message.unwrap()) };
}); });
} }
PostInput::DeletePost => {
let post_id = self.info.post_view.post.id;
std::thread::spawn(move || {
let _ = api::post::delete_post(post_id);
let _ = sender.output(crate::AppMsg::StartFetchPosts(None));
});
}
PostInput::EditPost => {
}
} }
} }
} }

View File

@ -3,7 +3,8 @@ use relm4::prelude::*;
use gtk::prelude::*; use gtk::prelude::*;
use relm4_components::web_image::WebImage; use relm4_components::web_image::WebImage;
use crate::util::get_web_image_url; use crate::{util::get_web_image_url, api};
use crate::settings;
use super::voting_row::{VotingRowModel, VotingStats}; use super::voting_row::{VotingRowModel, VotingStats};
@ -19,7 +20,8 @@ pub struct PostRow {
pub enum PostViewMsg { pub enum PostViewMsg {
OpenPost, OpenPost,
OpenCommunity, OpenCommunity,
OpenPerson OpenPerson,
DeletePost
} }
#[relm4::factory(pub)] #[relm4::factory(pub)]
@ -104,6 +106,15 @@ impl FactoryComponent for PostRow {
set_halign: gtk::Align::Start, set_halign: gtk::Align::Start,
set_text: &format!("{} comments", self.post.clone().counts.comments), set_text: &format!("{} comments", self.post.clone().counts.comments),
}, },
if self.post.creator.id.0 == settings::get_current_account().id {
gtk::Button {
set_icon_name: "edit-delete",
connect_clicked => PostViewMsg::DeletePost,
set_margin_start: 10,
}
} else {
gtk::Box {}
}
}, },
gtk::Separator { gtk::Separator {
@ -147,6 +158,13 @@ impl FactoryComponent for PostRow {
PostViewMsg::OpenPost => { PostViewMsg::OpenPost => {
sender.output(crate::AppMsg::OpenPost(self.post.post.id.clone())) sender.output(crate::AppMsg::OpenPost(self.post.post.id.clone()))
} }
PostViewMsg::DeletePost => {
let post_id = self.post.post.id;
std::thread::spawn(move || {
let _ = api::post::delete_post(post_id);
let _ = sender.output(crate::AppMsg::StartFetchPosts(None));
});
}
} }
} }
} }

View File

@ -265,7 +265,7 @@ impl SimpleComponent for App {
root: &Self::Root, root: &Self::Root,
sender: ComponentSender<Self>, sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {
let instance_url = settings::get_prefs().instance_url; let instance_url = settings::get_current_account().instance_url;
let state = if instance_url.is_empty() { AppState::ChooseInstance } else { AppState::Loading }; let state = if instance_url.is_empty() { AppState::ChooseInstance } else { AppState::Loading };
// initialize all controllers and factories // initialize all controllers and factories
@ -315,9 +315,9 @@ impl SimpleComponent for App {
match msg { match msg {
AppMsg::DoneChoosingInstance(instance_url) => { AppMsg::DoneChoosingInstance(instance_url) => {
if instance_url.trim().is_empty() { return; } if instance_url.trim().is_empty() { return; }
let mut preferences = settings::get_prefs(); let mut current_account = settings::get_current_account();
preferences.instance_url = instance_url; current_account.instance_url = instance_url;
settings::save_prefs(&preferences); settings::update_current_account(current_account);
self.state = AppState::Loading; self.state = AppState::Loading;
sender.input(AppMsg::StartFetchPosts(None)); sender.input(AppMsg::StartFetchPosts(None));
} }
@ -409,7 +409,14 @@ impl SimpleComponent for App {
let message = match api::auth::login(username, password) { let message = match api::auth::login(username, password) {
Ok(login) => { Ok(login) => {
if let Some(token) = login.jwt { if let Some(token) = login.jwt {
util::set_auth_token(Some(token)); let mut account = settings::get_current_account();
account.jwt = Some(token);
settings::update_current_account(account.clone());
if let Ok(site) = api::site::fetch_site() {
let user = site.my_user.unwrap().local_user_view.person;
account.name = user.name;
account.id = user.id.0;
}
AppMsg::StartFetchPosts(None) AppMsg::StartFetchPosts(None)
} else { } else {
AppMsg::ShowMessage("Wrong credentials!".to_string()) AppMsg::ShowMessage("Wrong credentials!".to_string())
@ -421,7 +428,9 @@ impl SimpleComponent for App {
}); });
} }
AppMsg::Logout => { AppMsg::Logout => {
util::set_auth_token(None); let mut account = settings::get_current_account();
account.jwt = None;
settings::update_current_account(account);
} }
AppMsg::ShowMessage(message) => { AppMsg::ShowMessage(message) => {
self.message = Some(message); self.message = Some(message);

View File

@ -4,10 +4,18 @@ use lemmy_api_common::sensitive::Sensitive;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::APP_ID; use crate::APP_ID;
#[derive(Deserialize, Serialize, Default, Clone)]
pub struct Account {
pub instance_url: String,
pub jwt: Option<Sensitive<String>>,
pub id: i32,
pub name: String,
}
#[derive(Deserialize, Serialize, Default)] #[derive(Deserialize, Serialize, Default)]
pub struct Preferences { pub struct Preferences {
pub instance_url: String, pub accounts: Vec<Account>,
pub jwt: Option<Sensitive<String>> pub current_account_index: u32
} }
pub fn data_path() -> PathBuf { pub fn data_path() -> PathBuf {
@ -33,3 +41,18 @@ pub fn get_prefs() -> Preferences {
} }
return Preferences::default(); return Preferences::default();
} }
pub fn get_current_account() -> Account {
let mut prefs = get_prefs();
if prefs.accounts.len() == 0 {
prefs.accounts.push(Account::default());
save_prefs(&prefs);
}
prefs.accounts[prefs.current_account_index as usize].clone()
}
pub fn update_current_account(account: Account) {
let mut settings = get_prefs();
settings.accounts[settings.current_account_index as usize] = account;
save_prefs(&settings);
}

View File

@ -1,8 +1,6 @@
use lemmy_api_common::{lemmy_db_schema::newtypes::DbUrl, sensitive::Sensitive}; use lemmy_api_common::lemmy_db_schema::newtypes::DbUrl;
use relm4_components::web_image::WebImageMsg; use relm4_components::web_image::WebImageMsg;
use crate::settings;
pub fn get_web_image_msg(url: Option<DbUrl>) -> WebImageMsg { pub fn get_web_image_msg(url: Option<DbUrl>) -> WebImageMsg {
return if let Some(url) = url { return if let Some(url) = url {
WebImageMsg::LoadImage(url.to_string()) WebImageMsg::LoadImage(url.to_string())
@ -18,13 +16,3 @@ pub fn get_web_image_url(url: Option<DbUrl>) -> String {
pub fn markdown_to_pango_markup(text: String) -> String { pub fn markdown_to_pango_markup(text: String) -> String {
return html2pango::markup_html(&markdown::to_html(&text)).unwrap_or(text) return html2pango::markup_html(&markdown::to_html(&text)).unwrap_or(text)
} }
pub fn set_auth_token(token: Option<Sensitive<String>>) {
let mut settings = settings::get_prefs();
settings.jwt = token.clone();
settings::save_prefs(&settings);
}
pub fn get_auth_token() -> Option<Sensitive<String>> {
settings::get_prefs().jwt
}