diff --git a/src/client/api/index.js b/src/client/api/index.js index b3520fba7..212896060 100644 --- a/src/client/api/index.js +++ b/src/client/api/index.js @@ -140,10 +140,13 @@ api.accounts.getWithPage = payload => { const type = payload && payload.type ? payload.type : 'all' let search = payload && payload.search ? payload.search : '' if (search) search = `&search=${search}` + const showDeleted = payload && payload.showDeleted ? payload.showDeleted : false - return axios.get(`/api/v2/accounts?type=${type}&limit=${limit}&page=${page}${search}`).then(res => { - return res.data - }) + return axios + .get(`/api/v2/accounts?type=${type}&limit=${limit}&page=${page}${search}&showDeleted=${showDeleted}`) + .then(res => { + return res.data + }) } api.accounts.updateUser = payload => { return axios.put(`/api/v2/accounts/${payload.username}`, payload).then(res => { @@ -168,7 +171,7 @@ api.groups.create = payload => { }) } api.groups.get = payload => { - const limit = payload && payload.limit ? payload.limit : 25 + const limit = payload && payload.limit ? payload.limit : 50 const page = payload && payload.page ? payload.page : 0 const type = payload && payload.type ? `&type=${payload.type}` : '' diff --git a/src/client/containers/Accounts/index.jsx b/src/client/containers/Accounts/index.jsx index 82bad5bc0..de1d77a96 100644 --- a/src/client/containers/Accounts/index.jsx +++ b/src/client/containers/Accounts/index.jsx @@ -82,8 +82,9 @@ class AccountsContainer extends React.Component { } getUsersWithPage (page) { - this.props.fetchAccounts({ page, limit: 25, type: this.props.view }).then(({ response }) => { - if (response.count < 25) this.hasMore = false + this.hasMore = false + this.props.fetchAccounts({ page, limit: 25, type: this.props.view, showDeleted: true }).then(({ response }) => { + this.hasMore = response.count >= 25 }) } @@ -93,9 +94,10 @@ class AccountsContainer extends React.Component { if (keyCode === 13) { if (search.length > 2) { this.props.unloadAccounts().then(() => { - this.props.fetchAccounts({ limit: 1000, search: search }).then(({ response }) => { + this.hasMore = false + this.props.fetchAccounts({ limit: -1, search: search }).then(({ response }) => { this.pageStart = -1 - if (response.count < 25) this.hasMore = false + this.hasMore = response.count >= 25 }) }) } else if (search.length === 0) { diff --git a/src/client/containers/Groups/index.jsx b/src/client/containers/Groups/index.jsx index 7200a4772..a9775731e 100644 --- a/src/client/containers/Groups/index.jsx +++ b/src/client/containers/Groups/index.jsx @@ -71,32 +71,37 @@ class GroupsContainer extends React.Component { return ( {group.get('name')} - + {group.get('members') && group.get('members').size > 0 && - group.get('members').map(user => { - const profilePic = user.get('image') || 'defaultProfile.jpg' - return ( -
- {user.get('fullname')} - -
- ) - })} + group + .get('members') + .filter(user => { + return !user.get('deleted') + }) + .map(user => { + const profilePic = user.get('image') || 'defaultProfile.jpg' + return ( +
+ {user.get('fullname')} + +
+ ) + })} {!group.get('members') &&
} diff --git a/src/client/containers/Modals/CreateTeamModal.jsx b/src/client/containers/Modals/CreateTeamModal.jsx index 02912fbdb..cbfde3939 100644 --- a/src/client/containers/Modals/CreateTeamModal.jsx +++ b/src/client/containers/Modals/CreateTeamModal.jsx @@ -33,7 +33,7 @@ class CreateTeamModal extends React.Component { @observable name = '' componentDidMount () { - this.props.fetchAccounts() + this.props.fetchAccounts({ limit: -1 }) helpers.UI.inputs() helpers.UI.reRenderInputs() @@ -68,7 +68,7 @@ class CreateTeamModal extends React.Component { render () { const mappedAccounts = this.props.accounts .filter(account => { - return account.getIn(['role', 'isAgent']) === true + return account.getIn(['role', 'isAgent']) === true && !account.get('deleted') }) .map(account => { return { text: account.get('fullname'), value: account.get('_id') } diff --git a/src/client/containers/Modals/EditGroupModal.jsx b/src/client/containers/Modals/EditGroupModal.jsx index 289fbf4f9..0bb109939 100644 --- a/src/client/containers/Modals/EditGroupModal.jsx +++ b/src/client/containers/Modals/EditGroupModal.jsx @@ -27,12 +27,13 @@ import Button from 'components/Button' import helpers from 'lib/helpers' import $ from 'jquery' +import SpinLoader from 'components/SpinLoader' @observer class EditGroupModal extends React.Component { @observable name = '' componentDidMount () { - this.props.fetchAccounts({ type: 'customers' }) + this.props.fetchAccounts({ type: 'customers', limit: -1 }) this.name = this.props.group.name helpers.UI.inputs() @@ -74,8 +75,9 @@ class EditGroupModal extends React.Component { }) return ( +
-

Create Group

+

Edit Group

this.onFormSubmit(e)}>
@@ -114,11 +116,13 @@ EditGroupModal.propTypes = { accounts: PropTypes.object.isRequired, updateGroup: PropTypes.func.isRequired, fetchAccounts: PropTypes.func.isRequired, - unloadAccounts: PropTypes.func.isRequired + unloadAccounts: PropTypes.func.isRequired, + accountsLoading: PropTypes.bool.isRequired } const mapStateToProps = state => ({ - accounts: state.accountsState.accounts + accounts: state.accountsState.accounts, + accountsLoading: state.accountsState.loading }) export default connect( diff --git a/src/client/containers/Modals/EditTeamModal.jsx b/src/client/containers/Modals/EditTeamModal.jsx index 72126342a..a72030fdb 100644 --- a/src/client/containers/Modals/EditTeamModal.jsx +++ b/src/client/containers/Modals/EditTeamModal.jsx @@ -27,13 +27,14 @@ import helpers from 'lib/helpers' import Button from 'components/Button' import MultiSelect from 'components/MultiSelect' import $ from 'jquery' +import SpinLoader from 'components/SpinLoader' @observer class EditTeamModal extends React.Component { @observable name = '' componentDidMount () { - this.props.fetchAccounts({ type: 'all' }) + this.props.fetchAccounts({ type: 'all', limit: -1 }) this.name = this.props.team.name helpers.UI.inputs() @@ -70,16 +71,18 @@ class EditTeamModal extends React.Component { render () { const mappedAccounts = this.props.accounts .filter(account => { - return account.getIn(['role', 'isAgent']) === true + return account.getIn(['role', 'isAgent']) === true && !account.get('deleted') }) .map(account => { return { text: account.get('fullname'), value: account.get('_id') } }) .toArray() + const selectedMembers = this.props.team.members return ( +

Edit Team

@@ -120,11 +123,13 @@ EditTeamModal.propTypes = { fetchAccounts: PropTypes.func.isRequired, unloadAccounts: PropTypes.func.isRequired, saveEditTeam: PropTypes.func.isRequired, - accounts: PropTypes.object.isRequired + accounts: PropTypes.object.isRequired, + accountsLoading: PropTypes.bool.isRequired } const mapStateToProps = state => ({ - accounts: state.accountsState.accounts + accounts: state.accountsState.accounts, + accountsLoading: state.accountsState.loading }) export default connect( diff --git a/src/client/containers/Teams/index.jsx b/src/client/containers/Teams/index.jsx index ea0e87da2..7147cedd8 100644 --- a/src/client/containers/Teams/index.jsx +++ b/src/client/containers/Teams/index.jsx @@ -93,29 +93,34 @@ class TeamsContainer extends React.Component { {team.get('members') && team.get('members').size > 0 && - team.get('members').map(user => { - const profilePic = user.get('image') || 'defaultProfile.jpg' - return ( -
- {user.get('fullname')} - -
- ) - })} + team + .get('members') + .filter(user => { + return !user.get('deleted') + }) + .map(user => { + const profilePic = user.get('image') || 'defaultProfile.jpg' + return ( +
+ {user.get('fullname')} + +
+ ) + })}
diff --git a/src/client/containers/TicketsContainer.jsx b/src/client/containers/TicketsContainer.jsx index 31827917c..329b3148c 100644 --- a/src/client/containers/TicketsContainer.jsx +++ b/src/client/containers/TicketsContainer.jsx @@ -296,7 +296,7 @@ class TicketsContainer extends React.Component { : '--' const isOverdue = () => { - if (!this.props.common.showOverdue || ticket.get('status') === 2) return false + if (!this.props.common.showOverdue || [2, 3].indexOf(ticket.get('status')) !== -1) return false const overdueIn = ticket.getIn(['priority', 'overdueIn']) const now = moment() let updated = ticket.get('updated') diff --git a/src/client/reducers/accountsReducer.js b/src/client/reducers/accountsReducer.js index 2c662ad80..0e87b1db1 100644 --- a/src/client/reducers/accountsReducer.js +++ b/src/client/reducers/accountsReducer.js @@ -25,11 +25,19 @@ import { const initialState = { accounts: List([]), - type: 'customers' + type: 'customers', + loading: false } const reducer = handleActions( { + [FETCH_ACCOUNTS.PENDING]: state => { + return { + ...state, + loading: true + } + }, + [FETCH_ACCOUNTS.SUCCESS]: (state, action) => { let arr = state.accounts.toArray() action.payload.response.accounts.map(i => { @@ -38,7 +46,8 @@ const reducer = handleActions( return { ...state, accounts: fromJS(arr), - type: action.payload.payload && action.payload.payload.type ? action.payload.payload.type : 'customers' + type: action.payload.payload && action.payload.payload.type ? action.payload.payload.type : 'customers', + loading: false } }, diff --git a/src/client/sagas/accounts/index.js b/src/client/sagas/accounts/index.js index 3f083d684..874f389fa 100644 --- a/src/client/sagas/accounts/index.js +++ b/src/client/sagas/accounts/index.js @@ -28,6 +28,7 @@ import api from '../../api' import helpers from 'lib/helpers' function * fetchAccounts ({ payload, meta }) { + yield put({ type: FETCH_ACCOUNTS.PENDING }) try { const response = yield call(api.accounts.getWithPage, payload) yield put({ type: FETCH_ACCOUNTS.SUCCESS, payload: { response, payload }, meta }) diff --git a/src/controllers/api/v1/tickets.js b/src/controllers/api/v1/tickets.js index 866165ba9..e074df5f8 100644 --- a/src/controllers/api/v1/tickets.js +++ b/src/controllers/api/v1/tickets.js @@ -1884,20 +1884,38 @@ apiTickets.getOverdue = function (req, res) { } var ticketSchema = require('../../../models/ticket') + var departmentSchema = require('../../../models/department') var groupSchema = require('../../../models/group') - groupSchema.getAllGroupsOfUser(req.user._id, function (err, grps) { - if (err) return res.status(400).json({ success: false, error: err.message }) - grps = grps.map(function (g) { - return g._id.toString() - }) - ticketSchema.getOverdue(grps, function (err, objs) { - if (err) return res.status(400).json({ success: false, error: err.message }) - var sorted = _.sortBy(objs, 'uid').reverse() + async.waterfall( + [ + function (next) { + if (!req.user.role.isAdmin && !req.user.role.isAgent) { + return groupSchema.getAllGroupsOfUserNoPopulate(req.user._id, next) + } else { + return departmentSchema.getDepartmentGroupsOfUser(req.user._id, next) + } + }, + function (groups, next) { + var groupIds = groups.map(function (g) { + return g._id + }) - return res.json({ success: true, tickets: sorted }) - }) - }) + ticketSchema.getOverdue(groupIds, function (err, tickets) { + if (err) return next(err) + + var sorted = _.sortBy(tickets, 'uid').reverse() + + return next(null, sorted) + }) + } + ], + function (err, overdueTickets) { + if (err) return res.status(400).json({ success: false, error: err.message }) + + return res.json({ success: true, tickets: overdueTickets }) + } + ) }) } diff --git a/src/controllers/api/v2/accounts.js b/src/controllers/api/v2/accounts.js index 364ba4dd6..35b111130 100644 --- a/src/controllers/api/v2/accounts.js +++ b/src/controllers/api/v2/accounts.js @@ -122,12 +122,13 @@ accountsApi.create = function (req, res) { accountsApi.get = function (req, res) { var query = req.query var type = query.type || 'customers' - var limit = query.limit ? Number(query.limit) : 10 + var limit = query.limit ? Number(query.limit) : 25 var page = query.page ? Number(query.page) : 0 var obj = { - limit: limit, - page: page + limit: limit === -1 ? 999999 : limit, + page: page, + showDeleted: query.showDeleted && query.showDeleted === 'true' } switch (type) { diff --git a/src/controllers/api/v2/groups.js b/src/controllers/api/v2/groups.js index ff877d767..70b1bbdf5 100644 --- a/src/controllers/api/v2/groups.js +++ b/src/controllers/api/v2/groups.js @@ -35,7 +35,7 @@ apiGroups.create = function (req, res) { } apiGroups.get = function (req, res) { - var limit = Number(req.query.limit) || 10 + var limit = Number(req.query.limit) || 50 var page = Number(req.query.page) || 0 var type = req.query.type || 'user' diff --git a/src/controllers/install.js b/src/controllers/install.js index c19ab89e9..092062d2d 100644 --- a/src/controllers/install.js +++ b/src/controllers/install.js @@ -144,7 +144,9 @@ installController.install = function (req, res) { value: require('../../package.json').version }) - return s.save(next) + return s.save(function (err) { + return next(err) + }) }, function (next) { var Counter = new Counters({ diff --git a/src/models/group.js b/src/models/group.js index 27cbd513c..53414b822 100644 --- a/src/models/group.js +++ b/src/models/group.js @@ -34,7 +34,7 @@ var groupSchema = mongoose.Schema({ { type: mongoose.Schema.Types.ObjectId, ref: 'accounts', - autopopulate: { select: '_id username email image title fullname' } + autopopulate: { select: '-hasL2Auth -preferences -__v' } } ], sendMailTo: [{ type: mongoose.Schema.Types.ObjectId, ref: 'accounts' }], @@ -106,8 +106,8 @@ groupSchema.statics.getGroupByName = function (name, callback) { var q = this.model(COLLECTION) .findOne({ name: name }) - .populate('members', '_id username fullname email role preferences image title') - .populate('sendMailTo', '_id username fullname email role preferences image title') + .populate('members', '_id username fullname email role preferences image title deleted') + .populate('sendMailTo', '_id username fullname email role preferences image title deleted') return q.exec(callback) } @@ -122,8 +122,8 @@ groupSchema.statics.getWithObject = function (obj, callback) { .find({ members: userId }) .limit(limit) .skip(page * limit) - .populate('members', '_id username fullname email role preferences image title') - .populate('sendMailTo', '_id username fullname email role preferences image title') + .populate('members', '_id username fullname email role preferences image title deleted') + .populate('sendMailTo', '_id username fullname email role preferences image title deleted') .sort('name') .exec(callback) } @@ -132,8 +132,8 @@ groupSchema.statics.getWithObject = function (obj, callback) { .find({}) .limit(limit) .skip(page * limit) - .populate('members', '_id username fullname email role preferences image title') - .populate('sendMailTo', '_id username fullname email role preferences image title') + .populate('members', '_id username fullname email role preferences image title deleted') + .populate('sendMailTo', '_id username fullname email role preferences image title deleted') .sort('name') .exec(callback) } @@ -141,8 +141,8 @@ groupSchema.statics.getWithObject = function (obj, callback) { groupSchema.statics.getAllGroups = function (callback) { var q = this.model(COLLECTION) .find({}) - .populate('members', '_id username fullname email role preferences image title') - .populate('sendMailTo', '_id username fullname email role preferences image title') + .populate('members', '_id username fullname email role preferences image title deleted') + .populate('sendMailTo', '_id username fullname email role preferences image title deleted') .sort('name') return q.exec(callback) @@ -169,7 +169,7 @@ groupSchema.statics.getGroups = function (groupIds, callback) { this.model(COLLECTION) .find({ _id: { $in: groupIds } }) - .populate('members', '_id username fullname email role preferences image title') + .populate('members', '_id username fullname email role preferences image title deleted') .sort('name') .exec(callback) } @@ -179,8 +179,8 @@ groupSchema.statics.getAllGroupsOfUser = function (userId, callback) { var q = this.model(COLLECTION) .find({ members: userId }) - .populate('members', '_id username fullname email role preferences image title') - .populate('sendMailTo', '_id username fullname email role preferences image title') + .populate('members', '_id username fullname email role preferences image title deleted') + .populate('sendMailTo', '_id username fullname email role preferences image title deleted') .sort('name') return q.exec(callback) diff --git a/src/models/team.js b/src/models/team.js index 7b21d68b6..511a1c344 100644 --- a/src/models/team.js +++ b/src/models/team.js @@ -27,7 +27,7 @@ var teamSchema = mongoose.Schema({ { type: mongoose.Schema.Types.ObjectId, ref: 'accounts', - autopopulate: { select: '_id username fullname email title image' } + autopopulate: { select: '-hasL2Auth -preferences -__v' } } ] }) @@ -81,7 +81,6 @@ teamSchema.statics.getWithObject = function (obj, callback) { .skip(obj.limit * obj.page) .limit(obj.limit) .sort('name') - .populate('members', '_id username fullname email image title') return q.exec(callback) } @@ -89,9 +88,7 @@ teamSchema.statics.getWithObject = function (obj, callback) { teamSchema.statics.getTeamByName = function (name, callback) { if (_.isUndefined(name) || name.length < 1) return callback('Invalid Team Name - TeamSchema.GetTeamByName()') - var q = this.model(COLLECTION) - .findOne({ normalized: name }) - .populate('members', '_id username fullname email image title') + var q = this.model(COLLECTION).findOne({ normalized: name }) return q.exec(callback) } @@ -99,7 +96,6 @@ teamSchema.statics.getTeamByName = function (name, callback) { teamSchema.statics.getTeams = function (callback) { var q = this.model(COLLECTION) .find({}) - .populate('members', '_id username fullname email image title') .sort('name') return q.exec(callback) @@ -108,7 +104,6 @@ teamSchema.statics.getTeams = function (callback) { teamSchema.statics.getTeamsByIds = function (ids, callback) { return this.model(COLLECTION) .find({ _id: { $in: ids } }) - .populate('members', '_id username fullname email image title') .sort('name') .exec(callback) } @@ -126,7 +121,6 @@ teamSchema.statics.getTeamsOfUser = function (userId, callback) { var q = this.model(COLLECTION) .find({ members: userId }) - .populate('members', '_id username fullname email image title') .sort('name') return q.exec(callback) @@ -145,9 +139,7 @@ teamSchema.statics.getTeamsOfUserNoPopulate = function (userId, callback) { teamSchema.statics.getTeam = function (id, callback) { if (_.isUndefined(id)) return callback('Invalid TeamId - TeamSchema.GetTeam()') - var q = this.model(COLLECTION) - .findOne({ _id: id }) - .populate('members', '_id username fullname email image title') + var q = this.model(COLLECTION).findOne({ _id: id }) return q.exec(callback) } diff --git a/src/models/user.js b/src/models/user.js index c6baf5a9f..f883a1d83 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -68,7 +68,7 @@ var userSchema = mongoose.Schema({ hasL2Auth: { type: Boolean, required: true, default: false }, accessToken: { type: String, sparse: true, select: false }, - iOSDeviceTokens: [{ type: String, select: false }], + iOSDeviceTokens: { type: [String], select: false }, preferences: { tourCompleted: { type: Boolean, default: false }, @@ -428,6 +428,8 @@ userSchema.statics.getUserWithObject = function (object, callback) { q.limit(limit) } + if (!object.showDeleted) q.where({ deleted: false }) + if (!_.isEmpty(search)) { q.where({ fullname: new RegExp('^' + search.toLowerCase(), 'i') }) } @@ -643,12 +645,15 @@ userSchema.statics.getCustomers = function (obj, callback) { return a.role._id }) - self + var q = self .find({ role: { $in: customerRoleIds } }, '-password -resetPassHash -resetPassExpire') .sort({ fullname: 1 }) .skip(page * limit) .limit(limit) - .exec(callback) + + if (!obj.showDeleted) q.where({ deleted: false }) + + q.exec(callback) }) } @@ -669,13 +674,16 @@ userSchema.statics.getAgents = function (obj, callback) { return a.role._id }) - self + var q = self .model(COLLECTION) .find({ role: { $in: agentRoleIds } }, '-password -resetPassHash -resetPassExpire') .sort({ fullname: 1 }) .skip(page * limit) .limit(limit) - .exec(callback) + + if (!obj.showDeleted) q.where({ deleted: false }) + + q.exec(callback) }) } @@ -696,13 +704,16 @@ userSchema.statics.getAdmins = function (obj, callback) { return a.role._id }) - self + var q = self .model(COLLECTION) .find({ role: { $in: adminRoleIds } }, '-password -resetPassHash -resetPassExpire') .sort({ fullname: 1 }) .skip(page * limit) .limit(limit) - .exec(callback) + + if (!obj.showDeleted) q.where({ deleted: false }) + + q.exec(callback) }) }