mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-05 04:34:37 +08:00
fix hound and refactor
This commit is contained in:
parent
48c8922604
commit
55772a80ab
12 changed files with 385 additions and 325 deletions
|
@ -1,34 +1,34 @@
|
|||
module ClientApi
|
||||
module Users
|
||||
class InvitationsController < Devise::InvitationsController
|
||||
module Users
|
||||
class InvitationsController < Devise::InvitationsController
|
||||
before_action :check_invite_users_permission, only: :invite_users
|
||||
|
||||
before_action :check_invite_users_permission, only: :invite_users
|
||||
def invite_users
|
||||
invite_service =
|
||||
ClientApi::InvitationsService.new(user: current_user,
|
||||
team: @team,
|
||||
role: params['user_role'],
|
||||
emails: params[:emails])
|
||||
invite_results = invite_service.invitation
|
||||
success_response(invite_results)
|
||||
end
|
||||
|
||||
def invite_users
|
||||
invite_service = ClientApi::InvitationsService.new(user: current_user,
|
||||
team: @team,
|
||||
role: params['user_role'],
|
||||
emails: params[:emails])
|
||||
invite_results = invite_service.invitation
|
||||
success_response(invite_results)
|
||||
end
|
||||
|
||||
def success_response(invite_results)
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
render template: '/client_api/users/invite_users',
|
||||
status: :ok,
|
||||
locals: {invite_results: invite_results, team: @team}
|
||||
def success_response(invite_results)
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
render template: '/client_api/users/invite_users',
|
||||
status: :ok,
|
||||
locals: { invite_results: invite_results, team: @team }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
def check_invite_users_permission
|
||||
@team = Team.find_by_id(params[:team_id])
|
||||
render_403 if @team && !is_admin_of_team(@team)
|
||||
def check_invite_users_permission
|
||||
@team = Team.find_by_id(params[:team_id])
|
||||
render_403 if @team && !is_admin_of_team(@team)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,27 +1,28 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { DropdownButton, MenuItem } from 'react-bootstrap';
|
||||
import React from "react";
|
||||
import { func } from "prop-types";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { DropdownButton, MenuItem } from "react-bootstrap";
|
||||
|
||||
const InviteUsersButton = props =>
|
||||
<DropdownButton
|
||||
bsStyle={'primary'}
|
||||
title={<FormattedMessage id="invite_users.dropdown_button.invite" />}
|
||||
id="invite_users.submit_button"
|
||||
>
|
||||
<MenuItem onClick={() => props.handleClick('guest')}>
|
||||
<FormattedMessage id="invite_users.dropdown_button.guest" />
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => props.handleClick('normal_user')}>
|
||||
<FormattedMessage id="invite_users.dropdown_button.normal_user" />
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => props.handleClick('admin')}>
|
||||
<FormattedMessage id="invite_users.dropdown_button.admin" />
|
||||
</MenuItem>
|
||||
</DropdownButton>;
|
||||
const InviteUsersButton = props => (
|
||||
<DropdownButton
|
||||
bsStyle={"primary"}
|
||||
title={<FormattedMessage id="invite_users.dropdown_button.invite" />}
|
||||
id="invite_users.submit_button"
|
||||
>
|
||||
<MenuItem onClick={() => props.handleClick("guest")}>
|
||||
<FormattedMessage id="invite_users.dropdown_button.guest" />
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => props.handleClick("normal_user")}>
|
||||
<FormattedMessage id="invite_users.dropdown_button.normal_user" />
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => props.handleClick("admin")}>
|
||||
<FormattedMessage id="invite_users.dropdown_button.admin" />
|
||||
</MenuItem>
|
||||
</DropdownButton>
|
||||
);
|
||||
|
||||
InviteUsersButton.propTypes = {
|
||||
handleClick: PropTypes.func.isRequired
|
||||
handleClick: func.isRequired
|
||||
};
|
||||
|
||||
export default InviteUsersButton;
|
||||
|
|
|
@ -1,38 +1,42 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormGroup, HelpBlock } from 'react-bootstrap';
|
||||
import TagsInput from 'react-tagsinput';
|
||||
import React from "react";
|
||||
import { string, func, arrayOf } from "prop-types";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { FormGroup, HelpBlock } from "react-bootstrap";
|
||||
import TagsInput from "react-tagsinput";
|
||||
|
||||
import { INVITE_USERS_LIMIT } from '../../../config/constants/numeric';
|
||||
import { INVITE_USERS_LIMIT } from "../../../config/constants/numeric";
|
||||
|
||||
const InviteUsersForm = props =>
|
||||
<FormGroup controlId="form-invite-user">
|
||||
<p>
|
||||
<FormattedMessage id="invite_users.input_text" values={{team: props.teamName}} />
|
||||
</p>
|
||||
<TagsInput
|
||||
value={props.tags}
|
||||
addKeys={[9, 13, 188]}
|
||||
addOnPaste
|
||||
onlyUnique
|
||||
maxTags={INVITE_USERS_LIMIT}
|
||||
inputProps={{
|
||||
placeholder: ''
|
||||
}}
|
||||
onChange={props.handleChange}
|
||||
/>
|
||||
<HelpBlock>
|
||||
<em>
|
||||
<FormattedMessage id="invite_users.input_help" />
|
||||
</em>
|
||||
</HelpBlock>
|
||||
</FormGroup>;
|
||||
const InviteUsersForm = props => (
|
||||
<FormGroup controlId="form-invite-user">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="invite_users.input_text"
|
||||
values={{ team: props.teamName }}
|
||||
/>
|
||||
</p>
|
||||
<TagsInput
|
||||
value={props.tags}
|
||||
addKeys={[9, 13, 188]}
|
||||
addOnPaste
|
||||
onlyUnique
|
||||
maxTags={INVITE_USERS_LIMIT}
|
||||
inputProps={{
|
||||
placeholder: ""
|
||||
}}
|
||||
onChange={props.handleChange}
|
||||
/>
|
||||
<HelpBlock>
|
||||
<em>
|
||||
<FormattedMessage id="invite_users.input_help" />
|
||||
</em>
|
||||
</HelpBlock>
|
||||
</FormGroup>
|
||||
);
|
||||
|
||||
InviteUsersForm.propTypes = {
|
||||
tags: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,
|
||||
handleChange: PropTypes.func.isRequired,
|
||||
teamName: PropTypes.string.isRequired
|
||||
tags: arrayOf(string.isRequired).isRequired,
|
||||
handleChange: func.isRequired,
|
||||
teamName: string.isRequired
|
||||
};
|
||||
|
||||
export default InviteUsersForm;
|
||||
|
|
|
@ -1,30 +1,38 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Alert } from 'react-bootstrap';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import React from "react";
|
||||
import { shape, arrayOf, string } from "prop-types";
|
||||
import { Alert } from "react-bootstrap";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
const InviteUsersResults = props =>
|
||||
<div>
|
||||
<h5>
|
||||
<FormattedMessage id="invite_users.results_title" />
|
||||
</h5>
|
||||
<hr />
|
||||
{props.results.invite_results.map(result =>
|
||||
<Alert bsStyle={result.alert} key={result.email}>
|
||||
<strong>{result.email}</strong>
|
||||
-
|
||||
<FormattedMessage id={`invite_users.results_msg.${result.status}`}
|
||||
values={{team: props.results.team_name,
|
||||
role: <FormattedMessage id={`invite_users.roles.${result.user_role}`} />,
|
||||
nr: result.invite_limit
|
||||
}} />
|
||||
</Alert>
|
||||
)}
|
||||
</div>;
|
||||
const InviteUsersResults = props => (
|
||||
<div>
|
||||
<h5>
|
||||
<FormattedMessage id="invite_users.results_title" />
|
||||
</h5>
|
||||
<hr />
|
||||
{props.results.invite_results.map(result => (
|
||||
<Alert bsStyle={result.alert} key={result.email}>
|
||||
<strong>{result.email}</strong>
|
||||
-
|
||||
<FormattedMessage
|
||||
id={`invite_users.results_msg.${result.status}`}
|
||||
values={{
|
||||
team: props.results.team_name,
|
||||
role: (
|
||||
<FormattedMessage id={`invite_users.roles.${result.user_role}`} />
|
||||
),
|
||||
nr: result.invite_limit
|
||||
}}
|
||||
/>
|
||||
</Alert>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
InviteUsersResults.propTypes = {
|
||||
results: PropTypes.object.isRequired
|
||||
results: shape({
|
||||
invite_results: arrayOf.isRequired,
|
||||
team_name: string.isRequired
|
||||
}).isRequired
|
||||
};
|
||||
|
||||
export default InviteUsersResults;
|
||||
|
||||
|
|
|
@ -1,107 +1,115 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Modal, ButtonToolbar, Button } from 'react-bootstrap';
|
||||
import styled from 'styled-components';
|
||||
import axios from '../../config/axios';
|
||||
import React, { Component } from "react";
|
||||
import { bool, func, shape, number, string } from "prop-types";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { Modal, ButtonToolbar, Button } from "react-bootstrap";
|
||||
import styled from "styled-components";
|
||||
import axios from "../../config/axios";
|
||||
|
||||
import { INVITE_USERS_PATH, TEAM_DETAILS_PATH } from '../../config/api_endpoints';
|
||||
import InviteUsersForm from './components/InviteUsersForm';
|
||||
import InviteUsersResults from './components/InviteUsersResults';
|
||||
import InviteUsersButton from './components/InviteUsersButton';
|
||||
import {
|
||||
INVITE_USERS_PATH,
|
||||
TEAM_DETAILS_PATH
|
||||
} from "../../config/api_endpoints";
|
||||
import InviteUsersForm from "./components/InviteUsersForm";
|
||||
import InviteUsersResults from "./components/InviteUsersResults";
|
||||
import InviteUsersButton from "./components/InviteUsersButton";
|
||||
|
||||
const StyledButtonToolbar = styled(ButtonToolbar)`
|
||||
float: right;
|
||||
`;
|
||||
const StyledButtonToolbar = styled(ButtonToolbar)`float: right;`;
|
||||
|
||||
class InviteUsersModal extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
showInviteUsersResults: false,
|
||||
inputTags: [],
|
||||
inviteResults: []
|
||||
};
|
||||
this.handleInputChange = this.handleInputChange.bind(this);
|
||||
this.inviteAs = this.inviteAs.bind(this);
|
||||
this.handleCloseModal = this.handleCloseModal.bind(this)
|
||||
}
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
showInviteUsersResults: false,
|
||||
inputTags: [],
|
||||
inviteResults: []
|
||||
};
|
||||
this.handleInputChange = this.handleInputChange.bind(this);
|
||||
this.inviteAs = this.inviteAs.bind(this);
|
||||
this.handleCloseModal = this.handleCloseModal.bind(this);
|
||||
}
|
||||
|
||||
handleCloseModal() {
|
||||
const path = TEAM_DETAILS_PATH.replace(":team_id", this.props.team.id);
|
||||
this.props.onCloseModal();
|
||||
this.setState({
|
||||
showInviteUsersResults: false,
|
||||
inputTags: [],
|
||||
inviteResults: []
|
||||
});
|
||||
// Update team members table
|
||||
axios.get(path).then(response => {
|
||||
const { users } = response.data.team_details;
|
||||
this.props.updateUsersCallback(users);
|
||||
})
|
||||
}
|
||||
handleCloseModal() {
|
||||
const path = TEAM_DETAILS_PATH.replace(":team_id", this.props.team.id);
|
||||
this.props.onCloseModal();
|
||||
this.setState({
|
||||
showInviteUsersResults: false,
|
||||
inputTags: [],
|
||||
inviteResults: []
|
||||
});
|
||||
// Update team members table
|
||||
axios.get(path).then(response => {
|
||||
const { users } = response.data.team_details;
|
||||
this.props.updateUsersCallback(users);
|
||||
});
|
||||
}
|
||||
|
||||
handleInputChange(inputTags) {
|
||||
this.setState({ inputTags });
|
||||
}
|
||||
handleInputChange(inputTags) {
|
||||
this.setState({ inputTags });
|
||||
}
|
||||
|
||||
inviteAs(role) {
|
||||
axios
|
||||
.put(INVITE_USERS_PATH, {
|
||||
user_role: role,
|
||||
emails: this.state.inputTags,
|
||||
team_id: this.props.team.id
|
||||
})
|
||||
.then(({ data }) => {
|
||||
this.setState({ inviteResults: data });
|
||||
this.setState({ showInviteUsersResults: true });
|
||||
})
|
||||
.catch(error => {});
|
||||
}
|
||||
inviteAs(role) {
|
||||
axios
|
||||
.put(INVITE_USERS_PATH, {
|
||||
user_role: role,
|
||||
emails: this.state.inputTags,
|
||||
team_id: this.props.team.id
|
||||
})
|
||||
.then(({ data }) => {
|
||||
this.setState({ inviteResults: data });
|
||||
this.setState({ showInviteUsersResults: true });
|
||||
})
|
||||
.catch(error => {});
|
||||
}
|
||||
|
||||
render() {
|
||||
let modalBody = null;
|
||||
let inviteButton = null;
|
||||
if (this.state.showInviteUsersResults) {
|
||||
modalBody = <InviteUsersResults results={this.state.inviteResults} />;
|
||||
inviteButton = null;
|
||||
} else {
|
||||
modalBody = <InviteUsersForm tags={this.state.inputTags} handleChange={this.handleInputChange} teamName={this.props.team.name} />;
|
||||
inviteButton = <InviteUsersButton handleClick={this.inviteAs} />;
|
||||
}
|
||||
render() {
|
||||
let modalBody = null;
|
||||
let inviteButton = null;
|
||||
if (this.state.showInviteUsersResults) {
|
||||
modalBody = <InviteUsersResults results={this.state.inviteResults} />;
|
||||
inviteButton = null;
|
||||
} else {
|
||||
modalBody = (
|
||||
<InviteUsersForm
|
||||
tags={this.state.inputTags}
|
||||
handleChange={this.handleInputChange}
|
||||
teamName={this.props.team.name}
|
||||
/>
|
||||
);
|
||||
inviteButton = <InviteUsersButton handleClick={this.inviteAs} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal show={this.props.showModal} onHide={this.handleCloseModal}>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>
|
||||
<FormattedMessage id="invite_users.modal_title" values={{team: this.props.team.name}} />
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
{modalBody}
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<StyledButtonToolbar>
|
||||
<Button onClick={this.handleCloseModal}>
|
||||
<FormattedMessage id="general.cancel" />
|
||||
</Button>
|
||||
{inviteButton}
|
||||
</StyledButtonToolbar>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Modal show={this.props.showModal} onHide={this.handleCloseModal}>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>
|
||||
<FormattedMessage
|
||||
id="invite_users.modal_title"
|
||||
values={{ team: this.props.team.name }}
|
||||
/>
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>{modalBody}</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<StyledButtonToolbar>
|
||||
<Button onClick={this.handleCloseModal}>
|
||||
<FormattedMessage id="general.cancel" />
|
||||
</Button>
|
||||
{inviteButton}
|
||||
</StyledButtonToolbar>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
InviteUsersModal.propTypes = {
|
||||
showModal: PropTypes.bool.isRequired,
|
||||
onCloseModal: PropTypes.func.isRequired,
|
||||
team: PropTypes.shape({
|
||||
id: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
updateUsersCallback: PropTypes.func.isRequired
|
||||
showModal: bool.isRequired,
|
||||
onCloseModal: func.isRequired,
|
||||
team: shape({
|
||||
id: number.isRequired,
|
||||
name: string.isRequired
|
||||
}).isRequired,
|
||||
updateUsersCallback: func.isRequired
|
||||
};
|
||||
|
||||
export default InviteUsersModal;
|
||||
|
|
|
@ -39,7 +39,7 @@ export const CHANGE_USER_RECENT_NOTIFICATION_EMAIL_PATH =
|
|||
"/client_api/users/change_recent_notification_email";
|
||||
export const CHANGE_USER_SYSTEM_MESSAGE_NOTIFICATION_EMAIL_PATH =
|
||||
"/client_api/users/change_system_notification_email";
|
||||
export const INVITE_USERS_PATH = '/client_api/users/invite_users';
|
||||
export const INVITE_USERS_PATH = "/client_api/users/invite_users";
|
||||
|
||||
// info dropdown_title
|
||||
export const CUSTOMER_SUPPORT_LINK = "http://scinote.net/support";
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
export default {
|
||||
'en-US': {
|
||||
"en-US": {
|
||||
general: {
|
||||
close: 'Close',
|
||||
cancel: 'Cancel',
|
||||
update: 'Update',
|
||||
edit: 'Edit',
|
||||
loading: 'Loading ...'
|
||||
close: "Close",
|
||||
cancel: "Cancel",
|
||||
update: "Update",
|
||||
edit: "Edit",
|
||||
loading: "Loading ..."
|
||||
},
|
||||
error_messages: {
|
||||
text_too_short: "is too short (minimum is {min_length} characters)",
|
||||
text_too_long: "is too long (maximum is {max_length} characters)"
|
||||
},
|
||||
navbar: {
|
||||
page_title: 'sciNote',
|
||||
home_label: 'Home',
|
||||
protocols_label: 'Protocols',
|
||||
repositories_label: 'Repositories',
|
||||
activities_label: 'Activities',
|
||||
search_label: 'Search',
|
||||
notifications_label: 'Notifications',
|
||||
info_label: 'Info'
|
||||
page_title: "sciNote",
|
||||
home_label: "Home",
|
||||
protocols_label: "Protocols",
|
||||
repositories_label: "Repositories",
|
||||
activities_label: "Activities",
|
||||
search_label: "Search",
|
||||
notifications_label: "Notifications",
|
||||
info_label: "Info"
|
||||
},
|
||||
settings_page: {
|
||||
all_teams: "All teams",
|
||||
|
@ -54,8 +54,8 @@ export default {
|
|||
"Assignment notifications appear whenever you get assigned to a team, project, task.",
|
||||
recent_changes: "Recent changes",
|
||||
recent_changes_msg:
|
||||
'Recent changes notifications appear whenever there is a change on a task you are assigned to.',
|
||||
system_message: 'System message',
|
||||
"Recent changes notifications appear whenever there is a change on a task you are assigned to.",
|
||||
system_message: "System message",
|
||||
system_message_msg:
|
||||
"System message notifications are specifically sent by site maintainers to notify all users about a system update.",
|
||||
show_in_scinote: "Show in sciNote",
|
||||
|
@ -64,20 +64,28 @@ export default {
|
|||
yes: "Yes",
|
||||
leave_team_modal: {
|
||||
title: "Leave team {teamName}",
|
||||
subtitle: "Are you sure you wish to leave team My projects? This action is irreversible.",
|
||||
subtitle:
|
||||
"Are you sure you wish to leave team My projects? This action is irreversible.",
|
||||
warnings: "Leaving team has following consequences:",
|
||||
warning_message_one: "you will lose access to all content belonging to the team (including projects, tasks, protocols and activities);",
|
||||
warning_message_two: "all projects in the team where you were the sole <b>Owner</b> will receive a new owner from the team administrators;",
|
||||
warning_message_three: "all repository protocols in the team belonging to you will be reassigned onto a new owner from team administrators.",
|
||||
warning_message_one:
|
||||
"you will lose access to all content belonging to the team (including projects, tasks, protocols and activities);",
|
||||
warning_message_two:
|
||||
"all projects in the team where you were the sole <b>Owner</b> will receive a new owner from the team administrators;",
|
||||
warning_message_three:
|
||||
"all repository protocols in the team belonging to you will be reassigned onto a new owner from team administrators.",
|
||||
leave_team: "Leave"
|
||||
},
|
||||
remove_user_modal: {
|
||||
title: "Remove user {user} from team {team}",
|
||||
subtitle: "Are you sure you wish to remove user {user} from team {team}?",
|
||||
subtitle:
|
||||
"Are you sure you wish to remove user {user} from team {team}?",
|
||||
warnings: "Removing user from team has following consequences:",
|
||||
warning_message_one: "user will lose access to all content belonging to the team (including projects, tasks, protocols and activities);",
|
||||
warning_message_two: "all projects in the team where user was the sole <b>Owner</b> will be reassigned onto you as a new owner;",
|
||||
warning_message_three: "all repository protocols in the team belonging to user will be reassigned onto you.",
|
||||
warning_message_one:
|
||||
"user will lose access to all content belonging to the team (including projects, tasks, protocols and activities);",
|
||||
warning_message_two:
|
||||
"all projects in the team where user was the sole <b>Owner</b> will be reassigned onto you as a new owner;",
|
||||
warning_message_three:
|
||||
"all repository protocols in the team belonging to user will be reassigned onto you.",
|
||||
remove_user: "Remove user"
|
||||
},
|
||||
update_team_description_modal: {
|
||||
|
@ -114,61 +122,65 @@ export default {
|
|||
}
|
||||
},
|
||||
activities: {
|
||||
modal_title: 'Activities',
|
||||
no_data: 'No Data',
|
||||
more_activities: 'More Activities'
|
||||
modal_title: "Activities",
|
||||
no_data: "No Data",
|
||||
more_activities: "More Activities"
|
||||
},
|
||||
global_team_switch: {
|
||||
new_team: 'New team'
|
||||
new_team: "New team"
|
||||
},
|
||||
notifications: {
|
||||
dropdown_title: 'Notifications',
|
||||
dropdown_settings_link: 'Settings',
|
||||
dropdown_show_all: 'Show all notifications'
|
||||
dropdown_title: "Notifications",
|
||||
dropdown_settings_link: "Settings",
|
||||
dropdown_show_all: "Show all notifications"
|
||||
},
|
||||
info_dropdown: {
|
||||
customer_support: 'Customer support',
|
||||
tutorials: 'Tutorials',
|
||||
release_notes: 'Release notes',
|
||||
premium: 'Premium',
|
||||
contact_us: 'Contact us'
|
||||
customer_support: "Customer support",
|
||||
tutorials: "Tutorials",
|
||||
release_notes: "Release notes",
|
||||
premium: "Premium",
|
||||
contact_us: "Contact us"
|
||||
},
|
||||
user_account_dropdown: {
|
||||
greeting: 'Hi, {name}',
|
||||
settings: 'Settings',
|
||||
log_out: 'Log out'
|
||||
greeting: "Hi, {name}",
|
||||
settings: "Settings",
|
||||
log_out: "Log out"
|
||||
},
|
||||
invite_users: {
|
||||
modal_title: 'Invite users to team {team}',
|
||||
input_text: 'Invite more people to team {team} and start using sciNote.',
|
||||
input_help: 'Input one or multiple emails, confirm each email with ENTER key.',
|
||||
modal_title: "Invite users to team {team}",
|
||||
input_text: "Invite more people to team {team} and start using sciNote.",
|
||||
input_help:
|
||||
"Input one or multiple emails, confirm each email with ENTER key.",
|
||||
dropdown_button: {
|
||||
invite: 'Invite user/s',
|
||||
guest: 'as Guest/s',
|
||||
normal_user: 'as Normal user/s',
|
||||
admin: 'as Administrator/s'
|
||||
invite: "Invite user/s",
|
||||
guest: "as Guest/s",
|
||||
normal_user: "as Normal user/s",
|
||||
admin: "as Administrator/s"
|
||||
},
|
||||
results_title: 'Invitation results:',
|
||||
results_title: "Invitation results:",
|
||||
roles: {
|
||||
guest: 'Guest',
|
||||
normal_user: 'Normal user',
|
||||
admin: 'Administrator'
|
||||
guest: "Guest",
|
||||
normal_user: "Normal user",
|
||||
admin: "Administrator"
|
||||
},
|
||||
results_msg: {
|
||||
user_exists: 'User is already a member of sciNote.',
|
||||
user_exists: "User is already a member of sciNote.",
|
||||
user_exists_unconfirmed:
|
||||
'User is already a member of sciNote but is not confirmed yet.',
|
||||
"User is already a member of sciNote but is not confirmed yet.",
|
||||
user_exists_and_in_team_unconfirmed:
|
||||
'User is already a member of sciNote and team {team} as {role} but is not confirmed yet.',
|
||||
"User is already a member of sciNote and team {team} as {role} but is not confirmed yet.",
|
||||
user_exists_invited_to_team_unconfirmed:
|
||||
'User is already a member of sciNote but is not confirmed yet - successfully invited to team {team} as {role}.',
|
||||
user_exists_and_in_team: 'User is already a member of sciNote and team {team} as {role}.',
|
||||
"User is already a member of sciNote but is not confirmed yet - successfully invited to team {team} as {role}.",
|
||||
user_exists_and_in_team:
|
||||
"User is already a member of sciNote and team {team} as {role}.",
|
||||
user_exists_invited_to_team:
|
||||
'User was already a member of sciNote - successfully invited to team {team} as {role}.',
|
||||
user_created: 'User succesfully invited to sciNote.',
|
||||
user_created_invited_to_team: 'User successfully invited to sciNote and team {team} as {role}.',
|
||||
user_invalid: 'Invalid email.',
|
||||
too_many_emails: 'Only invited first {nr} emails. To invite more users, fill in another invitation form.'
|
||||
"User was already a member of sciNote - successfully invited to team {team} as {role}.",
|
||||
user_created: "User succesfully invited to sciNote.",
|
||||
user_created_invited_to_team:
|
||||
"User successfully invited to sciNote and team {team} as {role}.",
|
||||
user_invalid: "Invalid email.",
|
||||
too_many_emails:
|
||||
"Only invited first {nr} emails. To invite more users, fill in another invitation form."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
import { FormattedMessage } from "react-intl";
|
||||
import axios from "../../../../../config/axios";
|
||||
|
||||
import InviteUsersModal from '../../../../../components/InviteUsersModal';
|
||||
import InviteUsersModal from "../../../../../components/InviteUsersModal";
|
||||
import RemoveUserModal from "./RemoveUserModal";
|
||||
import DataTable from "../../../../../components/data_table";
|
||||
import { UPDATE_USER_TEAM_ROLE_PATH } from "../../../../../config/api_endpoints";
|
||||
|
@ -30,8 +30,12 @@ class TeamsMembers extends Component {
|
|||
userToRemove: initalUserToRemove
|
||||
};
|
||||
this.memberAction = this.memberAction.bind(this);
|
||||
this.showInviteUsersModalCallback = this.showInviteUsersModalCallback.bind(this);
|
||||
this.closeInviteUsersModalCallback = this.closeInviteUsersModalCallback.bind(this);
|
||||
this.showInviteUsersModalCallback = this.showInviteUsersModalCallback.bind(
|
||||
this
|
||||
);
|
||||
this.closeInviteUsersModalCallback = this.closeInviteUsersModalCallback.bind(
|
||||
this
|
||||
);
|
||||
this.hideModal = this.hideModal.bind(this);
|
||||
}
|
||||
|
||||
|
@ -184,7 +188,7 @@ class TeamsMembers extends Component {
|
|||
<FormattedMessage id="settings_page.single_team.members_panel_title" />
|
||||
}
|
||||
>
|
||||
<Button bsStyle='primary' onClick={this.showInviteUsersModalCallback}>
|
||||
<Button bsStyle="primary" onClick={this.showInviteUsersModalCallback}>
|
||||
<Glyphicon glyph="plus" />
|
||||
<FormattedMessage id="settings_page.single_team.add_members" />
|
||||
</Button>
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
@import 'constants';
|
||||
@import 'react-bootstrap-timezone-picker/dist/react-bootstrap-timezone-picker.min.css';
|
||||
@import '~react-bootstrap-table/dist/react-bootstrap-table.min';
|
||||
@import 'react-tagsinput/react-tagsinput.css';
|
||||
@import "constants";
|
||||
@import "react-bootstrap-timezone-picker/dist/react-bootstrap-timezone-picker.min.css";
|
||||
@import "~react-bootstrap-table/dist/react-bootstrap-table.min";
|
||||
@import "react-tagsinput/react-tagsinput.css";
|
||||
|
||||
body {
|
||||
background-color: $color-concrete;
|
||||
color: $color-emperor;
|
||||
font-family: "Open Sans", Arial, Helvetica, sans-serif;
|
||||
font-size: 13px;
|
||||
background-color: $color-concrete;
|
||||
color: $color-emperor;
|
||||
font-family: "Open Sans", Arial, Helvetica, sans-serif;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.label-primary {
|
||||
background-color: $color-theme-primary;
|
||||
background-color: $color-theme-primary;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: $color-theme-secondary;
|
||||
border-color: $primary-hover-color;
|
||||
margin-right: 7px;
|
||||
&:hover {
|
||||
background-color: $primary-hover-color;
|
||||
}
|
||||
background-color: $color-theme-secondary;
|
||||
border-color: $primary-hover-color;
|
||||
margin-right: 7px;
|
||||
&:hover {
|
||||
background-color: $primary-hover-color;
|
||||
}
|
||||
}
|
||||
|
||||
// // fixes issue with dropdown in datatable
|
||||
|
|
|
@ -11,12 +11,14 @@ module ClientApi
|
|||
|
||||
raise ClientApi::CustomInvitationsError unless @emails && @team && @role
|
||||
@emails && @emails.empty? { raise ClientApi::CustomInvitationsError }
|
||||
@role && !UserTeam.roles.keys.include?(@role) { raise ClientApi::CustomInvitationsError }
|
||||
if @role && !UserTeam.roles.keys.include?(@role)
|
||||
raise ClientApi::CustomInvitationsError
|
||||
end
|
||||
end
|
||||
|
||||
def invitation
|
||||
invite_results = []
|
||||
|
||||
|
||||
@emails.each_with_index do |email, index|
|
||||
result = {}
|
||||
# Check invite users limit
|
||||
|
@ -33,52 +35,13 @@ module ClientApi
|
|||
# Check if user already exists
|
||||
user = User.find_by_email(email) if User.exists?(email: email)
|
||||
|
||||
# User does not exist
|
||||
if user.blank?
|
||||
password = generate_user_password
|
||||
# Validate the user data
|
||||
error = !(Constants::BASIC_EMAIL_REGEX === email)
|
||||
error = validate_user(email, email, password).count > 0 unless error
|
||||
|
||||
if !error
|
||||
user = invite_new_user(email)
|
||||
|
||||
result[:status] = :user_created
|
||||
result[:alert] = :success
|
||||
result[:user] = user
|
||||
|
||||
# Invitation to team
|
||||
if @team.present?
|
||||
user_team = create_user_team_relation_and_notification(user)
|
||||
result[:status] = :user_created_invited_to_team
|
||||
result[:user_team] = user_team
|
||||
end
|
||||
else
|
||||
# Return invalid status
|
||||
result[:status] = :user_invalid
|
||||
result[:alert] = :danger
|
||||
end
|
||||
# User exists
|
||||
else
|
||||
result[:status] = :"#{:user_exists}#{:_unconfirmed if !user.confirmed?}"
|
||||
result[:alert] = :info
|
||||
result[:user] = user
|
||||
|
||||
# Invitation to team
|
||||
if @team.present?
|
||||
user_team =
|
||||
UserTeam.where(user: user, team: @team).first if UserTeam.exists?(user: user, team: @team)
|
||||
|
||||
if user_team.present?
|
||||
result[:status] = :"#{:user_exists_and_in_team}#{:_unconfirmed if !user.confirmed?}"
|
||||
|
||||
else
|
||||
user_team = create_user_team_relation_and_notification(user)
|
||||
result[:status] = :"#{:user_exists_invited_to_team}#{:_unconfirmed if !user.confirmed?}"
|
||||
end
|
||||
result[:user_team] = user_team
|
||||
end
|
||||
end
|
||||
result = if user.blank?
|
||||
# User does not exist
|
||||
handle_new_user(result, email, user)
|
||||
else
|
||||
# User exists
|
||||
handle_existing_user(result, user)
|
||||
end
|
||||
invite_results << result
|
||||
end
|
||||
invite_results
|
||||
|
@ -86,6 +49,61 @@ module ClientApi
|
|||
|
||||
private
|
||||
|
||||
def handle_new_user(result, email, user)
|
||||
password = generate_user_password
|
||||
# Validate the user data
|
||||
error = (Constants::BASIC_EMAIL_REGEX !~ email)
|
||||
error = validate_user(email, email, password).count > 0 unless error
|
||||
|
||||
if !error
|
||||
# Invite new user
|
||||
user = invite_new_user(email)
|
||||
|
||||
result[:status] = :user_created
|
||||
result[:alert] = :success
|
||||
result[:user] = user
|
||||
|
||||
# Invitation to team
|
||||
if @team.present?
|
||||
user_team = create_user_team_relation_and_notification(user)
|
||||
result[:status] = :user_created_invited_to_team
|
||||
result[:user_team] = user_team
|
||||
end
|
||||
else
|
||||
# Return invalid status
|
||||
result[:status] = :user_invalid
|
||||
result[:alert] = :danger
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def handle_existing_user(result, user)
|
||||
result[:status] =
|
||||
:"#{:user_exists}#{:_unconfirmed unless user.confirmed?}"
|
||||
result[:alert] = :info
|
||||
result[:user] = user
|
||||
|
||||
# Invitation to team
|
||||
if @team.present?
|
||||
if UserTeam.exists?(user: user, team: @team)
|
||||
user_team = UserTeam.where(user: user, team: @team).first
|
||||
end
|
||||
|
||||
if user_team.present?
|
||||
result[:status] =
|
||||
:"#{:user_exists_and_in_team}#{:_unconfirmed unless user
|
||||
.confirmed?}"
|
||||
else
|
||||
user_team = create_user_team_relation_and_notification(user)
|
||||
result[:status] =
|
||||
:"#{:user_exists_invited_to_team}#{:_unconfirmed unless user
|
||||
.confirmed?}"
|
||||
end
|
||||
result[:user_team] = user_team
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def invite_new_user(email)
|
||||
user = User.invite!(
|
||||
full_name: email,
|
||||
|
@ -140,4 +158,4 @@ module ClientApi
|
|||
end
|
||||
|
||||
CustomInvitationsError = Class.new(StandardError)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,11 @@ json.invite_results invite_results do |invite_result|
|
|||
json.status invite_result[:status]
|
||||
json.alert invite_result[:alert]
|
||||
json.email invite_result[:email]
|
||||
json.user_role invite_result[:user_team].role if invite_result[:user_team].present?
|
||||
json.invite_limit invite_result[:invite_user_limit] if invite_result[:invite_user_limit].present?
|
||||
if invite_result[:user_team].present?
|
||||
json.user_role invite_result[:user_team].role
|
||||
end
|
||||
if invite_result[:invite_user_limit].present?
|
||||
json.invite_limit invite_result[:invite_user_limit]
|
||||
end
|
||||
end
|
||||
json.team_name team.name if team.present?
|
||||
json.team_name team.name if team.present?
|
||||
|
|
|
@ -83,7 +83,8 @@
|
|||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="col-xs-24 col-sm-12">
|
||||
<a href="#" class="btn btn-primary pull-right row" data-trigger="invite-users" data-turbolinks="false" data-modal-id="team-invite-users-modal">
|
||||
<a href="#" class="btn btn-primary pull-right row" data-trigger="invite-users"
|
||||
data-turbolinks="false" data-modal-id="team-invite-users-modal">
|
||||
<span class="glyphicon glyphicon-plus"></span>
|
||||
<%= t("users.settings.teams.edit.add_user") %>
|
||||
</a>
|
||||
|
|
Loading…
Add table
Reference in a new issue