[Shanda Zhiyun Project Log] seahub frontend components common for source code analysis

2021SC@SDUSC
This time, combined with the deployed web application interface of the original seafile, and then starting from the source code, find out the corresponding components on the page. Map each component of the page to the code. First from components Lower common Start under the folder.
Sub components in the header component of the home page account.js The corresponding page elements are as follows:

Next, expand the analysis and look at the schematic diagram first:

1. Distinguish between ordinary user panel and system administrator panel

Through the props passed from the parent component, the child component uses the bool attribute in propTypes to determine whether the user is an administrator

const propTypes = {
  isAdminPanel: PropTypes.bool,
};

2. Set the state of the component

  constructor(props) {
    super(props);
    this.state = {
      showInfo: false,  //Display information
      userName: '', //user name
      contactEmail: '', //User mailbox
      quotaUsage: '', //Quota used
      quotaTotal: '', //Total quota
      isStaff: false,  //Administrator
      isOrgStaff: false, //Are you a group administrator
      usageRate: '',  // Utilization rate
    };
    this.isFirstMounted = true;  //Is this the first mount
  }

3. Elements rendered to the page - Avatar

         <a id="my-info" onClick={this.onClickAccount} className="account-toggle no-deco d-none d-md-block" aria-label="View profile and more">
          <span>{this.renderAvatar()}</span>
          <span className="fas fa-caret-down vam"></span> //It is an empty space. Here we fill in a little content "??" to locate the span position
        </a> //Avatar element} 
               

Obtained by function renderAvatar()

renderAvatar = () => {
    return (<img src={appAvatarURL} width="36" height="36" className="avatar" alt={gettext('Avatar')} />);

Compared with the page, we added "the touxiang" to facilitate positioning. Let's see the figure

Click the avatar or the position occupied by the blank span, and we get the above schematic diagram. The code is as follows

<div id="user-info-popup" className={`account-popup sf-popover ${this.state.showInfo? '':'hide'}`}>
          <div className="outer-caret up-outer-caret">
            <div className="inner-caret"></div>
          </div>
          <div className="sf-popover-con">
            <div className="item o-hidden">
              {this.renderAvatar()}  //Avatar, user name under a box.
              <div className="txt">{this.state.userName}</div> 
            </div>
            <div id="space-traffic">
              <div className="item">
                <p>{gettext('Used:')}{' '}{this.state.quotaUsage} / {this.state.quotaTotal}</p> //Used space quota / total quota
                <div id="quota-bar"><span id="quota-usage" className="usage" style={{width: this.state.usageRate}}></span></div>
                //The usage frequency is dynamically controlled by span style
              </div>
            </div>
            <a href={siteRoot + 'profile/'} className="item">{gettext('Settings')}</a>//system management
           {this.renderMenu()} 
            <a href={siteRoot + 'accounts/logout/'} className="item">{gettext('Log out')}</a>
          </div>  //sign out
        </div>

The gettext() function here is used under the internationalization component. When the user switches the language, the parameters in gettext() are converted into the language set by the user. The corresponding language here is Chinese.
Review the diagram again:

4. After analyzing the page elements, take a look at the main functions:
After the component is first mounted

onClickAccount = () => {
    if (this.isFirstMounted) {
      seafileAPI.getAccountInfo().then(resp => { //Execute after calling the interface successfully
        this.setState({  //The return information obtained through the api is set to the status resp, and then the page elements can be used
          userName: resp.data.name,
          contactEmail: resp.data.email,
          usageRate: resp.data.space_usage,
          quotaUsage: Utils.bytesToSize(resp.data.usage),
          quotaTotal: Utils.bytesToSize(resp.data.total),
          isStaff: resp.data.is_staff,
          isInstAdmin: resp.data.is_inst_admin,
          isOrgStaff: resp.data.is_org_staff === 1 ? true : false,
          showInfo: !this.state.showInfo,
        });
      }).catch(error => {   //Error message capture
        let errMessage = Utils.getErrorMsg(error);
        toaster.danger(errMessage);
      });
      this.isFirstMounted = false;   // Since the component is successfully mounted, set the state of the first mount to false 
    } else {
      this.setState({showInfo: !this.state.showInfo});  //If it is not the first time to mount, there is no need to call the api
    }
  }

Another function is the renderMenu function, which is displayed on the page

In this function, first judge whether the user is in the management panel, and then set different options by judging the user identity.

  renderMenu = () => {
    let data;
    const { isStaff, isOrgStaff, isInstAdmin } = this.state;

    if (this.props.isAdminPanel) {  //If you are a system administrator
      if (isStaff) {
        data = {
          url: siteRoot,
          text: gettext('Exit System Admin') 
        };
      } else if (isOrgStaff) {
        data = {
          url: siteRoot,
          text: gettext('Exit Organization Admin')
        };
      } else if (isInstAdmin) {
        data = {
          url: siteRoot,
          text: gettext('Exit Institution Admin')
        };
      }

    } else {
      if (isStaff) {   
        data = {
          url: `${siteRoot}sys/info/`,
          text: gettext('System Admin')
        };
      } else if (isOrgStaff) {
        data = {
          url: `${siteRoot}org/useradmin/`,
          text: gettext('Organization Admin')
        };
      } else if (isInstAdmin) {
        data = {
          url: `${siteRoot}inst/useradmin/`,
          text: gettext('Institution Admin')
        };
      }
    }

    return data && <a href={data.url} title={data.text} className="item">{data.text}</a>;
  }


Through the content analysis of the English version, "System Admin" knows that we use the identity of system administrator. And no longer manage the panel.
We enter the management panel and check again: it has become exiting the management panel.

We use the system administrator to add an ordinary user 123@qq.com , observe its identity: ordinary users have no options for system management, so they can't touch the content related to background management. The security of this part needs to be tested. I wonder whether the developer tool or hacker bar can enter the background management by modifying the isStaff attribute in the state of ordinary users.

See the figure below:

Keywords: Javascript ECMAScript React

Added by Cloud on Sun, 31 Oct 2021 16:41:47 +0200