<|start_filename|>client/src/actions/types.js<|end_filename|>
export const ERROR = 'error';
export const SUCCESS = 'success';
export const DATA = 'data';
export const FILE = 'file';

export const AUTH_USER = 'auth_user';
export const UNAUTH_USER = 'unauth_user';
export const AUTH_ERROR = 'auth_error';
export const CHANGEPASSWORD_ERROR = 'changepassword_error';
export const CHANGEPASSWORD_SUCCESS = 'changepassword_success';




<|start_filename|>client/src/components/Common/SystemMessages.js<|end_filename|>
import React from 'react';
import {connect} from 'react-redux'

class SystemMessages extends React.Component {
    destroyer = false;

    constructor(props) {
        super(props);
        this.state = {
            messages: []
        }
    }

    onClick = (index) => {
        let messages = this.state.messages;
        messages.splice(index, 1);
        if (!messages.length) {
            clearTimeout(this.destroyer);
            this.destroyer = false;
        }
        this.setState({
            messages: messages
        });
    };

    delayedRemove = () => {
        if (!this.destroyer)
            this.destroyer = setTimeout(() => {
                let messages = this.state.messages;
                messages.pop();
                this.setState({
                    messages: messages
                });
                clearTimeout(this.destroyer);
                this.destroyer = false;
                if (messages.length)
                    this.delayedRemove();
            }, 4000)
    };

    componentDidUpdate = (props) => {
        const error = props.system && props.system.error && props.system.error.data && props.system.error.data.error;
        const success = props.system && props.system.message;
        if (error || success) {
            let messages = this.state.messages || [];
            const message = error ? {type: 'error', ...error} : {type: 'success', ...success};
            messages.push(message);
            this.setState({
                messages: messages
            });
        }
    };

    render() {
        return (
            <div id="systemMessages">{
                this.state.messages.map((message, key) => {
                    const className = message.type === 'error' ? 'alert-danger' : 'alert-success';
                    return <div key={key}
                                className={"system-messages col-sm-12 col-md-6 col-lg-5 mx-auto alert alert-dismissible show "
                                + className}>
                        <i className="fa fa-exclamation-triangle mr-2"/>
                        <strong>{message.name}:</strong> {message.message}
                        <button type="button" className="close" data-dismiss="alert" aria-label="Close"
                                onClick={() => {
                                    this.onClick(key)
                                }}>
                            <span aria-hidden="true">&times;</span>
                        </button>
                        {this.delayedRemove(key)}
                    </div>
                })}
            </div>
        );
    }
}

const mapStateToProps = (state) => {
    return {system: state.system}
};

export default connect(mapStateToProps, null)(SystemMessages);


<|start_filename|>server/server.js<|end_filename|>
'use strict';

var loopback = require('loopback');
var boot = require('loopback-boot');
var errorHandler = require('strong-error-handler');

var app = module.exports = loopback();
app.use(loopback.token({
    model: app.models.accessToken,
    currentUserLiteral: 'me'
}));

app.use(errorHandler({
    debug: true,
    log: true,
}));

// Passport configurators..
var loopbackPassport = require('loopback-component-passport');
var PassportConfigurator = loopbackPassport.PassportConfigurator;
var passportConfigurator = new PassportConfigurator(app);

app.start = function () {
    // start the web server
    return app.listen(function () {
        app.emit('started');
        var baseUrl = app.get('url').replace(/\/$/, '');
        console.log('Web server listening at: %s', baseUrl);
        if (app.get('loopback-component-explorer')) {
            var explorerPath = app.get('loopback-component-explorer').mountPath;
            console.log('Browse your REST API at %s%s', baseUrl, explorerPath);
        }
    });
};

// Bootstrap the application, configure models, datasources and middleware.
// Sub-apps like REST API are mounted via boot scripts.
boot(app, __dirname, function (err) {
    if (err) console.log(err);//throw err;

    // start the server if `$ node server.js`
    if (require.main === module)
        app.start();
});


<|start_filename|>server/models/container.js<|end_filename|>
'use strict';

module.exports = function (Container) {

    Container.putContainer = function (container, cb) {

        Container.getContainer(container, function (err, c) {
            // if (err)
            //   return cb(err)
            if (c && c.name) {
                console.log('CONTAINER ALREADY EXIST', container);
                cb(null, c.name)
            }
            else {
                Container.createContainer({name: container}, function (err, c) {
                    if (err)
                        return cb(err);
                    console.log('CONTAINER CREATED', container);
                    cb(null, c.name)
                });
            }
        });


    };

};


<|start_filename|>client/src/actions/index.js<|end_filename|>
import Qs from 'qs';
import axios from 'axios';
import History from '../history.js';
import * as type from './types';

const API_URL = process.env.REACT_APP_API_URL;
const FILE_URL = process.env.REACT_APP_FILE_URL;
let TOKEN = localStorage.getItem('token');
let UID = localStorage.getItem('uid');

const errorBeautifier = error => {
  return error.hasOwnProperty('payload')
    ? error
    : {type: type.ERROR, payload: {data: {error: {name: 'Error', message: error.message}}}}
};

axios.interceptors.response.use(
  response => response,
  error => Promise.reject(error && error.response
    ? {type: type.ERROR, payload: error.response}
    : errorBeautifier(error))
);
axios.interceptors.request.use(config => {
  console.log(config);
  config.paramsSerializer = params => {
    // Qs is already included in the Axios package
    return Qs.stringify(params, {
      arrayFormat: "brackets",
      encode: false
    });
  };
  return config;
});

export const signUp = (data) => {
  return (dispatch) => {
    axios.post(`${API_URL}/users`, data)
      .then(() => {
        dispatch({
          type: type.SUCCESS,
          payload: {name: 'SUCCESS', message: 'Check your email for confirmation link.'}
        });
        setTimeout(() => {
          History.push('/signin')
        }, 1500);
      })
      .catch(error => dispatch(error));
  };
};

export const setSession = (response) => {
  //response.isAdmin = response.roles.find(x => x.name === 'admin');
  //response.isEditor = response.roles.find(x => x.name === 'editor');
  sessionStorage.setItem('me', JSON.stringify(response));
  return response;
};

export const signIn = (data) => {
  return async (dispatch) => {
    await axios.post(`${API_URL}/users/login`, data)
      .then(response => {
        localStorage.setItem('token', response.data.id);
        localStorage.setItem('uid', response.data.userId);
        localStorage.setItem('ttl', response.data.ttl);
        TOKEN = localStorage.getItem('token');
        UID = localStorage.getItem('uid');
        getUser(response.data.userId)
          .then(response => {
            dispatch({type: type.AUTH_USER, payload: setSession(response)});
            History.push('/home');
          })
          .catch(error => dispatch(error));
      })
      .catch(error => dispatch(error));
  };
};

export const signOut = () => {
  return (dispatch) => {
    localStorage.removeItem('token');
    sessionStorage.removeItem('me');
    TOKEN = null;
    dispatch({
      type: type.UNAUTH_USER,
      payload: null
    });
    History.push('/');
  }
};

export const resetPasswordRequest = (email) => {
  return (dispatch) => {
    axios.post(`${API_URL}/users/reset`, {email})
      .then(() => {
        dispatch({
          type: type.SUCCESS,
          payload: {name: 'SUCCESS', message: 'We sent an email to you. Please check your email.'}
        })
      })
      .catch(error => dispatch(error));
  };
};

export const resetPassword = ({token, password}) => {
  return (dispatch) => {
    axios.post(`${API_URL}/users/reset-password`, {newPassword: password}, {
      headers: {authorization: token}
    })
      .then(() => {
        dispatch({
          type: type.SUCCESS,
          payload: {name: 'SUCCESS', message: 'You has been changed your password successfully.'}
        });
        setTimeout(() => {
          History.push('/signin')
        }, 1500);
      })
      .catch(error => dispatch(error));
  };
};

function computeUser(user) {
  user = user || {roles: []};
  user.isAdmin = user.roles.find(x => x.name === 'admin');
  user.isEditor = user.roles.find(x => x.name === 'editor');
  user.isManager = user.roles.find(x => x.name === 'manager');
  user.isWorker = user.roles.find(x => x.name === 'worker');
  user.icon = user.isAdmin ? 'fas fa-user-astronaut'
    : user.isEditor ? 'fa fa-user-secret'
      : user.isManager || user.isWorker ? 'fa fa-user-tie' : 'fa fa-user';
  if (typeof user.image === 'object') {
    user.image.thumb = FILE_URL + user.image.normal;
    user.image.normal = FILE_URL + user.image.normal;
    user.image.url = FILE_URL + user.image.url;
  } else {
    user.image = {
      thumb: 'http://holder.ninja/50x50,P.svg',
      normal: 'http://holder.ninja/250x250,PROFILE.svg',
      url: 'http://holder.ninja/500x500,PROFILE.svg'
    };
  }
  if (typeof user.cover === 'object') {
    user.cover.thumb = FILE_URL + user.cover.normal;
    user.cover.normal = FILE_URL + user.cover.normal;
    user.cover.url = FILE_URL + user.cover.url;
  } else {
    user.cover = {
      thumb: 'http://holder.ninja/400x120,COVER-1200x360.svg',
      normal: 'http://holder.ninja/1200x360,COVER-1200x360.svg',
      url: 'http://holder.ninja/1200x360,COVER-1200x360.svg'
    };
  }
  return user;
}

export const getUser = (uid) => {
  return new Promise((resolve, reject) => {
    axios.get(`${API_URL}/users/${uid}`, {
      headers: {authorization: localStorage.getItem('token')}
    })
      .then(response => {
        resolve(computeUser(response.data))
      })
      .catch(error => {
        reject(error.response && error.response.data && error.response.data.error)
      });
  });
};

export const fetchUser = (id) => {
  return (dispatch) => {
    axios.get(`${API_URL}/users/${id}`, {
      headers: {authorization: localStorage.getItem('token')}
    })
      .then(response => {
        dispatch({type: type.DATA, payload: computeUser(response.data)});
      })
      .catch(error => dispatch(error));
  }
};

export const searchUserByName = async (name) => {
  const query = JSON.stringify({where: {name: {like: name, options: 'i'}}});
  try {
    const response = await axios.get(`${API_URL}/users?filter=${query}`, {
      headers: {authorization: localStorage.getItem('token')}
    });
    console.log('searchUserByName', response);
    return response.data
  } catch (error) {
    throw error
  }
};

export const getProfile = (username) => {
  return (dispatch) => {
    axios.get(`${API_URL}/users/profile/${username}`, {
      headers: {authorization: localStorage.getItem('token')}
    })
      .then(response => {
        dispatch({type: type.DATA, payload: computeUser(response.data.user)});
      })
      .catch(error => {
        dispatch(errorBeautifier(error))
      });
  }

  // return new Promise((resolve, reject) => {
  //     axios.get(`${API_URL}/users/profile/${username}`, {
  //         headers: {authorization: localStorage.getItem('token')}
  //     })
  //         .then(response => {
  //             resolve(computeUser(response.data.user))
  //         })
  //         .catch(error => {
  //             reject(error.response.data.error)
  //         });
  // });
};

export const getSession = (callback) => {
  const token = localStorage.getItem('token');
  const me = sessionStorage.getItem('me');
  if (token) {
    if (me) {
      callback(JSON.parse(me));
    } else {
      getUser(localStorage.getItem('uid'))
        .then((response) => {
          callback(setSession(response))
        })
        .catch((error) => {
          localStorage.removeItem('token');
          localStorage.removeItem('uid');
          localStorage.removeItem('ttl');
          window.location.reload(true);
          throw error;
        });
    }
  } else callback(null)
};

export const addUser = (data) => {
  return (dispatch) => {
    axios.post(`${API_URL}/users`, data)
      .then(() => {
        History.push('/users');
      })
      .catch(error => dispatch(error));
  };
};

export const settingsAccount = (data) => {
  return (dispatch) => {
    axios.patch(`${API_URL}/users/${UID}`, data,
      {headers: {authorization: TOKEN}})
      .then(response => {
        dispatch({type: type.AUTH_USER, payload: setSession(computeUser(response.data))});
        dispatch({
          type: type.SUCCESS,
          payload: {name: 'SUCCESS', message: 'Your account has been updated successfully!'}
        });
      })
      .catch(error => dispatch(error));
  };
};

export const settingsChangePassword = ({oldPassword, newPassword}) => {
  return (dispatch) => {
    axios.post(`${API_URL}/users/change-password`, {oldPassword, newPassword},
      {headers: {authorization: localStorage.getItem('token')}})
      .then(() => {
        dispatch({
          type: type.SUCCESS,
          payload: {name: 'SUCCESS', message: 'Your password has been changed successfully!'}
        });
      })
      .catch(error => dispatch(error));
  }
};

export const getUsers = () => {
  return (dispatch) => {
    axios.get(`${API_URL}/users`, {
      headers: {authorization: localStorage.getItem('token')}
    })
      .then(response => {
        dispatch({type: type.DATA, payload: response.data.map(user => computeUser(user))});
      })
      .catch(error => dispatch(error));
  }
};

export const fetchUsers = (params = {}) => {
  return (dispatch) => {
    axios.get(`${API_URL}/users/list`, {
      headers: {authorization: localStorage.getItem('token')},
      params
    })
      .then(response => {
        response.data.list.items.map(user => computeUser(user));
        dispatch({type: type.DATA, payload: response.data.list});
      })
      .catch(error => dispatch(error));
  }
};

export const updateUser = async (data) => {
  await axios.patch(`${API_URL}/users/${data.id}`, data,
    {headers: {authorization: TOKEN}})
    .then(response => {
      return response.data
    })
    .catch(error => {
      throw error.response.data.error.message;
    });
};

export const toggleAdmin = (id, toggleType = 'Admin') => {
  return (dispatch) => {
    axios.post(`${API_URL}/users/${id}/toggle${toggleType}`, {id},
      {headers: {authorization: TOKEN}})
      .then(response => {
        dispatch({type: type.DATA, payload: computeUser(response.data.data)});
      })
      .catch(error => {
        dispatch({
          type: type.ERROR,
          payload: error.response
        });
      });
  }
};

export const toggleEditor = (id) => {
  return toggleAdmin(id, 'Editor')
};

export const toggleManager = (id) => {
  return toggleAdmin(id, 'Manager')
};

export const toggleWorker = (id) => {
  return toggleAdmin(id, 'Worker')
};

export const toggleStatus = (id) => {
  return toggleAdmin(id, 'Status')
};

export const uploadCoverImage = (file) => {
  return async (dispatch) => {
    await axios.post(`${API_URL}/users/${UID}/cover`, file, {
      headers: {authorization: TOKEN},
      onUploadProgress: progressEvent => {
        console.log(progressEvent.loaded, progressEvent.total)
      }
    })
      .then(response => {
        dispatch({type: type.AUTH_USER, payload: setSession(computeUser(response.data.user))});
      })
      .catch(error => dispatch(error));
  };
};

export const uploadProfileImage = (file) => {
    return async (dispatch) => {
        await axios.post(`${API_URL}/users/${UID}/image`, file, {
            headers: {authorization: TOKEN},
            onUploadProgress: progressEvent => {
                console.log(progressEvent.loaded, progressEvent.total)
            }
        })
            .then(response => {
                dispatch({type: type.AUTH_USER, payload: setSession(computeUser(response.data.user))});
            })
            .catch(error => dispatch(error));
    };
};



<|start_filename|>client/src/components/Auth/SignIn/SignIn.js<|end_filename|>
import React from 'react';
import {Link} from 'react-router-dom';
import {Field, Form, withFormik} from 'formik'
import * as Yup from 'yup'
import {signIn} from '../../../actions'
import {connect} from 'react-redux'

let setSubmittingHigher;
const FormikForm = ({
                        values,
                        touched,
                        errors,
                        isSubmitting
                    }) => (
    <section className="cover bg-light">
        <div className="container">
            <div className="row h-100 justify-content-md-center">
                <div className="col-sm-4 my-auto">
                    <Form className="card border-0 p-4 shadow">
                        <h1 className="h4 lined"><span>SIGN IN</span></h1>
                        <fieldset className="form-group">
                            <label className="small">Username or Email</label>
                            <Field className="form-control" type="text" name="username" placeholder="Username"/>
                            {touched.email && errors.email &&
                            <small className="form-text text-danger">{errors.email}</small>}
                        </fieldset>
                        <fieldset className="form-group">
                            <label className="small">Password</label>
                            <Field className="form-control" type="password" name="password" placeholder="Password"/>
                            {touched.password && errors.password &&
                            <small className="form-text text-danger">{errors.password}</small>}
                        </fieldset>
                        <button className="btn btn-primary w-100" type="submit" disabled={isSubmitting}>
                            {isSubmitting && <span><i className="fa fa-circle-notch fa-spin"/>&nbsp;</span>}
                            Login
                        </button>
                        <p className="pt-4 text-center small">You can <Link to="/signup">sign up</Link> easly
                            if you don't have an account yet. Or you have an issue about sign in you can
                            reset your password <Link to="/reset">here</Link></p>
                    </Form>
                </div>
            </div>
        </div>
    </section>
);

const EnhancedForm = withFormik({
    mapPropsToValues({username}) {
        return {
            username: username || '',
            password: ''
        }
    },
    validationSchema: Yup.object().shape({
        username: Yup.string().required('Email/username is required'),
        // password: Yup.string().min(8, 'Password must be 8 characters or longer')
        //   .matches(/[a-z]/, 'Password must contain at least one lowercase char')
        //   .matches(/[A-Z]/, 'Password must contain at least one uppercase char')
        //   .matches(/[a-zA-Z]+[^a-zA-Z\s]+/, 'at least 1 number or special char (@,!,#, etc).'),
    }),
    handleSubmit(values, {props, resetForm, setFieldError, setSubmitting}) {
        if (values.username.match(/^[A-z0-9._%+-]+@[A-z0-9.-]+\.[A-z0-9.]{2,}$/))
            values = {email: values.username, password: <PASSWORD>};
        setSubmittingHigher = setSubmitting;
        props.signIn(values);
    },
})(FormikForm);

const mapStateToProps = (state) => {
    typeof setSubmittingHigher === 'function' && setSubmittingHigher(false);
    return {system: state.system}
};

const mapDispatchToProps = (dispatch) => {
    return {
        signIn: (values) => {
            dispatch(signIn(values));
        },
    }
};

export default connect(mapStateToProps, mapDispatchToProps)(EnhancedForm);


<|start_filename|>client/src/components/StaticPages/TermsOfService.js<|end_filename|>
import React, {Component} from 'react';

class TermsOfService extends Component {
    render() {
        return <section id="termsOfService">
            <div className="container">
                <h1 className="h3">Terms of Service</h1>
                <hr className="border-primary"/>
                <p>This is a static page.</p>
            </div>
        </section>;
    }
}

export default TermsOfService;


<|start_filename|>client/src/components/Common/ToggleButton.js<|end_filename|>
import React from 'react';

class ToggleButton extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            textActive: props.textActive,
            textPassive: props.textPassive,
            classActive: props.classActive || 'btn btn-default text-primary',
            classPassive: props.classPassive || 'btn btn-default',
            iconActive: props.iconActive || 'fa fa-check',
            iconPassive: props.iconPassive || 'fa fa-times',
            iconLoading: props.iconLoading || 'fa fa-circle-notch fa-spin',
            status: props.status,
            loading: props.loading
        }
    }

    onClick = (e) => {
        e.preventDefault();
        this.setState({
            loading: true
        });
        this.props.toggleFunction()
            // .then(response => {
            //     console.log('toggleFunction', this.state.textActive);
            //     // this.setState({
            //     //     status: typeof response === 'boolean' ? response : this.state.status,
            //     //     loading: false
            //     // });
            // })
    };

    componentDidUpdate = (props) => {
        this.setState({
            status: props.status,
            loading: false
        });
    };

    render() {
        //console.log('status', this.state.status, this.props.toggleFunction);
        const text = this.state.status ? this.state.textActive : this.state.textPassive;
        const className = this.state.status ? this.state.classActive : this.state.classPassive;
        const icon = this.state.loading ? this.state.iconLoading
            : this.state.status ? this.state.iconActive : this.state.iconPassive;
        return (
            <button style={{...this.props.style}}
                    ref={this.props.forwardref ? this.props.forwardref : null}
                    className={className + ' ' + this.props.className} onClick={this.onClick}>
                <i className={icon}/> {text}
            </button>
        );
    }
}


export default React.forwardRef((props, ref) =>
    (
        <ToggleButton {...props} forwardref={ref}/>
    )
)



<|start_filename|>client/src/components/Users/List.js<|end_filename|>
import React, {Component} from 'react';
import {Link} from 'react-router-dom';
import {connect} from 'react-redux';
import {fetchUsers} from '../../actions';
import Pagination from "../Common/Pagination";
import History from "../../history";
import {Input} from "reactstrap";

class List extends Component {

  constructor(props) {
    super(props);
    const params = new URLSearchParams(props.location.search);
    const search = params.get('search') || '';
    const page = params.get('page') || 1;
    this.state = {
      me: props.me,
      count: 0,
      page,
      limit: 10,
      range: 10,
      items: [],
      query: search,
      search: search,
      filteredItems: false,
    }
  }

  componentDidMount() {
    if (!this.state.me)
      return History.push('/signin');
    console.log('componentDidMount', this.state);
    if (this.state.query) {
      const filter = {skip: Math.max(0, this.state.page - 1) * this.state.limit, limit: this.state.limit};
      this.props.fetchList({query: this.state.query, filter});
    } else {
      this.props.fetchList();
    }
  }

  componentDidUpdate(props) {
    const params = new URLSearchParams(props.location.search);
    const search = params.get('search') || '';
    const page = params.get('page') || 1;
    console.log('componentDidUpdate', props);

    if (page !== this.state.page) {
      console.log('page', props);
      const filter = {skip: Math.max(0, page - 1) * this.state.limit, limit: this.state.limit};
      this.setState({page: page});
      this.props.fetchList({query: this.state.query, filter});
    } else if (search !== this.state.search) {
      console.log('search', props);
      this.setState({search});
      this.props.fetchList({query: search});
    }

    if (props.data && props.data.items) {
      this.setState({
        isLoading: false,
        count: props.data.count,
        items: props.data.items,
        filteredItems: false
      });
    }
  }

  handleFilter = (e) => {
    e.preventDefault();
    console.log(e.currentTarget.value);
    const query = e.currentTarget.value.toLowerCase();
    const filteredItems = this.state.items.filter(item => {
      console.log({item});
      return (item.name.toLowerCase().indexOf(query) > -1 || item.surname.toLowerCase().indexOf(query) > -1
        || item.username.toLowerCase().indexOf(query) > -1 || item.email.toLowerCase().indexOf(query) > -1)
    });
    this.setState({query, filteredItems});
  };

  handleSearch = (e) => {
    e.preventDefault();
    console.log(e.key);
    if (e.key === 'Enter')
      return History.push('?search=' + this.state.query);
  };

  renderItems() {
    return (this.state.filteredItems || this.state.items).map(user => {
      return <div className="col-sm-4" key={user.id}>
        <div className="card mb-2">
          <div className="card-body p-2">
            <img className="img-thumbnail rounded-circle float-left mr-2"
                 src={user.image.thumb} alt={user.name}
                 width="100"
            />
            <div className="">
              <h3 className="h5 card-title">
                <i className={user.icon}/>&nbsp;&nbsp;{user.username}</h3>
              <p>
                <small>{user.name} {user.surname}</small>
              </p>
              <div className="text-right">
                <Link to={user.username} className="btn btn-sm btn-primary">PROFILE</Link>
                {(this.props.me.isAdmin || this.props.me.isEditor) &&
                <Link to={'/users/edit/' + user.id} className="btn btn-sm btn-success ml-1">EDIT</Link>}
              </div>
            </div>
          </div>
        </div>
      </div>;
    })
  }

  render() {
    if (!this.state.items) {
      return <div>Loading...</div>;
    }
    return (<React.Fragment>
        <div className="list">
          <div className="searchInput text-right pr-4">
            <Input type="text" className="form-control-sm" placeholder="Filter or Search..." value={this.state.query}
                   onKeyUp={this.handleSearch} onChange={this.handleFilter}/>
            <small className="text-muted">Total result: {this.state.count}</small></div>
          <div className="row">
            {this.renderItems()}
          </div>
          {this.state.count &&
          <Pagination page={this.state.page} count={this.state.count}
                      limit={this.state.limit} range={this.state.range}
                      query={{search: this.state.search}}/>}
        </div>
      </React.Fragment>
    );
  }
}

const mapStateToProps = (state) => {
  return {me: state.auth.me, data: state.system.data}
};

const mapDispatchToProps = (dispatch) => {
  return {
    fetchList: (params) => {
      dispatch(fetchUsers(params));
    },
  }
};

export default connect(mapStateToProps, mapDispatchToProps)(List);


<|start_filename|>server/boot/init.js<|end_filename|>
'use strict';

module.exports = (app) => {
    if (!app.get('initialData')) return;

    const User = app.models.user;
    const Role = app.models.Role;
    const RoleMapping = app.models.RoleMapping;
    // create a user
    User.findOrCreate({where: {email: '<EMAIL>'}},
        {
            name: 'Admin',
            surname: '-',
            username: 'admin',
            email: '<EMAIL>',
            password: '<PASSWORD>',
            emailVerified: true
        }
        , function (err, user) {
            if (err) console.log('ERROR', err);
            console.log('Created user:', user);

            //create the admin role
            Role.findOrCreate({where: {name: 'admin'}}, {
                name: 'admin'
            }, function (err, role) {
                if (err) console.log('ERROR', err);

                // make an admin user
                RoleMapping.findOrCreate({
                    where: {
                        principalId: user.id,
                        roleId: role.id
                    }
                }, {
                    principalType: RoleMapping.USER,
                    principalId: user.id,
                    roleId: role.id
                }, function (err, principal) {
                    if (err) console.log('ERROR', err);
                    console.log('Created principal:', principal);
                });
            });
        });

    User.findOrCreate({where: {email: '<EMAIL>'}},
        {
            name: 'Editor',
            surname: '-',
            username: 'editor',
            email: '<EMAIL>',
            password: '<PASSWORD>',
            emailVerified: true
        }
        , function (err, user) {
            if (err) console.log('ERROR', err);
            console.log('Created user:', user);

            //create the editor role
            Role.findOrCreate({where: {name: 'editor'}}, {
                name: 'editor'
            }, function (err, role) {
                if (err) console.log('ERROR', err);

                // make an editor user
                RoleMapping.findOrCreate({
                    where: {
                        principalId: user.id,
                        roleId: role.id
                    }
                }, {
                    principalType: RoleMapping.USER,
                    principalId: user.id,
                    roleId: role.id
                }, function (err, principal) {
                    if (err) console.log('ERROR', err);
                    console.log('Created principal:', principal);
                });
            });
        });

    User.findOrCreate({where: {email: '<EMAIL>'}},
        {
            name: 'Manager',
            surname: '-',
            username: 'manager',
            email: '<EMAIL>',
            password: '<PASSWORD>',
            emailVerified: true
        }
        , function (err, user) {
            if (err) console.log('ERROR', err);
            console.log('Created user:', user);

            //create the editor role
            Role.findOrCreate({where: {name: 'manager'}}, {
                name: 'manager'
            }, function (err, role) {
                if (err) console.log('ERROR', err);

                // make an editor user
                RoleMapping.findOrCreate({
                    where: {
                        principalId: user.id,
                        roleId: role.id
                    }
                }, {
                    principalType: RoleMapping.USER,
                    principalId: user.id,
                    roleId: role.id
                }, function (err, principal) {
                    if (err) console.log('ERROR', err);
                    console.log('Created principal:', principal);
                });
            });
        });

    User.findOrCreate({where: {email: '<EMAIL>'}},
        {
            name: 'Worker',
            surname: '-',
            username: 'worker',
            email: '<EMAIL>',
            password: '<PASSWORD>',
            emailVerified: true
        }
        , function (err, user) {
            if (err) console.log('ERROR', err);
            console.log('Created user:', user);

            //create the editor role
            Role.findOrCreate({where: {name: 'worker'}}, {
                name: 'worker'
            }, function (err, role) {
                if (err) console.log('ERROR', err);

                // make an editor user
                RoleMapping.findOrCreate({
                    where: {
                        principalId: user.id,
                        roleId: role.id
                    }
                }, {
                    principalType: RoleMapping.USER,
                    principalId: user.id,
                    roleId: role.id
                }, function (err, principal) {
                    if (err) console.log('ERROR', err);
                    console.log('Created principal:', principal);
                });
            });
        });


    User.findOrCreate({where: {email: '<EMAIL>'}},
        {
            name: 'User',
            surname: '-',
            username: 'user',
            email: '<EMAIL>',
            password: '<PASSWORD>',
            emailVerified: true
        }
        , function (err, user) {
            if (err) console.log('ERROR', err);
            console.log('Created user:', user);
        });

};


<|start_filename|>client/src/reducers/index.js<|end_filename|>
import {combineReducers} from 'redux';
import {reducer as systemReducer} from './system';
import {reducer as authReducer} from './auth';
import {reducer as settingsReducer} from './settings';

const rootReducer = combineReducers({
    system: systemReducer,
    auth: authReducer,
    settings: settingsReducer
});

export default rootReducer;


<|start_filename|>client/src/components/Users/Edit.js<|end_filename|>
import React, {Component} from 'react';
import {Field, Form, Formik} from 'formik'
import * as Yup from 'yup'
import {
    fetchUser,
    getUser,
    toggleAdmin,
    toggleEditor,
    toggleManager,
    toggleStatus,
    toggleWorker,
    updateUser
} from '../../actions'
import {connect} from 'react-redux'
import ToggleButton from "../Common/ToggleButton";

const FormikForm = ({
                        values,
                        touched,
                        errors,
                        status,
                        isSubmitting
                    }) => (
    <Form>
        <fieldset className="form-group">
            <Field className="form-control" type="text" name="username" placeholder="Username"/>
            {touched.username && errors.username && <small className="form-text text-danger">{errors.username}</small>}
        </fieldset>
        <fieldset className="form-group">
            <Field className="form-control" type="text" name="email" placeholder="<EMAIL>"/>
            {touched.email && errors.email && <small className="form-text text-danger">{errors.email}</small>}
        </fieldset>
        <div className="row">
            <fieldset className="col-md-6 form-group">
                <label>Name</label>
                <Field className="form-control" type="text" name="name" placeholder="Name"/>
                {touched.name && errors.name && <small className="form-text text-danger">{errors.name}</small>}
            </fieldset>
            <fieldset className="col-md-6 form-group">
                <label>Surname</label>
                <Field className="form-control" type="text" name="surname" placeholder="Surname"/>
                {touched.surname && errors.surname && <small className="form-text text-danger">{errors.surname}</small>}
            </fieldset>
        </div>
        <fieldset className="form-group">
            <Field className="form-control" component="textarea" name="bio"
                   placeholder="Write something short about you"/>
            {touched.bio && errors.bio && <small className="form-text text-danger">{errors.bio}</small>}
        </fieldset>
        {status && status.error && <div className="alert alert-danger">
            <small>{status.error}</small>
        </div>}
        {status && status.success && <div className="alert alert-success">
            <small>{status.success}</small>
        </div>}
        <input type="hidden" name="id" value={values.id}/>
        <button className="btn btn-primary" type="submit" disabled={isSubmitting}>
            {isSubmitting && <span><i className="fa fa-circle-notch fa-spin"/>&nbsp;</span>}
            Update the Account
        </button>
    </Form>);

class EnhancedForm extends Component {
    constructor(props) {
        super(props);
        this.state = {
            user: props.user || {},
            // user: {
            //     id: '',
            //     username: '',
            //     email: '',
            //     name: '',
            //     surname: '',
            //     bio: '',
            //     roles: []
            // },
            error: null
        }
    }

    getUserData(id) {
        if (!this.state.user || id !== this.state.user.id)
            getUser(id)
                .then(user => {
                    this.setState({user: user})
                })
                .catch(error => {
                    this.setState({'error': error})
                })
    }

    componentDidMount() {
        this.props.getUser(this.props.match.params.id);
        // if (!this.props.me || (!this.props.me.isAdmin && !this.props.me.isEditor))
        //     return History.goBack();
        // this.getUserData(this.props.match.params.id)
    }

    componentDidUpdate = (props) => {
        if (props.user && this.props.user !== props.user)
            this.setState({
                user: props.user,
                loading: false
            });
    };

    async handleSubmit(values, {props, setFieldError, setSubmitting, setStatus}) {
        setStatus(null);
        try {
            await updateUser(values);
            setStatus({'success': 'Your account has been updated successfully!'});
            setSubmitting(false);
        } catch (errors) {
            setStatus({'error': errors})
            setSubmitting(false);
        }
    }

    toggleAdmin(id) {
        this.setState({
            error: null,
        });
        this.props.toggleAdmin(id)
    }

    toggleEditor(id) {
        this.setState({
            error: null,
        });
        this.props.toggleEditor(id)
    }

    toggleManager(id) {
        this.setState({
            error: null,
        });
        this.props.toggleManager(id)
    }

    toggleWorker(id) {
        this.setState({
            error: null,
        });
        this.props.toggleWorker(id)
    }

    toggleStatus(id) {
        this.setState({
            error: null,
        });
        this.props.toggleStatus(id)
    }


    render() {
        return (
            <div className="row justify-content-md-center">
                <div className="col-md-6">
                    <Formik component={FormikForm}
                            enableReinitialize="true"
                            initialValues={{
                                id: this.state.user.id || '',
                                username: this.state.user.username || '',
                                email: this.state.user.email || '',
                                name: this.state.user.name || '',
                                surname: this.state.user.surname || '',
                                bio: this.state.user.bio || '',
                            }}
                            validationSchema={Yup.object().shape({
                                username: Yup.string().required('Username is required'),
                                email: Yup.string().email('Please write a correct email address').required('Email is required'),
                                name: Yup.string().required('Name is required'),
                                surname: Yup.string().required('Surname is required'),
                                bio: Yup.string().max(200, 'Short bio must be under 200 characters or shorter')
                            })}
                            onSubmit={this.handleSubmit}/>
                    <hr/>
                    <div>
                        {this.state.error && <div className="alert alert-danger" role="alert">{this.state.error}</div>}
                        <table className="table">
                            <tbody>
                                <tr>
                                    <th>Admin</th>
                                    <th>Editor</th>
                                    <th>Manager</th>
                                    <th>Worker</th>
                                    <th>Status</th>
                                </tr>
                                <tr>
                                    <td>
                                        <ToggleButton status={this.state.user.isAdmin}
                                                      toggleFunction={() => this.toggleAdmin(this.state.user.id)}/>
                                    </td>
                                    <td>
                                        <ToggleButton status={this.state.user.isEditor}
                                                      toggleFunction={() => this.toggleEditor(this.state.user.id)}/>
                                    </td>
                                    <td>
                                        <ToggleButton status={this.state.user.isManager}
                                                      toggleFunction={() => this.toggleManager(this.state.user.id)}/>
                                    </td>
                                    <td>
                                        <ToggleButton status={this.state.user.isWorker}
                                                      toggleFunction={() => this.toggleWorker(this.state.user.id)}/>
                                    </td>
                                    <td>
                                        <ToggleButton status={this.state.user.status}
                                                      toggleFunction={() => this.toggleStatus(this.state.user.id)}/>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>)
    }
}

const mapStateToProps = (state) => {
    return {me: state.auth.me, user: state.system.data}
};

const mapDispatchToProps = (dispatch) => {
    return {
        getUser: (values) => {
            dispatch(fetchUser(values));
        },
        toggleAdmin: (values) => {
            dispatch(toggleAdmin(values));
        },
        toggleEditor: (values) => {
            dispatch(toggleEditor(values));
        },
        toggleManager: (values) => {
            dispatch(toggleManager(values));
        },
        toggleWorker: (values) => {
            dispatch(toggleWorker(values));
        },
        toggleStatus: (values) => {
            dispatch(toggleStatus(values));
        },
    }
};

export default connect(mapStateToProps, mapDispatchToProps)(EnhancedForm);


<|start_filename|>client/src/components/Common/Navbar.js<|end_filename|>
import React, {PureComponent} from 'react';
import {connect} from 'react-redux';
import {Link} from 'react-router-dom';
import SystemMessages from './SystemMessages';
import logo from '../../styles/img/logo.svg';

class Navbar extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      me: props.me,
      shrink: !!props.me
    };
  }

  static dropDownToggle(e) {
    const dd = e.currentTarget;
    dd.classList.toggle('show');
    dd.querySelector('.dropdown-menu').classList.toggle('show');
  }

  static Shrink(e, shrink) {
    const navbar = document.getElementById('navbar');
    if (shrink || window.pageYOffset > 1) {
      navbar.classList.add("navbar-shrink");
    } else {
      navbar.classList.remove("navbar-shrink");
    }
  }

  componentDidMount() {
    Navbar.Shrink(null, this.state.shrink);
    if (!this.state.shrink)
      window.addEventListener('scroll', Navbar.Shrink);
  }

  componentDidUpdate(props) {
    this.setState({
      me: props.me,
      shrink: !!props.me
    });
    Navbar.Shrink(null, props.me);
    if (props.me)
      window.removeEventListener('scroll', Navbar.Shrink);
    else
      window.addEventListener('scroll', Navbar.Shrink);
  }


  renderLogo() {
    return <Link to={this.state.me ? "/home" : "/"} className="navbar-brand" key="logo">
      <img src={logo} className="img-fluid" alt="logo"/>
    </Link>
  }

    renderLinks() {
        if (this.state.me) {
            return <React.Fragment>
                <li className="nav-item" key="users">
                    <Link className="nav-link" to="/users">Users</Link>
                </li>
                {this.state.me.isWorker &&
                <li className="nav-item">
                    <Link className="nav-link" to="/sales-slips">Sales Slips</Link>
                </li>}
            </React.Fragment>
        } else {
            return [<li className="nav-item" key="features">
                <Link className="nav-link" to="/features">Features</Link>
            </li>];
        }
    }

  renderUserMenu() {
    if (this.state.me && this.state.me.image) {
      return [
        <li className="nav-item dropdown" key="userMenu" onClick={Navbar.dropDownToggle}>
          <span className="nav-link dropdown-toggle" data-toggle="dropdown">
              <img className="navbar-avatar"
                   src={this.state.me.image.thumb} alt={this.state.me.name}/>
            <i className={this.state.me.icon}/> <strong>{this.state.me.name}</strong>
          </span>
          <div className="dropdown-menu">
            <Link className="dropdown-item" to="/profile">Profile</Link>
            <Link className="dropdown-item" to="/settings">Settings</Link>
            <div className="dropdown-divider"/>
            <Link className="dropdown-item" to="/signout">Log out</Link>
          </div>
        </li>
      ];
    } else {
      return [
        <li className="nav-item" key="signin">
          <Link className="nav-link" to="/signin">Sign In</Link>
        </li>,
        <li className="nav-item" key="signup">
          <Link className="nav-link" to="/signup">Sign Up</Link>
        </li>
      ];
    }
  }

  render() {
    return (
      <nav id="navbar" className="navbar navbar-expand-lg navbar-light fixed-top">
        <div className="container">
          {this.renderLogo()}
          <button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarMain"
                  aria-controls="navbarMain" aria-expanded="false" aria-label="Toggle navigation">
            <span className="navbar-toggler-icon"/>
          </button>

          <div className="collapse navbar-collapse" id="navbarMain">
            <ul className="navbar-nav mr-auto">
              <li className="nav-item" key="about">
                <Link className="nav-link" to="/#about">About</Link>
              </li>
              {this.renderLinks()}
            </ul>

            <ul className="nav navbar-nav navbar-right">
              {this.renderUserMenu()}
            </ul>
          </div>
        </div>
        <SystemMessages/>
      </nav>
    );
  }
}

const mapStateToProps = (state) => {
  return {me: state.auth.me}
}

export default connect(mapStateToProps)(Navbar);


<|start_filename|>client/src/components/Welcome/Welcome.js<|end_filename|>
import React, {Component} from 'react';

class Welcome extends Component {
  render() {
    return <React.Fragment>
      <header className="intro">
        <div className="container">
          <div className="intro-text">
            <h2 className="intro-lead-in">Welcome,</h2>
            <h1 className="intro-heading text-uppercase">The FullStack <br/>React + LB3 <br/><span
              className="highlight">Playground</span></h1>
            <a className="btn btn-primary btn-xl text-uppercase js-scroll-trigger" href="#about">Tell Me
              More</a>
          </div>
        </div>
      </header>
      <section id="about" className="container">
        <div className="row justify-content-center">
          <div className="col-md-4">
          </div>
          <div className="col-md-8">
            <h2 className="section-heading">ABOUT</h2>
            <h3 className="section-subheading text-muted">This is a default static page and no need
              authentication.</h3>
            <p>Hi, I'm Goker and I'm developing the project for experience a full-stack React application
              with LoopBack - Node.js framework. If you want to contribute you can reach me freely via <a
                href="https://goker.me"
                rel="noopener noreferrer"
                target="_blank">goker.me</a></p>
          </div>
        </div>
      </section>
    </React.Fragment>;
  }
}

export default Welcome;


<|start_filename|>client/src/components/Common/Pagination.js<|end_filename|>
import React from 'react';
import {Link} from 'react-router-dom';
import {Pagination, PaginationItem} from 'reactstrap';

class CustomPagination extends React.Component {

  constructor(props) {
    super(props);
    const totalPages = Math.ceil(props.count / props.limit);
    const range = Math.min(totalPages, props.range);
    const center = totalPages > range ? Math.ceil(range / 2) : range;
    const start = (props.page > center ? (props.page >= totalPages - center ? totalPages - range : props.page - center) : 1);
    const end = totalPages > range ? (start + range) : (start + range - 1);
    this.state = {
      range,
      center,
      start,
      end,
      page: props.page,
      query: props.query,
      totalPages
    };
  }

  pageNumbers = () => {
    let pages = [];
    for (let i = this.state.start; i <= this.state.end; i++) {
      const query = new URLSearchParams({...this.state.query, page: i});
      const isActive = i === parseInt(this.state.page);
      pages.push(<PaginationItem key={i} active={isActive}>
        <Link className={"page-link " + (isActive && "text-white")} to={'?' + query.toString()}>{i}</Link>
      </PaginationItem>)
    }
    return pages
  };

  componentDidUpdate = (props) => {
    const totalPages = Math.ceil(props.count / props.limit);
    const range = Math.min(totalPages, props.range);
    const center = totalPages > range ? Math.ceil(range / 2) : range;
    const start = (props.page > center ? (props.page >= totalPages - center ? totalPages - range : props.page - center) : 1);
    const end = totalPages > range ? (start + range) : (start + range - 1);
    this.setState({
      range,
      center,
      start,
      end,
      page: props.page,
      query: props.query,
      totalPages
    });
  };

  render() {
    const className = this.state.status ? this.state.classActive : this.state.classPassive;
    const first = '?' + (new URLSearchParams({...this.state.query, page: 1})).toString();
    const previous = '?' + (new URLSearchParams({...this.state.query, page: parseInt(this.state.page) - 1})).toString();
    const next = '?' + (new URLSearchParams({...this.state.query, page: parseInt(this.state.page) + 1})).toString();
    const last = '?' + (new URLSearchParams({...this.state.query, page: this.state.totalPages})).toString();
    return (
      <Pagination style={{...this.props.style}}
                  ref={this.props.forwardref ? this.props.forwardref : null}
                  className={className + ' ' + this.props.className}>
        <PaginationItem disabled={this.state.page <= this.state.start}>
          <Link className="page-link" to={first}>&laquo;</Link>
        </PaginationItem>
        <PaginationItem disabled={this.state.page <= this.state.start}>
          <Link className="page-link" to={previous}>&lsaquo;</Link>
        </PaginationItem>
        {
          this.pageNumbers()
        }
        <PaginationItem disabled={this.state.page >= this.state.end}>
          <Link className="page-link" to={next}>&rsaquo;</Link>
        </PaginationItem>
        <PaginationItem disabled={this.state.page >= this.state.end}>
          <Link className="page-link" to={last}>&raquo;</Link>
        </PaginationItem>
      </Pagination>
    );
  }
}


export default React.forwardRef((props, ref) =>
  (
    <CustomPagination {...props} forwardref={ref}/>
  )
)



<|start_filename|>client/src/components/Common/Footer.js<|end_filename|>
import React, {PureComponent} from 'react';
import {Link} from 'react-router-dom';

class Footer extends PureComponent {
    constructor(props) {
        super(props)
        this.state = {}
    }

    render() {
        return (
            <footer id="footer" className="small">
                <div className="container py-3 border-top">
                    <div className="row">
                        <div className="col-sm-4  text-center text-sm-left text-uppercase">
                            React Loopback Playground.
                        </div>
                        <div className="col-sm-4 text-center">
                            The project under the <a href="https://opensource.org/licenses/MIT"
                                                     rel="noopener noreferrer"
                                                     target="_blank">MIT license</a>.
                        </div>
                        <div className="col-sm-4 text-center text-sm-right">
                            <ul className="nav justify-content-center justify-content-sm-end">
                                <li className="nav-item" key="about">
                                    <Link className="nav-link py-0" to="/about">About</Link>
                                </li>
                                <li className="nav-item" key="tos">
                                    <Link className="nav-link py-0" to="/tos">Terms of Service</Link>
                                </li>
                                <li className="nav-item" key="privacy">
                                    <Link className="nav-link py-0" to="/privacy">Privacy Policy</Link>
                                </li>
                            </ul>
                        </div>
                    </div>
                </div>
            </footer>
        );
    }
}

export default Footer;


<|start_filename|>client/src/components/App.js<|end_filename|>
import React, {PureComponent} from 'react';
import Navbar from './Common/Navbar'
import Footer from './Common/Footer'

import '../styles/App.scss';

class App extends PureComponent {
    constructor(props) {
        super(props)
        this.state = {
            me: props.me
        }
    }

    render() {
        console.log('App render', this.state.me);
        return (
            <React.Fragment>
                <Navbar/>
                <div className="page" data-spy="scroll" data-target="#navbar" data-offset="0">
                    {this.props.children}
                </div>
                <Footer/>
            </React.Fragment>
        );
    }
}

export default App;


<|start_filename|>server/boot/autentication.js<|end_filename|>
module.exports = enableAuthentication = server => {
  //commit
    server.enableAuth();
};


<|start_filename|>client/src/components/StaticPages/PrivacyPolicy.js<|end_filename|>
import React, {Component} from 'react';

class PrivacyPolicy extends Component {
    render() {
        return <section id="privacyPolicy">
            <div className="container">
                <h1 className="h3">Privacy Policy</h1>
                <hr className="border-primary"/>
                <p>This is a static page.</p>
            </div>
        </section>;
    }
}

export default PrivacyPolicy;


<|start_filename|>common/models/user.js<|end_filename|>
const config = require('../../server/config.json');
const sharp = require('sharp');
const nodemailer = require("nodemailer");
const mandrillTransport = require('nodemailer-mandrill-transport');
const from = config.fromMail;

const transport = nodemailer.createTransport(mandrillTransport({
  auth: {
    apiKey: config.mandrillApiKey
  },
  mandrillOptions: {
    async: false
  }
}));

const templateMail = function (title, html) {
  return `<html><head>
        <meta name="viewport" content="width=device-width" />
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>${title}</title>
        </head><body bgcolor="#FFFFFF">
        <table style="max-width:600px;margin: 0 auto;"><tr><td style="padding:15px;text-align: center;">
        <a href="${config.url}"><img src="${config.url}/favicon.png" alt="${config.name}" 
        style="border:0; max-width:240px; max-height:100px;"></a></td></tr>
        <tr><td>${html}</td></tr>
        <tr><td style="padding:15px;font-size: small; color: #444444;">You’re receiving this email because you have an account in 
        <a href="${config.url}">${config.name}</a>. If you are not sure why you’re receiving this, please contact us.</td>
        </tr></table>
        </body></html>`;
};

module.exports = function (User) {
  User.observe('before save', function (context, next) {
    if (context.instance)
      delete context.instance.unsetAttribute('roles');
    else
      delete context.data.roles;
    next();
  });
  User.afterRemote('create', function (context, user, next) {
    User.generateVerificationToken(user, null, function (err, token) {
      if (err) {
        return next(err);
      }
      console.log('USER', user);
      user.status = true;
      user.verificationToken = token;
      user.save(function (err) {
        if (err) {
          return next(err);
        }
        const title = 'Account Verification';
        const link = config.url + '/api/users/confirm?uid='
          + user.id + '&redirect=/signin&token=' + token;
        const html = `<table><tr><td style="padding:15px">Hi <strong>${user.name}</strong>;<br><br>
                    Thanks so much joining ${config.name}! To finish your register you just need to confirm that we got your email right.
                    </td></tr><tr><td style="padding:15px;text-align: center">
                    <a href="${link}" style="display:inline-block;margin:0 auto;padding:15px 20px;border-radius:10px;background:#20a8d8;color: #ffffff;text-decoration:none;">
                    Confirm your account</a>
                    </td></tr><tr><td style="padding:15px">Button not working? Try pasting this link into your browser:<br><br>
                    ${link}</td></tr></table>`;

        // User.app.models.Email.send({
        //     to: user.email,
        //     from: from,
        //     subject: title,
        //     html: templateMail(title, html)
        // }, function (err, res) {
        //     if (err) return console.log('> error sending verify  email', err);
        //     console.log('> sending verify reset email to:', user.email, res);
        // });
        console.log('VERIFICATION LINK', link);
        transport.sendMail({
          mandrillOptions: {
            async: false
          },
          from: from,
          to: user.email,
          subject: title,
          html: templateMail(title, html)
        }, function (err, info) {
          if (err) {
            console.error(err);
          } else {
            console.log(info);
          }
        });
      });
    });
    next();
  });
  // // Method to render
  // User.afterRemote('prototype.verify', function (context, user, next) {
  //     context.res.render('response', {
  //         title: 'A Link to verify your identity has been sent ' +
  //         'to your email successfully',
  //         content: 'Please check your email and click on the verification link ' +
  //         'before logging in',
  //         redirectTo: '/',
  //         redirectToLinkText: 'Log in'
  //     });
  // });
  //send password reset link when requested
  User.on('resetPasswordRequest', function (user) {
    const url = config.url + '/newpassword';
    const html = `Click the link to reset your password <br><a href="${url}/${user.accessToken.id}">
            ${url}/${user.accessToken.id}</a>`;
    console.log('html', html);
    transport.sendMail({
      from: from,
      to: user.email,
      subject: 'Password Reset',
      html: templateMail('Password Reset', html)
    }, function (err, info) {
      if (err) {
        return console.log('Error sending password reset email');
      } else {
        console.log('Sending password reset email to:', user.email, info);
      }
    });
  });
  User.approve = function (id, cb) {
    User.findById(id, function (err, user) {
      if (err) {
        cb(err);
      } else {
        user.emailVerified = true;
        user.adminVerified = true;
        user.save(function (err) {
          if (err) {
            console.log(err);
            next(err);
          } else {
            const html = '<div style="text-align: center"><h3>Good News</h3>' +
              '<p> We have just approved your account. ' +
              'You can play ' + config.name + ' the game whenever you want.</p></div>';
            transport.sendMail({
              from: from,
              to: user.email,
              subject: 'Account Approved',
              html: templateMail('Account Approved', html)
            }, function (err, info) {
              if (err) {
                console.log(err);
                cb(err);
              }
              console.log('Sending password reset email to:', user.email, info);
              cb(null, user);
            });
          }
        });
      }
    });
  };
  User.profile = function (username, cb) {
    User.findOne({"where": {"username": username}}, function (err, user) {
      if (err) {
        cb(err);
      } else {
        cb(null, user);
      }
    });
  };
  User.cover = function (id, context, options, cb) {
    const Container = User.app.models.Container;
    const token = options && options.accessToken;
    const root = User.app.dataSources.storage.settings.root;
    User.findById(token && token.userId, function (err, user) {
      if (err) {
        cb(err);
      } else {
        // each user has own container as named by user id
        Container.putContainer(user.id.toString(), function (err, container) {
          if (err) {
            cb(err);
          } else {
            console.log('CONTAINER CHECK', container);
            Container.upload(context.req, context.res, {container: container}, function (err, file) {
              if (err) {
                cb(err);
              } else {
                file = file.files.file && file.files.file.pop();
                console.log('FILE UPLOADING', file);
                //console.log('USER IMAGE', user);

                const normal = file.name.replace(/\./, '_normal.');
                sharp(root + file.container + '/' + file.name)
                  .resize(1200, 360, {fit: 'cover'})
                  .on('error', function (err) {
                    console.log(err);
                  })
                  .jpeg()
                  .toFile(root + file.container + '/' + normal)
                  .then(function () {
                    const thumb = file.name.replace(/\./, '_thumb.');
                    sharp(root + file.container + '/' + file.name)
                      .resize(400, 120)
                      .toFile(root + file.container + '/' + thumb)
                      .then(function () {
                        user.updateAttributes({
                          'cover': {
                            name: file.name,
                            type: file.type,
                            container: file.container,
                            url: '/api/containers/' + file.container + '/download/' + file.name,
                            normal: '/api/containers/' + file.container + '/download/' + normal,
                            thumb: '/api/containers/' + file.container + '/download/' + thumb
                          }
                        }, function (err) {
                          if (err) {
                            console.log(err);
                            cb(err);
                          }
                          console.log('USER COVER SAVED', user);
                          cb(null, user);
                          //return user.image;
                        });

                      })
                      .catch(err => {
                        throw err
                      });

                  })
                  .catch(err => {
                    throw err
                  });
              }
            });
          }
        });
      }
    });
  };
  User.image = function (id, context, options, cb) {
    const Container = User.app.models.Container;
    const token = options && options.accessToken;
    const root = User.app.dataSources.storage.settings.root;
    //console.log(cb);
    //cb = function(){return console.log()};
    User.findById(token && token.userId, function (err, user) {
      if (err) {
        cb(err);
      } else {
        // each user has own container as named by user id
        Container.putContainer(user.id.toString(), function (err, container) {
          if (err) {
            cb(err);
          } else {
            Container.upload(context.req, context.res, {container: container}, function (err, file) {
              if (err) {
                cb(err);
              } else {
                file = file.files.file.pop();
                //console.log('FILE UPLOADED', file);

                console.log('FILE UPLOADED', root + file.container + '/' + file.name);

                const normal = file.name.replace(/\./, '_normal.');

                sharp(root + file.container + '/' + file.name)
                  .resize(360, 360, {fit: 'cover'})
                  //.crop(sharp.strategy.attention)
                  .on('error', function (err) {
                    console.log(err);
                  })
                  .jpeg()
                  .toFile(root + file.container + '/' + normal)
                  .then(function () {
                    const thumb = file.name.replace(/\./, '_thumb.');
                    sharp(root + file.container + '/' + file.name)
                      .resize(50, 50)
                      .toFile(root + file.container + '/' + thumb)
                      .then(function () {
                        user.updateAttributes({
                          'image': {
                            name: file.name,
                            type: file.type,
                            container: file.container,
                            url: '/api/containers/' + file.container + '/download/' + file.name,
                            normal: '/api/containers/' + file.container + '/download/' + normal,
                            thumb: '/api/containers/' + file.container + '/download/' + thumb
                          }
                        }, function (err) {
                          if (err) {
                            console.log(err);
                            cb(err);
                          }
                          console.log('USER IMAGE SAVED', user);
                          cb(null, user);
                          //return user.image;
                        })

                      })
                      .catch(err => {
                        throw err
                      });

                  })
                  .catch(err => {
                    throw err
                  });


              }
            });
          }
        });
      }
    });
  };

  const setACL = (id, cb, type) => {
    const Role = User.app.models.Role;
    const RoleMapping = User.app.models.RoleMapping;
    User.findById(id, function (err, user) {
      if (err) {
        cb(err);
      } else {
        Role.findOrCreate({where: {name: type}}, {
          name: type
        }, function (err, role) {
          if (err) cb(err);
          RoleMapping.find({
            where: {
              principalId: user.id,
              roleId: role.id
            }
          }, function (err, principal) {
            if (err) cb(err);
            if (!principal.length)
              RoleMapping.create({
                principalType: RoleMapping.USER,
                principalId: user.id,
                roleId: role.id
              }, function (err) {
                if (err) cb(err);
                User.findById(id, function (err, user) {
                  if (err) {
                    cb(err);
                  }
                  cb(null, user);
                });
              });
            else
              RoleMapping.destroyById(principal[0].id, function (err) {
                if (err) cb(err);
                User.findById(id, function (err, user) {
                  if (err) {
                    cb(err);
                  }
                  cb(null, user);
                });
              });
          });
        });
      }
    });
  };
  User.toggleAdmin = function (id, cb) {
    setACL(id, cb, 'admin');
  };
  User.toggleEditor = function (id, cb) {
    setACL(id, cb, 'editor');
  };
  User.toggleManager = function (id, cb) {
    setACL(id, cb, 'manager');
  };
  User.toggleWorker = function (id, cb) {
    setACL(id, cb, 'worker');
  };
  User.toggleStatus = function (id, cb) {
    User.findById(id, function (err, user) {
      if (err) {
        cb(err);
      } else {
        user.status = !user.status;
        user.save(function (err) {
          if (err) {
            cb(err);
          } else {
            User.findById(id, function (err, user) {
              if (err) {
                cb(err);
              }
              cb(null, user);
            });
          }
        });
      }
    });
  };
  User.list = function (req, cb) {
    let {query, filter} = req.query;
    const {skip, limit} = filter || {skip: 0, limit: 10};
    const {body, params} = req;
    console.log({body, params, query, filter});
    query = query && query !== 'undefined' ? new RegExp(`^${query}`, 'i') : false;
    const where = query ? {
      and: [{status: true}, {
        or: [{name: query}
          , {surname: query}
          , {username: query}
          , {email: query}]
      }]
    } : {status: true};
    console.log({query});
    User.count(where,
      (err, count) => {
        User.find({
            where: where,
            //fields: {id: true, name: true, username: true, createdAt: true, status: true},
            order: 'name ASC',
            skip, limit
          },
          (err, items) => {
            if (err) return cb(err);
            console.log('Users', items.length);
            cb(null, {items, count});
          });
      });
  };
};


<|start_filename|>client/src/components/Settings/Images.js<|end_filename|>
import React, {Component} from 'react';
import {uploadCoverImage, uploadProfileImage} from '../../actions'
import {connect} from 'react-redux'

class Images extends Component {
    constructor(props) {
        super(props);
        this.state = {
            me: props.me,
            selectedFile: '',
            isUploading: false,
            isUploadingCover: false,
            isUploadingProfile: false
        };
        // this.handleSubmit = this.handleSubmit.bind(this);
        this.handleFileChange = this.handleFileChange.bind(this);
    }

    componentDidUpdate(props) {
        if (this.props.me !== props.me)
            this.setState({
                me: props.me,
                isDone: true,
                isUploadingCover: false,
                isUploadingProfile: false,
            })
    }

    static handleBrowseFile(e) {
        e.stopPropagation();
        document.getElementById(e.currentTarget.dataset.input).click();
    }

    handleFileChange(e) {
        this.handleImageUpload(e.target.id, e.target.files[0])
    }

    async handleImageUpload(id, file) {
        this.setState({status: '', isUploadingCover: id === 'cover', isUploadingProfile: id === 'profile'});
        const formData = new FormData();
        formData.append('file', file, file.name);
        if (id === 'cover')
            this.props.uploadCoverImage(formData);
        else
            this.props.uploadProfileImage(formData)
    }

    render() {
        return <div>

            <figure className={this.state.isUploadingCover ? 'CoverImage uploading' : 'CoverImage'}
                    data-input="cover"
                    onClick={Images.handleBrowseFile}>
                <span className="loader"><i className="fa fa-spinner fa-spin fa-3x"/></span>
                {this.state.me.cover && this.state.me.cover.normal &&
                <img src={this.state.me.cover.normal} alt={this.state.me.name}/>
                }
                <div className="image-input-container">
                    <input type="file" id="cover" name="image" onChange={this.handleFileChange}/>
                </div>
                <figure className={this.state.isUploadingProfile ? 'ProfileImage uploading' : 'ProfileImage'}
                        data-input="profile"
                        onClick={Images.handleBrowseFile}>
                    <span className="loader"><i className="fa fa-spinner fa-spin fa-3x"/></span>
                    {this.state.me.image && this.state.me.image.normal &&
                    <img src={this.state.me.image.normal} alt={this.state.me.name}/>
                    }
                    <div className="image-input-container">
                        <input type="file" id="profile" name="image" onChange={this.handleFileChange}/>
                    </div>
                </figure>
            </figure>
            <pre>{JSON.stringify(this.state.me, null, 2)}</pre>
        </div>
    }
}


const mapStateToProps = (state) => {
    return {me: state.auth.me}
};

const mapDispatchToProps = (dispatch) => {
    return {
        uploadCoverImage: (values) => {
            dispatch(uploadCoverImage(values));
        },
        uploadProfileImage: (values) => {
            dispatch(uploadProfileImage(values));
        },
    }
};

export default connect(mapStateToProps, mapDispatchToProps)(Images);


<|start_filename|>client/src/index.js<|end_filename|>
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
import {applyMiddleware, compose, createStore} from 'redux';
import reduxThunk from 'redux-thunk';
import {BrowserRouter, Router} from 'react-router-dom';

import ScrollToTop from './components/Common/ScrollToTop';
import History from './history';
import Routes from './routes';

import rootReducer from './reducers';
import {getSession} from './actions';
import * as type from "./actions/types";

import * as serviceWorker from './serviceWorker';

/*
// UNCOMMENT IT FOR PRODUCTION
const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore);
const store = createStoreWithMiddleware(rootReducer);
*/

/* COMMENT IT OUT FOR PRODUCTION */
const store = createStore(
  rootReducer,
  compose(
    applyMiddleware(reduxThunk),
    window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f
  )
);

getSession((me) => {
  me && store.dispatch({type: type.AUTH_USER, payload: me});
  ReactDOM.render(
    <Provider store={store}>
      <BrowserRouter>
        <Router history={History}>
          <ScrollToTop>
            <Routes me={me}/>
          </ScrollToTop>
        </Router>
      </BrowserRouter>
    </Provider>, document.getElementById('root'));
  // If you want your app to work offline and load faster, you can change
  // unregister() to register() below. Note this comes with some pitfalls.
  // Learn more about service workers: http://bit.ly/CRA-PWA
  serviceWorker.unregister();
});

