mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-08 09:24:17 +00:00
Add a vote_display_mode local_user setting. (#4450)
* Add a vote_display_mode local_user setting. - Fixes #4449 * Changing HideDownvotes to Score. * Adding ScoreAndDownvote display mode. * Adding upvote and downvote mode. * Extracting vote_display_mode to another table. * Fixing fmt. * Remove published and updated columns. --------- Co-authored-by: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com>
This commit is contained in:
parent
45c56df4e8
commit
15f02f00a9
|
@ -14,6 +14,7 @@ use lemmy_db_schema::{
|
|||
source::{
|
||||
actor_language::LocalUserLanguage,
|
||||
local_user::{LocalUser, LocalUserUpdateForm},
|
||||
local_user_vote_display_mode::{LocalUserVoteDisplayMode, LocalUserVoteDisplayModeUpdateForm},
|
||||
person::{Person, PersonUpdateForm},
|
||||
},
|
||||
traits::Crud,
|
||||
|
@ -136,5 +137,15 @@ pub async fn save_user_settings(
|
|||
.await
|
||||
.ok();
|
||||
|
||||
// Update the vote display modes
|
||||
let vote_display_modes_form = LocalUserVoteDisplayModeUpdateForm {
|
||||
score: data.show_scores,
|
||||
upvotes: data.show_upvotes,
|
||||
downvotes: data.show_downvotes,
|
||||
upvote_percentage: data.show_upvote_percentage,
|
||||
};
|
||||
LocalUserVoteDisplayMode::update(&mut context.pool(), local_user_id, &vote_display_modes_form)
|
||||
.await?;
|
||||
|
||||
Ok(Json(SuccessResponse::default()))
|
||||
}
|
||||
|
|
|
@ -86,8 +86,6 @@ pub struct SaveUserSettings {
|
|||
pub show_nsfw: Option<bool>,
|
||||
pub blur_nsfw: Option<bool>,
|
||||
pub auto_expand: Option<bool>,
|
||||
/// Show post and comment scores.
|
||||
pub show_scores: Option<bool>,
|
||||
/// Your user's theme.
|
||||
pub theme: Option<String>,
|
||||
pub default_sort_type: Option<SortType>,
|
||||
|
@ -122,6 +120,7 @@ pub struct SaveUserSettings {
|
|||
pub open_links_in_new_tab: Option<bool>,
|
||||
/// Enable infinite scroll
|
||||
pub infinite_scroll_enabled: Option<bool>,
|
||||
/// A post-view mode that changes how multiple post listings look.
|
||||
pub post_listing_mode: Option<PostListingMode>,
|
||||
/// Whether to allow keyboard navigation (for browsing and interacting with posts and comments).
|
||||
pub enable_keyboard_navigation: Option<bool>,
|
||||
|
@ -129,6 +128,11 @@ pub struct SaveUserSettings {
|
|||
pub enable_animated_images: Option<bool>,
|
||||
/// Whether to auto-collapse bot comments.
|
||||
pub collapse_bot_comments: Option<bool>,
|
||||
/// Some vote display mode settings
|
||||
pub show_scores: Option<bool>,
|
||||
pub show_upvotes: Option<bool>,
|
||||
pub show_downvotes: Option<bool>,
|
||||
pub show_upvote_percentage: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
|
||||
|
|
|
@ -21,6 +21,7 @@ use lemmy_db_schema::{
|
|||
source::{
|
||||
captcha_answer::{CaptchaAnswer, CheckCaptchaAnswer},
|
||||
local_user::{LocalUser, LocalUserInsertForm},
|
||||
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||
person::{Person, PersonInsertForm},
|
||||
registration_application::{RegistrationApplication, RegistrationApplicationInsertForm},
|
||||
},
|
||||
|
@ -183,6 +184,7 @@ pub async fn register(
|
|||
if local_site.require_email_verification {
|
||||
let local_user_view = LocalUserView {
|
||||
local_user: inserted_local_user,
|
||||
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),
|
||||
person: inserted_person,
|
||||
counts: PersonAggregates::default(),
|
||||
};
|
||||
|
|
|
@ -17,6 +17,7 @@ use lemmy_db_schema::{
|
|||
instance::Instance,
|
||||
instance_block::{InstanceBlock, InstanceBlockForm},
|
||||
local_user::{LocalUser, LocalUserUpdateForm},
|
||||
local_user_vote_display_mode::{LocalUserVoteDisplayMode, LocalUserVoteDisplayModeUpdateForm},
|
||||
person::{Person, PersonUpdateForm},
|
||||
person_block::{PersonBlock, PersonBlockForm},
|
||||
post::{PostSaved, PostSavedForm},
|
||||
|
@ -50,6 +51,7 @@ pub struct UserSettingsBackup {
|
|||
// TODO: might be worth making a separate struct for settings backup, to avoid breakage in case
|
||||
// fields are renamed, and to avoid storing unnecessary fields like person_id or email
|
||||
pub settings: Option<LocalUser>,
|
||||
pub vote_display_mode_settings: Option<LocalUserVoteDisplayMode>,
|
||||
#[serde(default)]
|
||||
pub followed_communities: Vec<ObjectId<ApubCommunity>>,
|
||||
#[serde(default)]
|
||||
|
@ -80,6 +82,7 @@ pub async fn export_settings(
|
|||
matrix_id: local_user_view.person.matrix_user_id,
|
||||
bot_account: local_user_view.person.bot_account.into(),
|
||||
settings: Some(local_user_view.local_user),
|
||||
vote_display_mode_settings: Some(local_user_view.local_user_vote_display_mode),
|
||||
followed_communities: vec_into(lists.followed_communities),
|
||||
blocked_communities: vec_into(lists.blocked_communities),
|
||||
blocked_instances: lists.blocked_instances,
|
||||
|
@ -132,6 +135,27 @@ pub async fn import_settings(
|
|||
)
|
||||
.await?;
|
||||
|
||||
// Update the vote display mode settings
|
||||
let vote_display_mode_form = LocalUserVoteDisplayModeUpdateForm {
|
||||
score: data.vote_display_mode_settings.as_ref().map(|s| s.score),
|
||||
upvotes: data.vote_display_mode_settings.as_ref().map(|s| s.upvotes),
|
||||
downvotes: data
|
||||
.vote_display_mode_settings
|
||||
.as_ref()
|
||||
.map(|s| s.downvotes),
|
||||
upvote_percentage: data
|
||||
.vote_display_mode_settings
|
||||
.as_ref()
|
||||
.map(|s| s.upvote_percentage),
|
||||
};
|
||||
|
||||
LocalUserVoteDisplayMode::update(
|
||||
&mut context.pool(),
|
||||
local_user_view.local_user.id,
|
||||
&vote_display_mode_form,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let url_count = data.followed_communities.len()
|
||||
+ data.blocked_communities.len()
|
||||
+ data.blocked_users.len()
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::{
|
|||
source::{
|
||||
actor_language::{LocalUserLanguage, SiteLanguage},
|
||||
local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
|
||||
local_user_vote_display_mode::{LocalUserVoteDisplayMode, LocalUserVoteDisplayModeInsertForm},
|
||||
},
|
||||
traits::Crud,
|
||||
utils::{
|
||||
|
@ -211,6 +212,12 @@ impl Crud for LocalUser {
|
|||
LocalUserLanguage::update(pool, vec![], local_user_.id).await?;
|
||||
}
|
||||
|
||||
// Create their vote_display_modes
|
||||
let vote_display_mode_form = LocalUserVoteDisplayModeInsertForm::builder()
|
||||
.local_user_id(local_user_.id)
|
||||
.build();
|
||||
LocalUserVoteDisplayMode::create(pool, &vote_display_mode_form).await?;
|
||||
|
||||
Ok(local_user_)
|
||||
}
|
||||
async fn update(
|
||||
|
|
57
crates/db_schema/src/impls/local_user_vote_display_mode.rs
Normal file
57
crates/db_schema/src/impls/local_user_vote_display_mode.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use crate::{
|
||||
newtypes::LocalUserId,
|
||||
schema::local_user_vote_display_mode,
|
||||
source::local_user_vote_display_mode::{
|
||||
LocalUserVoteDisplayMode,
|
||||
LocalUserVoteDisplayModeInsertForm,
|
||||
LocalUserVoteDisplayModeUpdateForm,
|
||||
},
|
||||
utils::{get_conn, DbPool},
|
||||
};
|
||||
use diesel::{dsl::insert_into, result::Error, QueryDsl};
|
||||
use diesel_async::RunQueryDsl;
|
||||
|
||||
impl LocalUserVoteDisplayMode {
|
||||
pub async fn read(pool: &mut DbPool<'_>) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
local_user_vote_display_mode::table
|
||||
.first::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn create(
|
||||
pool: &mut DbPool<'_>,
|
||||
form: &LocalUserVoteDisplayModeInsertForm,
|
||||
) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
insert_into(local_user_vote_display_mode::table)
|
||||
.values(form)
|
||||
.get_result::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
pub async fn update(
|
||||
pool: &mut DbPool<'_>,
|
||||
local_user_id: LocalUserId,
|
||||
form: &LocalUserVoteDisplayModeUpdateForm,
|
||||
) -> Result<(), Error> {
|
||||
// avoid error "There are no changes to save. This query cannot be built"
|
||||
if form.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
diesel::update(local_user_vote_display_mode::table.find(local_user_id))
|
||||
.set(form)
|
||||
.get_result::<Self>(conn)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl LocalUserVoteDisplayModeUpdateForm {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.score.is_none()
|
||||
&& self.upvotes.is_none()
|
||||
&& self.downvotes.is_none()
|
||||
&& self.upvote_percentage.is_none()
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ pub mod language;
|
|||
pub mod local_site;
|
||||
pub mod local_site_rate_limit;
|
||||
pub mod local_user;
|
||||
pub mod local_user_vote_display_mode;
|
||||
pub mod login_token;
|
||||
pub mod moderator;
|
||||
pub mod password_reset_request;
|
||||
|
|
|
@ -454,6 +454,16 @@ diesel::table! {
|
|||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
local_user_vote_display_mode (local_user_id) {
|
||||
local_user_id -> Int4,
|
||||
score -> Bool,
|
||||
upvotes -> Bool,
|
||||
downvotes -> Bool,
|
||||
upvote_percentage -> Bool,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
login_token (token) {
|
||||
token -> Text,
|
||||
|
@ -961,6 +971,7 @@ diesel::joinable!(local_site_rate_limit -> local_site (local_site_id));
|
|||
diesel::joinable!(local_user -> person (person_id));
|
||||
diesel::joinable!(local_user_language -> language (language_id));
|
||||
diesel::joinable!(local_user_language -> local_user (local_user_id));
|
||||
diesel::joinable!(local_user_vote_display_mode -> local_user (local_user_id));
|
||||
diesel::joinable!(login_token -> local_user (user_id));
|
||||
diesel::joinable!(mod_add_community -> community (community_id));
|
||||
diesel::joinable!(mod_ban_from_community -> community (community_id));
|
||||
|
@ -1043,6 +1054,7 @@ diesel::allow_tables_to_appear_in_same_query!(
|
|||
local_site_rate_limit,
|
||||
local_user,
|
||||
local_user_language,
|
||||
local_user_vote_display_mode,
|
||||
login_token,
|
||||
mod_add,
|
||||
mod_add_community,
|
||||
|
|
|
@ -36,6 +36,7 @@ pub struct LocalUser {
|
|||
pub show_avatars: bool,
|
||||
pub send_notifications_to_email: bool,
|
||||
/// Whether to show comment / post scores.
|
||||
// TODO now that there is a vote_display_mode, this can be gotten rid of in future releases.
|
||||
pub show_scores: bool,
|
||||
/// Whether to show bot accounts.
|
||||
pub show_bot_accounts: bool,
|
||||
|
@ -55,6 +56,7 @@ pub struct LocalUser {
|
|||
pub infinite_scroll_enabled: bool,
|
||||
/// Whether the person is an admin.
|
||||
pub admin: bool,
|
||||
/// A post-view mode that changes how multiple post listings look.
|
||||
pub post_listing_mode: PostListingMode,
|
||||
pub totp_2fa_enabled: bool,
|
||||
/// Whether to allow keyboard navigation (for browsing and interacting with posts and comments).
|
||||
|
|
51
crates/db_schema/src/source/local_user_vote_display_mode.rs
Normal file
51
crates/db_schema/src/source/local_user_vote_display_mode.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
use crate::newtypes::LocalUserId;
|
||||
#[cfg(feature = "full")]
|
||||
use crate::schema::local_user_vote_display_mode;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::skip_serializing_none;
|
||||
#[cfg(feature = "full")]
|
||||
use ts_rs::TS;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Default, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "full", derive(Queryable, Selectable, Identifiable, TS))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = local_user_vote_display_mode))]
|
||||
#[cfg_attr(feature = "full", diesel(primary_key(local_user_id)))]
|
||||
#[cfg_attr(
|
||||
feature = "full",
|
||||
diesel(belongs_to(crate::source::local_site::LocalUser))
|
||||
)]
|
||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// The vote display settings for your user.
|
||||
pub struct LocalUserVoteDisplayMode {
|
||||
pub local_user_id: LocalUserId,
|
||||
pub score: bool,
|
||||
pub upvotes: bool,
|
||||
pub downvotes: bool,
|
||||
pub upvote_percentage: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
#[builder(field_defaults(default))]
|
||||
#[cfg_attr(feature = "full", derive(Insertable))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = local_user_vote_display_mode))]
|
||||
pub struct LocalUserVoteDisplayModeInsertForm {
|
||||
#[builder(!default)]
|
||||
pub local_user_id: LocalUserId,
|
||||
pub score: Option<bool>,
|
||||
pub upvotes: Option<bool>,
|
||||
pub downvotes: Option<bool>,
|
||||
pub upvote_percentage: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
#[cfg_attr(feature = "full", derive(AsChangeset))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = local_user_vote_display_mode))]
|
||||
pub struct LocalUserVoteDisplayModeUpdateForm {
|
||||
pub score: Option<bool>,
|
||||
pub upvotes: Option<bool>,
|
||||
pub downvotes: Option<bool>,
|
||||
pub upvote_percentage: Option<bool>,
|
||||
}
|
|
@ -23,6 +23,7 @@ pub mod language;
|
|||
pub mod local_site;
|
||||
pub mod local_site_rate_limit;
|
||||
pub mod local_user;
|
||||
pub mod local_user_vote_display_mode;
|
||||
pub mod login_token;
|
||||
pub mod moderator;
|
||||
pub mod password_reset_request;
|
||||
|
|
|
@ -223,6 +223,7 @@ mod tests {
|
|||
community::{Community, CommunityInsertForm, CommunityModerator, CommunityModeratorForm},
|
||||
instance::Instance,
|
||||
local_user::{LocalUser, LocalUserInsertForm},
|
||||
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||
person::{Person, PersonInsertForm},
|
||||
post::{Post, PostInsertForm},
|
||||
},
|
||||
|
@ -258,6 +259,7 @@ mod tests {
|
|||
let timmy_local_user = LocalUser::create(pool, &new_local_user).await.unwrap();
|
||||
let timmy_view = LocalUserView {
|
||||
local_user: timmy_local_user,
|
||||
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),
|
||||
person: inserted_timmy.clone(),
|
||||
counts: Default::default(),
|
||||
};
|
||||
|
|
|
@ -441,6 +441,7 @@ mod tests {
|
|||
instance::Instance,
|
||||
language::Language,
|
||||
local_user::{LocalUser, LocalUserInsertForm},
|
||||
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||
person::{Person, PersonInsertForm},
|
||||
person_block::{PersonBlock, PersonBlockForm},
|
||||
post::{Post, PostInsertForm},
|
||||
|
@ -614,6 +615,7 @@ mod tests {
|
|||
|
||||
let timmy_local_user_view = LocalUserView {
|
||||
local_user: inserted_timmy_local_user.clone(),
|
||||
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),
|
||||
person: inserted_timmy_person.clone(),
|
||||
counts: Default::default(),
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@ use diesel::{result::Error, BoolExpressionMethods, ExpressionMethods, JoinOnDsl,
|
|||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_db_schema::{
|
||||
newtypes::{LocalUserId, PersonId},
|
||||
schema::{local_user, person, person_aggregates},
|
||||
schema::{local_user, local_user_vote_display_mode, person, person_aggregates},
|
||||
utils::{
|
||||
functions::{coalesce, lower},
|
||||
DbConn,
|
||||
|
@ -33,6 +33,7 @@ fn queries<'a>(
|
|||
) -> Queries<impl ReadFn<'a, LocalUserView, ReadBy<'a>>, impl ListFn<'a, LocalUserView, ListMode>> {
|
||||
let selection = (
|
||||
local_user::all_columns,
|
||||
local_user_vote_display_mode::all_columns,
|
||||
person::all_columns,
|
||||
person_aggregates::all_columns,
|
||||
);
|
||||
|
@ -58,6 +59,7 @@ fn queries<'a>(
|
|||
_ => query,
|
||||
};
|
||||
query
|
||||
.inner_join(local_user_vote_display_mode::table)
|
||||
.inner_join(person_aggregates::table.on(person::id.eq(person_aggregates::person_id)))
|
||||
.select(selection)
|
||||
.first::<LocalUserView>(&mut conn)
|
||||
|
@ -68,10 +70,11 @@ fn queries<'a>(
|
|||
match mode {
|
||||
ListMode::AdminsWithEmails => {
|
||||
local_user::table
|
||||
.filter(local_user::email.is_not_null())
|
||||
.filter(local_user::admin.eq(true))
|
||||
.inner_join(local_user_vote_display_mode::table)
|
||||
.inner_join(person::table)
|
||||
.inner_join(person_aggregates::table.on(person::id.eq(person_aggregates::person_id)))
|
||||
.filter(local_user::email.is_not_null())
|
||||
.filter(local_user::admin.eq(true))
|
||||
.select(selection)
|
||||
.load::<LocalUserView>(&mut conn)
|
||||
.await
|
||||
|
|
|
@ -206,6 +206,7 @@ mod tests {
|
|||
community::{Community, CommunityInsertForm, CommunityModerator, CommunityModeratorForm},
|
||||
instance::Instance,
|
||||
local_user::{LocalUser, LocalUserInsertForm},
|
||||
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||
person::{Person, PersonInsertForm},
|
||||
post::{Post, PostInsertForm},
|
||||
post_report::{PostReport, PostReportForm},
|
||||
|
@ -241,6 +242,7 @@ mod tests {
|
|||
let timmy_local_user = LocalUser::create(pool, &new_local_user).await.unwrap();
|
||||
let timmy_view = LocalUserView {
|
||||
local_user: timmy_local_user,
|
||||
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),
|
||||
person: inserted_timmy.clone(),
|
||||
counts: Default::default(),
|
||||
};
|
||||
|
|
|
@ -749,6 +749,7 @@ mod tests {
|
|||
instance_block::{InstanceBlock, InstanceBlockForm},
|
||||
language::Language,
|
||||
local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
|
||||
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||
person::{Person, PersonInsertForm},
|
||||
person_block::{PersonBlock, PersonBlockForm},
|
||||
post::{Post, PostHide, PostInsertForm, PostLike, PostLikeForm, PostRead, PostUpdateForm},
|
||||
|
@ -871,11 +872,13 @@ mod tests {
|
|||
let inserted_bot_post = Post::create(pool, &new_bot_post).await?;
|
||||
let local_user_view = LocalUserView {
|
||||
local_user: inserted_local_user,
|
||||
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),
|
||||
person: inserted_person,
|
||||
counts: Default::default(),
|
||||
};
|
||||
let blocked_local_user_view = LocalUserView {
|
||||
local_user: inserted_blocked_local_user,
|
||||
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),
|
||||
person: inserted_blocked_person,
|
||||
counts: Default::default(),
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@ use lemmy_db_schema::{
|
|||
local_site::LocalSite,
|
||||
local_site_rate_limit::LocalSiteRateLimit,
|
||||
local_user::LocalUser,
|
||||
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||
person::Person,
|
||||
post::Post,
|
||||
post_report::PostReport,
|
||||
|
@ -73,6 +74,7 @@ pub struct CommentView {
|
|||
/// A local user view.
|
||||
pub struct LocalUserView {
|
||||
pub local_user: LocalUser,
|
||||
pub local_user_vote_display_mode: LocalUserVoteDisplayMode,
|
||||
pub person: Person,
|
||||
pub counts: PersonAggregates,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
DROP TABLE local_user_vote_display_mode;
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
-- Create an extra table to hold local user vote display settings
|
||||
-- Score and Upvote percentage are turned on by default.
|
||||
CREATE TABLE local_user_vote_display_mode (
|
||||
local_user_id int REFERENCES local_user ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
||||
score boolean DEFAULT TRUE NOT NULL,
|
||||
upvotes boolean DEFAULT FALSE NOT NULL,
|
||||
downvotes boolean DEFAULT FALSE NOT NULL,
|
||||
upvote_percentage boolean DEFAULT TRUE NOT NULL,
|
||||
PRIMARY KEY (local_user_id)
|
||||
);
|
||||
|
||||
-- Insert rows for every local user
|
||||
INSERT INTO local_user_vote_display_mode (local_user_id)
|
||||
SELECT
|
||||
id
|
||||
FROM
|
||||
local_user;
|
||||
|
Loading…
Reference in a new issue