<commit_before>import React, { Component } from 'react'
import { Link } from 'react-router-dom'

import { Loading, DisplayDate } from './Common'
import Fetch from './Fetch'
import store from './Store'

class Users extends Component {
  constructor(props) {
    super(props)
    this.pageTitle = 'User Management'
    this.state = {
      loading: true,
      users: null,
    }
  }
  componentWillMount() {
    store.resetApiRequests()
  }

  componentDidMount() {
    document.title = this.pageTitle
    this._fetchUsers()
  }

  _fetchUsers = () => {
    this.setState({ loading: true })
    Fetch('/api/users/', { credentials: 'same-origin' }).then(r => {
      this.setState({ loading: false })
      if (r.status === 403 && !store.currentUser) {
        store.setRedirectTo(
          '/',
          `You have to be signed in to view "${this.pageTitle}"`
        )
        return
      }
      if (r.status === 200) {
        if (store.fetchError) {
          store.fetchError = null
        }
        return r.json().then(response => {
          this.setState({
            users: response.users,
            loading: false
          })
        })
      } else {
        store.fetchError = r
      }
    })
  }

  render() {
    return (
      <div>
        <h1 className="title">
          {this.pageTitle}
        </h1>
        {this.state.loading
          ? <Loading />
          : <DisplayUsers users={this.state.users} />}
      </div>
    )
  }
}

export default Users

class DisplayUsers extends Component {
  state = {
    filter: {
      q: ''
    }
  }

  onEdit = (event, id) => {
    event.preventDefault()
    this.props.editUser(id)
  }

  _resetFilter = event => {
    event.preventDefault()
    this.setState({
      filter: {
        q: ''
      }
    })
  }

  render() {
    const { users } = this.props
    if (!users) {
      return (
        <p>
          There are <b>no users</b>.
        </p>
      )
    }
    return (
      <table className="table">
        <thead>
          <tr>
            <th>Email</th>
            <th>Last Login</th>
            <th>Permissions</th>
            <th>Uploads</th>
            <th>API Tokens</th>
            <th />
          </tr>
        </thead>
        <tfoot>
          <tr>
            <th>
              <input
                type="search"
                className="input"
                value={this.state.filter.q}
                onChange={e => this.setState({ filter: { q: e.target.value } })}
                placeholder="Filter by email"
              />
            </th>
            <th />
            <th />
            <th />
            <th />
            <th>
              {this.state.filter.q &&
                <button
                  className="button is-primary"
                  onClick={this._resetFilter}
                >
                  Clear filter
                </button>}
            </th>
          </tr>
        </tfoot>
        <tbody>
          {users.map(user => {
            // Yeah, it's a unscalable hack to filter in render().
            // It's also not scalable to load ALL users into memory with AJAX.
            // There's not even pagination.
            if (this.state.filter.q) {
              // return null if the email doesn't match
              if (
                !user.email
                  .toLowerCase()
                  .includes(this.state.filter.q.toLowerCase())
              ) {
                return null
              }
            }
            return (
              <tr key={user.id}>
                <td>
                  {user.email}{' '}
                  {!user.is_active
                    ? <span className="tag is-danger">Not Active</span>
                    : null}
                </td>
                <td>
                  <DisplayDate date={user.last_login} /> <br />
                  <small>
                    (joined <DisplayDate date={user.date_joined} />)
                  </small>
                </td>
                <td>
                  {user.is_superuser
                    ? <span className="tag is-warning">Superuser</span>
                    : user.permissions.map(p =>
                        <code key={p.id} style={{ display: 'block' }}>
                          {p.name}
                        </code>
                      )}
                </td>
                <td>
                  {user.no_uploads}
                </td>
                <td><commit_msg>fixes bug 1388108 - Users might have last_login = null in User Management (#302)<commit_after>import React, { Component } from 'react'
import { Link } from 'react-router-dom'

import { Loading, DisplayDate } from './Common'
import Fetch from './Fetch'
import store from './Store'

class Users extends Component {
  constructor(props) {
    super(props)
    this.pageTitle = 'User Management'
    this.state = {
      loading: true,
      users: null,
    }
  }
  componentWillMount() {
    store.resetApiRequests()
  }

  componentDidMount() {
    document.title = this.pageTitle
    this._fetchUsers()
  }

  _fetchUsers = () => {
    this.setState({ loading: true })
    Fetch('/api/users/', { credentials: 'same-origin' }).then(r => {
      this.setState({ loading: false })
      if (r.status === 403 && !store.currentUser) {
        store.setRedirectTo(
          '/',
          `You have to be signed in to view "${this.pageTitle}"`
        )
        return
      }
      if (r.status === 200) {
        if (store.fetchError) {
          store.fetchError = null
        }
        return r.json().then(response => {
          this.setState({
            users: response.users,
            loading: false
          })
        })
      } else {
        store.fetchError = r
      }
    })
  }

  render() {
    return (
      <div>
        <h1 className="title">
          {this.pageTitle}
        </h1>
        {this.state.loading
          ? <Loading />
          : <DisplayUsers users={this.state.users} />}
      </div>
    )
  }
}

export default Users

class DisplayUsers extends Component {
  state = {
    filter: {
      q: ''
    }
  }

  onEdit = (event, id) => {
    event.preventDefault()
    this.props.editUser(id)
  }

  _resetFilter = event => {
    event.preventDefault()
    this.setState({
      filter: {
        q: ''
      }
    })
  }

  render() {
    const { users } = this.props
    if (!users) {
      return (
        <p>
          There are <b>no users</b>.
        </p>
      )
    }
    return (
      <table className="table">
        <thead>
          <tr>
            <th>Email</th>
            <th>Last Login</th>
            <th>Permissions</th>
            <th>Uploads</th>
            <th>API Tokens</th>
            <th />
          </tr>
        </thead>
        <tfoot>
          <tr>
            <th>
              <input
                type="search"
                className="input"
                value={this.state.filter.q}
                onChange={e => this.setState({ filter: { q: e.target.value } })}
                placeholder="Filter by email"
              />
            </th>
            <th />
            <th />
            <th />
            <th />
            <th>
              {this.state.filter.q &&
                <button
                  className="button is-primary"
                  onClick={this._resetFilter}
                >
                  Clear filter
                </button>}
            </th>
          </tr>
        </tfoot>
        <tbody>
          {users.map(user => {
            // Yeah, it's a unscalable hack to filter in render().
            // It's also not scalable to load ALL users into memory with AJAX.
            // There's not even pagination.
            if (this.state.filter.q) {
              // return null if the email doesn't match
              if (
                !user.email
                  .toLowerCase()
                  .includes(this.state.filter.q.toLowerCase())
              ) {
                return null
              }
            }
            return (
              <tr key={user.id}>
                <td>
                  {user.email}{' '}
                  {!user.is_active
                    ? <span className="tag is-danger">Not Active</span>
                    : null}
                </td>
                <td>
                  {user.last_login ? <DisplayDate date={user.last_login} /> : <i>never logged in</i> }
                  <br />
                  <small>
                    (joined <DisplayDate date={user.date_joined} />)
                  </small>
                </td>
                <td>
                  {user.is_superuser
                    ? <span className="tag is-warning">Superuser</span>
                    : user.permissions.map(p =>
                        <code key={p.id} style={{ display: 'block' }}>
                          {p.name}
                        </code>
                      )}
                </td>
                <td>
                  {user.no_uploads}
                </td>
                <td>
{'fraction_non_alphanumeric': 0.1294637921503593, 'fraction_numerical': 0.0028745163073521283, 'mean_word_length': 1.109608208955224, 'pattern_counts': {'":': 0, '<': 131, '<?xml version=': 0, '>': 147, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5861544', 'n_tokens_mistral': 2599, 'n_tokens_neox': 2492, 'n_words': 534}