]> Untitled Git - lemmy.git/commitdiff
Add user bios (#1043)
authorAzriel Lector <Axighi@users.noreply.github.com>
Fri, 31 Jul 2020 01:08:13 +0000 (09:08 +0800)
committerGitHub <noreply@github.com>
Fri, 31 Jul 2020 01:08:13 +0000 (21:08 -0400)
* 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>
.gitignore
server/src/api/user.rs
ui/src/components/markdown-textarea.tsx
ui/src/components/user.tsx
ui/src/interfaces.ts
ui/translations/en.json

index 6ae0ae1935606bd725bebea231f30b0e6437acc1..c3a8bd70ed5174a0fb40a66fa8d45cfb2751acb0 100644 (file)
@@ -16,5 +16,6 @@ ui/src/translations
 
 # ide config
 .idea/
+.vscode/
 
 target
index c2b6955b56cc3163f55543dfc337a813e0d7b98e..f9a92cd39e86c03ad75daf8f0dbe056fe11ff2e3 100644 (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,
index 237ef9ff3c0bf21f64a3c7f88fa398a5d1a6ca13..002d7c86ba4ddf3499bd88de7230667ce7addf67 100644 (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
index d0dcdf55e5c097a05919e3fd4a80e282024805a0..9bda827465bbd4ee5c272752d51b98070615bae1 100644 (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({
index 87aa400a6400f61c1b516c2cb387a7371bb461c5..9c0e76244eef925f74c4933f2f93caabe27d8df4 100644 (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;
index 4ee0907a51195ad94bf9defebe42fdbb29ca147c..7304d4a75821d2f9e33a369a9c9d73275a47463e 100644 (file)
     "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.",
     "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"
 }