Browse Source

Add user bios (#1043)

* Add user bios

* Version v0.7.35

* Add domain name change instructions to docs. (#1044)

* Add domain name change instructions to docs.

* Changing docker execs to docker-compose execs

* Set maxLength to user bio and render as md

* Fix bio updating after SaveUserSetting

Co-authored-by: Dessalines <tyhou13@gmx.com>
Co-authored-by: Dessalines <dessalines@users.noreply.github.com>
more-inbox-permissions
Azriel Lector 8 months ago
committed by GitHub
parent
commit
1acb51105a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 57 additions and 6 deletions
  1. +1
    -0
      .gitignore
  2. +13
    -1
      server/src/api/user.rs
  3. +2
    -1
      ui/src/components/markdown-textarea.tsx
  4. +37
    -3
      ui/src/components/user.tsx
  5. +1
    -0
      ui/src/interfaces.ts
  6. +3
    -1
      ui/translations/en.json

+ 1
- 0
.gitignore View File

@ -16,5 +16,6 @@ ui/src/translations
# ide config
.idea/
.vscode/
target

+ 13
- 1
server/src/api/user.rs View File

@ -97,6 +97,7 @@ pub struct SaveUserSettings {
lang: String,
avatar: Option<String>,
email: Option<String>,
bio: Option<String>,
matrix_user_id: Option<String>,
new_password: Option<String>,
new_password_verify: Option<String>,
@ -557,6 +558,17 @@ impl Perform for Oper<SaveUserSettings> {
None => read_user.email,
};
let bio = match &data.bio {
Some(bio) => {
if bio.chars().count() <= 300 {
Some(bio.to_owned())
} else {
return Err(APIError::err("bio_length_overflow").into());
}
}
None => read_user.bio,
};
let avatar = match &data.avatar {
Some(avatar) => Some(avatar.to_owned()),
None => read_user.avatar,
@ -613,7 +625,7 @@ impl Perform for Oper<SaveUserSettings> {
show_avatars: data.show_avatars,
send_notifications_to_email: data.send_notifications_to_email,
actor_id: read_user.actor_id,
bio: read_user.bio,
bio,
local: read_user.local,
private_key: read_user.private_key,
public_key: read_user.public_key,


+ 2
- 1
ui/src/components/markdown-textarea.tsx View File

@ -21,6 +21,7 @@ interface MarkdownTextAreaProps {
replyType?: boolean;
focus?: boolean;
disabled?: boolean;
maxLength?: number;
onSubmit?(msg: { val: string; formId: string }): any;
onContentChange?(val: string): any;
onReplyCancel?(): any;
@ -121,7 +122,7 @@ export class MarkdownTextArea extends Component<
required
disabled={this.props.disabled}
rows={2}
maxLength={10000}
maxLength={this.props.maxLength || 10000}
/>
{this.state.previewMode && (
<div


+ 37
- 3
ui/src/components/user.tsx View File

@ -31,6 +31,7 @@ import {
toast,
setupTippy,
getLanguage,
mdToHtml,
} from '../utils';
import { UserListing } from './user-listing';
import { SortSelect } from './sort-select';
@ -39,6 +40,7 @@ import { MomentTime } from './moment-time';
import { i18n } from '../i18next';
import moment from 'moment';
import { UserDetails } from './user-details';
import { MarkdownTextArea } from './markdown-textarea';
interface UserState {
user: UserView;
@ -109,6 +111,7 @@ export class User extends Component<any, UserState> {
show_avatars: null,
send_notifications_to_email: null,
auth: null,
bio: null,
},
userSettingsLoading: null,
deleteAccountLoading: null,
@ -149,7 +152,13 @@ export class User extends Component<any, UserState> {
this.handleUserSettingsListingTypeChange = this.handleUserSettingsListingTypeChange.bind(
this
);
this.handleUserSettingsListingTypeChange = this.handleUserSettingsListingTypeChange.bind(
this
);
this.handlePageChange = this.handlePageChange.bind(this);
this.handleUserSettingsBioChange = this.handleUserSettingsBioChange.bind(
this
);
this.state.user_id = Number(this.props.match.params.id) || null;
this.state.username = this.props.match.params.username;
@ -375,6 +384,12 @@ export class User extends Component<any, UserState> {
)}
</ul>
</h5>
<div className="d-flex align-items-center mb-2">
<div
className="md-div"
dangerouslySetInnerHTML={mdToHtml(user.bio)}
/>
</div>
<div className="d-flex align-items-center mb-2">
<svg class="icon">
<use xlinkHref="#icon-cake"></use>
@ -570,6 +585,18 @@ export class User extends Component<any, UserState> {
/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-3 col-form-label" htmlFor="user-bio">
{i18n.t('bio')}
</label>
<div class="col-lg-9">
<MarkdownTextArea
initialContent={this.state.userSettingsForm.bio}
onContentChange={this.handleUserSettingsBioChange}
maxLength={300}
/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-5 col-form-label">
<a
@ -900,6 +927,11 @@ export class User extends Component<any, UserState> {
i.setState(i.state);
}
handleUserSettingsBioChange(val: string) {
this.state.userSettingsForm.bio = val;
this.setState(this.state);
}
handleUserSettingsMatrixUserIdChange(i: User, event: any) {
i.state.userSettingsForm.matrix_user_id = event.target.value;
if (
@ -1057,6 +1089,7 @@ export class User extends Component<any, UserState> {
this.state.userSettingsForm.lang = UserService.Instance.user.lang;
this.state.userSettingsForm.avatar = UserService.Instance.user.avatar;
this.state.userSettingsForm.email = this.state.user.email;
this.state.userSettingsForm.bio = this.state.user.bio;
this.state.userSettingsForm.send_notifications_to_email = this.state.user.send_notifications_to_email;
this.state.userSettingsForm.show_avatars =
UserService.Instance.user.show_avatars;
@ -1068,9 +1101,10 @@ export class User extends Component<any, UserState> {
} else if (res.op == UserOperation.SaveUserSettings) {
const data = res.data as LoginResponse;
UserService.Instance.login(data);
this.setState({
userSettingsLoading: false,
});
this.state.user.bio = this.state.userSettingsForm.bio;
this.state.userSettingsLoading = false;
this.setState(this.state);
window.scrollTo(0, 0);
} else if (res.op == UserOperation.DeleteAccount) {
this.setState({


+ 1
- 0
ui/src/interfaces.ts View File

@ -597,6 +597,7 @@ export interface UserSettingsForm {
lang: string;
avatar?: string;
email?: string;
bio?: string;
matrix_user_id?: string;
new_password?: string;
new_password_verify?: string;


+ 3
- 1
ui/translations/en.json View File

@ -228,6 +228,7 @@
"landing_0":
"Lemmy is a <1>link aggregator</1> / reddit alternative, intended to work in the <2>fediverse</2>.<3></3>It's self-hostable, has live-updating comment threads, and is tiny (<4>~80kB</4>). Federation into the ActivityPub network is on the roadmap. <5></5>This is a <6>very early beta version</6>, and a lot of features are currently broken or missing. <7></7>Suggest new features or report bugs <8>here.</8><9></9>Made with <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>. <14></14> <15>Thank you to our contributors: </15> dessalines, Nutomic, asonix, zacanger, and iav.",
"not_logged_in": "Not logged in.",
"bio_length_overflow": "User bio cannot exceed 300 characters!",
"logged_in": "Logged in.",
"must_login": "You must <1>log in or register</1> to comment.",
"site_saved": "Site Saved.",
@ -284,5 +285,6 @@
"cake_day_info": "It's {{ creator_name }}'s cake day today!",
"invalid_post_title": "Invalid post title",
"invalid_url": "Invalid URL.",
"play_captcha_audio": "Play Captcha Audio"
"play_captcha_audio": "Play Captcha Audio",
"bio": "Bio"
}

Loading…
Cancel
Save