diff --git a/app/controllers/client_api/permissions_controller.rb b/app/controllers/client_api/permissions_controller.rb
index 807f36a27..4d893211b 100644
--- a/app/controllers/client_api/permissions_controller.rb
+++ b/app/controllers/client_api/permissions_controller.rb
@@ -15,28 +15,34 @@ module ClientApi
def generate_permissions_object
sanitize_permissions!
@permissions = {}
- if @resource
- @required_permissions.collect do |permission|
- @permissions.merge!("#{permission}?" => @holder.eval(permission,
- current_user,
- @resource))
- end
- else
- @required_permissions.collect do |permission|
+ obj = @resource.fetch(:type)
+ .constantize
+ .public_send(:find_by_id, @resource.fetch(:id) {
+ raise ArgumentError, 'ID must be present'
+ }) if @resource
+ @required_permissions.collect do |permission|
+ parsed_permision = permission.gsub('can_', '')
+ if @resource
+ # return false if object does not exist
+ result = obj ? @holder.eval('read_team', current_user, obj) : false
+ @permissions.merge!(permission => result)
+ else
@permissions.merge!(
- "#{permission}?" => @holder.eval_generic(permission, current_user)
+ permission => @holder.eval_generic(
+ parsed_permision, current_user
+ )
)
end
end
end
def sanitize_permissions!
- @required_permissions = params.fetch(:parsePermission) do
+ @required_permissions = params.fetch(:requiredPermissions) do
:permissions_array_missing
end
@holder = Canaid::PermissionsHolder.instance
@required_permissions.each do |permission|
- next if @holder.has_permission?(permission)
+ next if @holder.has_permission?(permission.gsub('can_', ''))
# this error should happen only in development
raise ArgumentError, "Method #{permission} has no related " \
"permission registered."
@@ -49,7 +55,7 @@ module ClientApi
def resource_valid?
@resource = params[:resource]
return true unless @resource
- return true if Object.const_get(@resource.classify)
+ return true if Object.const_get(@resource.fetch(:type).classify)
rescue NameError
return false
end
diff --git a/app/javascript/src/scenes/SettingsPage/scenes/teams/components/TeamsPageDetails.jsx b/app/javascript/src/scenes/SettingsPage/scenes/teams/components/TeamsPageDetails.jsx
index 1d946b66e..168542018 100644
--- a/app/javascript/src/scenes/SettingsPage/scenes/teams/components/TeamsPageDetails.jsx
+++ b/app/javascript/src/scenes/SettingsPage/scenes/teams/components/TeamsPageDetails.jsx
@@ -5,10 +5,18 @@ import styled from "styled-components";
import { FormattedMessage, FormattedPlural } from "react-intl";
import { Button, Glyphicon } from "react-bootstrap";
import { SETTINGS_NEW_TEAM_ROUTE } from "../../../../../config/routes";
+import * as Permissions from "../../../../../services/permissions"
const Wrapper = styled.div`margin: 15px 0;`;
-const TeamsPageDetails = ({ teams }) => {
+const TeamsPageDetails = ({ teams, permissions }) => {
const teamsNumber = teams.length;
+ const newTeamButton = (
+
+
+
+ )
return (
{
/>
}
/>
-
-
-
+ {permissions.can_create_teams ? newTeamButton : ''}
);
};
@@ -53,7 +57,8 @@ TeamsPageDetails.propTypes = {
};
TeamsPageDetails.defaultProps = {
- teams: []
+ teams: [],
+ permissions: {}
};
-export default TeamsPageDetails;
+export default Permissions.connect(TeamsPageDetails, ["can_create_teams"]);
diff --git a/app/javascript/src/services/api/permissions_api.js b/app/javascript/src/services/api/permissions_api.js
index cdfd776f9..3305a6078 100644
--- a/app/javascript/src/services/api/permissions_api.js
+++ b/app/javascript/src/services/api/permissions_api.js
@@ -7,10 +7,9 @@ export const getPermissionStatus = (
requiredPermissions: Array,
resource: string
): Promise<*> => {
- const parsePermission = requiredPermissions.map(el => el.replace("?", ""));
return axiosInstance
.post(PERMISSIONS_PATH, {
- parsePermission,
+ requiredPermissions,
resource
})
.then(({ data }) => data);
diff --git a/app/javascript/src/services/permissions/index.js b/app/javascript/src/services/permissions/index.js
index 49bfd7c70..667e2c66a 100644
--- a/app/javascript/src/services/permissions/index.js
+++ b/app/javascript/src/services/permissions/index.js
@@ -7,14 +7,48 @@
Than you use the Permissions.connect method to wrap your component and
pass this "permissions helper methods" in your component params:
+ If you need to specific model you have to specify it in the connect method
+ like the example below
>
- > Permissions.connect(MyComponent, ["can_update_team?", "can_read_team?"], "Team");
+ > Permissions.connect(MyComponent, ["can_update_team", "can_read_team"], "Team");
>
+ In case your component is connected to Redux or some other HOC you can simply
+ chain the HOC's
+ >
+ > const mapStateToProps = ({ current_team }) => ({ current_team });
+ > const MyComponentWithPermissions = Permissions.connect(MyComponent, ["can_read_team"], "Team");
+ > export default connect(mapStateToProps)(MyComponentWithPermissions);
+ >
+ beside the permissions object you get the setPermissionResourceId/1 function
+ in your component props. Than you can pass the id of the resource when you have it.
+
+ Example: you need the current team for whatever reason you can call it in the
+ shouldComponentUpdate function...
+
+ > shouldComponentUpdate(nextProps: any, nextState: any) {
+ > this.props.setPermissionResourceId(this.props.current_team.id);
+ > return true; // remember to return true!
+ > }
+
+ JUST REMEMBER THAT YOU HAVE PASS A VALID ID and you have to check if is present
+ at the moment of execution. THE REQUEST WILL BE TRIGGERED WHEN YOU INVOKE
+ setPermissionResourceId/1 FUNCTION!!!!
+
+ else you can pass just the perrmissions on the user
+ >
+ > Permissions.connect(MyComponent, ["can_update"])
+ >
+ THE REQUEST WILL BE TRIGGERED WHEN THE COMPONENT MOUNTS!!!
+
Now you can access your permissions through component params. The permissions
you required have 3 states [true, false, null]. Null is when you are waiting for server response.
- You can use methods params.can_update_team? or whatever permissions you declare
+
+ Finally you can access to your permissions in the component using
+ props.permissions.can_.... whatever you specify. The props.permissions is
+ basically an object that holds all required permissions.
*/
+
import * as React from "react";
import { getPermissionStatus } from "../api/permissions_api";
@@ -22,15 +56,20 @@ type State = {
permissions: any
};
+type ResourceObject = {
+ type: string,
+ id: number
+};
+
type PermissionsObject = {
[string]: boolean | null
-}
+};
/*
This function accepts 3 arguments which are REQUIRED
- 1.) WrappedComponent: Component that you want to have permissions
- 2.) requiredPermissions: an array of strings with permissions methods that
+ 1.) @WrappedComponent: Component that you want to have permissions
+ 2.) @requiredPermissions: an array of strings with permissions methods that
will be available in your component
- 3.) resource: a string of reference/model name
+ 3.) @resource: a string of reference/model name
*/
export function connect(
WrappedComponent: React.ComponentType,
@@ -41,31 +80,55 @@ export function connect(
requiredPermissions.forEach(el => {
parsedPermissions[el] = null;
});
-
return class extends React.Component<*, State> {
constructor(props: any) {
super(props);
- this.state = { permissions: parsedPermissions };
+ this.state = {
+ permissions: parsedPermissions,
+ permissionsRequestDone: false
+ };
+ (this: any).getPermissions = this.getPermissions.bind(this);
+ (this: any).setPermissionResourceId = this.setPermissionResourceId.bind(
+ this
+ );
}
componentDidMount(): void {
- getPermissionStatus(requiredPermissions, resource)
- .then(data => {
- this.setState({ permissions: data });
- })
- .catch(() => {
- const permissions: PermissionsObject = {};
- requiredPermissions.forEach(el => {
- permissions[el] = false;
+ if (!resource) {
+ this.getPermissions(requiredPermissions, resource);
+ }
+ }
+
+ setPermissionResourceId(id: number): void {
+ this.getPermissions(requiredPermissions, { type: resource, id });
+ }
+
+ getPermissions(
+ permissionsArray: Array,
+ resourceObject: ResourceObject | undefined
+ ): void {
+ if (!this.state.permissionsRequestDone) {
+ getPermissionStatus(permissionsArray, resourceObject)
+ .then(data => {
+ this.setState({ permissions: data, permissionsRequestDone: true });
+ })
+ .catch(() => {
+ const permissions: PermissionsObject = {};
+ permissionsArray.forEach(el => {
+ permissions[el] = false;
+ });
+ this.setState({ permissions });
});
- this.setState({ permissions });
- });
+ }
}
render(): any {
return (
);
diff --git a/spec/controllers/client_api/permissions_controller_spec.rb b/spec/controllers/client_api/permissions_controller_spec.rb
index 8d7698a77..710ded152 100644
--- a/spec/controllers/client_api/permissions_controller_spec.rb
+++ b/spec/controllers/client_api/permissions_controller_spec.rb
@@ -4,10 +4,20 @@ describe ClientApi::PermissionsController, type: :controller do
login_user
describe '#status' do
+ let!(:user) { User.first || create(:user) }
+ let!(:team) { create :team, created_by: user }
+ let!(:user_team) { create :user_team, user: user, team: team, role: 2 }
let(:params) do
- { parsePermission: ['can_view_team'], resource: 'UserTeam' }
+ { requiredPermissions: ['can_read_team'],
+ resource: { type: 'Team', id: team.id } }
end
+
let(:subject) { post :status, format: :json, params: params }
it { is_expected.to be_success }
+
+ it 'returns an object with the permission' do
+ body = JSON.parse(subject.body)
+ expect(body).to eq('can_read_team' => true)
+ end
end
end