optimize detail pages, add new permission for comment posting (#1432)

This commit is contained in:
Kevin Papst
2020-02-02 18:16:23 +01:00
committed by GitHub
parent 6a533579b7
commit 69cf7015d8
12 changed files with 95 additions and 81 deletions

View File

@@ -8,6 +8,16 @@ you can upgrade your Kimai installation to the latest stable release.
Check below if there are more version specific steps required, which need to be executed after the normal update process.
Perform EACH version specific task between your version and the new one, otherwise you risk data inconsistency or a broken installation.
## [1.8](https://github.com/kevinpapst/kimai2/releases/tag/1.8)
New permissions:
- `comments_create_customer` - NEW: permission that allows to add new comments for customers
- `comments_create_team_customer` - NEW: permission that allows to add new comments for team members of the current customer
- `comments_create_teamlead_customer` - NEW: permission that allows to add new comments for a teamlead of the current customer
- `edit_teamlead_project` - removed default permission from ROLE_TEAMLEAD (if you use it: change it in the Role & Permission UI)
- `edit_teamlead_customer` - removed default permission from ROLE_TEAMLEAD (if you use it: change it in the Role & Permission UI)
## [1.7](https://github.com/kevinpapst/kimai2/releases/tag/1.7)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**

View File

@@ -87,14 +87,14 @@ kimai:
sets:
ACTIVITIES: ['view_activity','create_activity','edit_activity','budget_activity','delete_activity']
ACTIVITIES_TEAMLEAD: ['view_activity','create_activity','edit_teamlead_activity','budget_teamlead_activity']
PROJECTS: ['view_project','create_project','edit_project','budget_project','delete_project','permissions_project','comments_project','details_project']
PROJECTS_ALL_TEAMLEAD: ['view_teamlead_project','edit_teamlead_project','budget_teamlead_project','permissions_teamlead_project','comments_teamlead_project','details_teamlead_project']
PROJECTS_ALL_TEAM: ['view_team_project','edit_team_project','budget_team_project','comments_team_project','details_team_project']
PROJECTS_TEAMLEAD: ['view_teamlead_project','edit_teamlead_project','budget_teamlead_project','comments_teamlead_project','details_teamlead_project']
CUSTOMERS: ['view_customer','create_customer','edit_customer','budget_customer','delete_customer','permissions_customer','comments_customer','details_customer']
CUSTOMERS_ALL_TEAMLEAD: ['view_teamlead_customer','edit_teamlead_customer','budget_teamlead_customer','permissions_teamlead_customer','comments_teamlead_customer','details_teamlead_customer']
CUSTOMERS_ALL_TEAM: ['view_team_customer','edit_team_customer','budget_team_customer','comments_team_customer','details_team_customer']
CUSTOMERS_TEAMLEAD: ['view_teamlead_customer','edit_teamlead_customer','budget_teamlead_customer','comments_teamlead_customer','details_teamlead_customer']
PROJECTS: ['view_project','create_project','edit_project','budget_project','delete_project','permissions_project','comments_project','comments_create_project','details_project']
PROJECTS_ALL_TEAMLEAD: ['view_teamlead_project','edit_teamlead_project','budget_teamlead_project','permissions_teamlead_project','comments_teamlead_project','comments_create_teamlead_project','details_teamlead_project']
PROJECTS_ALL_TEAM: ['view_team_project','edit_team_project','budget_team_project','comments_team_project','comments_create_team_project','details_team_project']
PROJECTS_TEAMLEAD: ['view_teamlead_project','budget_teamlead_project','comments_teamlead_project','comments_create_teamlead_project','details_teamlead_project']
CUSTOMERS: ['view_customer','create_customer','edit_customer','budget_customer','delete_customer','permissions_customer','comments_customer','comments_create_customer','details_customer']
CUSTOMERS_ALL_TEAMLEAD: ['view_teamlead_customer','edit_teamlead_customer','budget_teamlead_customer','permissions_teamlead_customer','comments_teamlead_customer','comments_create_teamlead_customer','details_teamlead_customer']
CUSTOMERS_ALL_TEAM: ['view_team_customer','edit_team_customer','budget_team_customer','comments_team_customer','comments_create_team_customer','details_team_customer']
CUSTOMERS_TEAMLEAD: ['view_teamlead_customer','budget_teamlead_customer','comments_teamlead_customer','comments_create_teamlead_customer','details_teamlead_customer']
INVOICE: ['view_invoice','create_invoice']
INVOICE_TEMPLATE: ['manage_invoice_template']
TIMESHEET: ['view_own_timesheet','start_own_timesheet','stop_own_timesheet','create_own_timesheet','edit_own_timesheet','export_own_timesheet','delete_own_timesheet']

View File

@@ -168,7 +168,7 @@ final class CustomerController extends AbstractController
/**
* @Route(path="/{id}/comment_add", name="customer_comment_add", methods={"POST"})
* @Security("is_granted('edit', customer) and is_granted('comments', customer)")
* @Security("is_granted('comments_create', customer)")
*/
public function addCommentAction(Customer $customer, Request $request)
{
@@ -271,12 +271,8 @@ final class CustomerController extends AbstractController
$teams = null;
$projects = null;
if ($this->isGranted('edit', $customer)) {
$commentForm = $this->getCommentForm($customer, new CustomerComment())->createView();
if ($this->isGranted('create_team')) {
$defaultTeam = $teamRepository->findOneBy(['name' => $customer->getName()]);
}
if ($this->isGranted('edit', $customer) && $this->isGranted('create_team')) {
$defaultTeam = $teamRepository->findOneBy(['name' => $customer->getName()]);
}
if (null !== $customer->getTimezone()) {
@@ -291,6 +287,10 @@ final class CustomerController extends AbstractController
$comments = $this->repository->getComments($customer);
}
if ($this->isGranted('comments_create', $customer)) {
$commentForm = $this->getCommentForm($customer, new CustomerComment())->createView();
}
if ($this->isGranted('permissions', $customer) || $this->isGranted('details', $customer) || $this->isGranted('view_team')) {
$teams = $customer->getTeams();
}

View File

@@ -171,7 +171,7 @@ final class ProjectController extends AbstractController
/**
* @Route(path="/{id}/comment_add", name="project_comment_add", methods={"POST"})
* @Security("is_granted('edit', project) and is_granted('comments', project)")
* @Security("is_granted('comments_create', project)")
*/
public function addCommentAction(Project $project, Request $request)
{
@@ -273,12 +273,8 @@ final class ProjectController extends AbstractController
$comments = null;
$teams = null;
if ($this->isGranted('edit', $project)) {
$commentForm = $this->getCommentForm($project, new ProjectComment())->createView();
if ($this->isGranted('create_team')) {
$defaultTeam = $teamRepository->findOneBy(['name' => $project->getName()]);
}
if ($this->isGranted('edit', $project) && $this->isGranted('create_team')) {
$defaultTeam = $teamRepository->findOneBy(['name' => $project->getName()]);
}
if ($this->isGranted('budget', $project)) {
@@ -289,6 +285,10 @@ final class ProjectController extends AbstractController
$comments = $this->repository->getComments($project);
}
if ($this->isGranted('comments_create', $project)) {
$commentForm = $this->getCommentForm($project, new ProjectComment())->createView();
}
if ($this->isGranted('permissions', $project) || $this->isGranted('details', $project) || $this->isGranted('view_team')) {
$teams = $project->getTeams();
}

View File

@@ -30,6 +30,7 @@ class CustomerVoter extends AbstractVoter
'delete',
'permissions',
'comments',
'comments_create',
'details',
];

View File

@@ -29,6 +29,7 @@ class ProjectVoter extends AbstractVoter
'delete',
'permissions',
'comments',
'comments_create',
'details',
];

View File

@@ -107,35 +107,35 @@
<td>{{ customer.vatId }}</td>
</tr>
{% endif %}
{% if can_edit %}
<tr>
<th>{{ 'label.fixedRate'|trans }}</th>
<td>
{% if customer.fixedRate is not empty %}
{{ customer.fixedRate|money(customer.currency) }}
{% else %}
&ndash;
{% endif %}
</td>
</tr>
<tr>
<th>{{ 'label.hourlyRate'|trans }}</th>
<td>
{% if customer.hourlyRate is not empty %}
{{ customer.hourlyRate|money(customer.currency) }}
{% else %}
&ndash;
{% endif %}
</td>
</tr>
{% endif %}
{% for metaField in customer.visibleMetaFields %}
<tr>
<th>{{ metaField.label }}</th>
<td>{{ widgets.form_type_value(metaField.type, metaField.value, customer) }}</td>
</tr>
{% endfor %}
{% endif %}
{% if can_edit %}
<tr>
<th>{{ 'label.fixedRate'|trans }}</th>
<td>
{% if customer.fixedRate is not empty %}
{{ customer.fixedRate|money(customer.currency) }}
{% else %}
&ndash;
{% endif %}
</td>
</tr>
<tr>
<th>{{ 'label.hourlyRate'|trans }}</th>
<td>
{% if customer.hourlyRate is not empty %}
{{ customer.hourlyRate|money(customer.currency) }}
{% else %}
&ndash;
{% endif %}
</td>
</tr>
{% endif %}
{% for metaField in customer.visibleMetaFields %}
<tr>
<th>{{ metaField.label }}</th>
<td>{{ widgets.form_type_value(metaField.type, metaField.value, customer) }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
{% endembed %}

View File

@@ -44,7 +44,7 @@
{{ tables.datatable_header(tableName, columns, query, {'reload': 'kimai.customerUpdate kimai.customerTeamUpdate'}) }}
{% for entry in entries %}
<tr class="alternative-link open-edit" data-href="{{ path('customer_details', {'id': entry.id}) }}">
<tr{% if is_granted('view', entry) %} class="alternative-link open-edit" data-href="{{ path('customer_details', {'id': entry.id}) }}"{% endif %}>
<td>
{{ widgets.label_color_dot('customer', true, entry.name, null, entry.color) }}
</td>

View File

@@ -20,6 +20,8 @@
<span class="text-muted pull-right">
{% if route_pin is not null %}
<a href="{{ path(route_pin, {'id': comment.id}) }}" class="btn btn-default btn-xs {% if comment.pinned %}active{% endif %}"><i class="{{ 'pin'|icon }}"></i></a>
{% elseif comment.pinned %}
<i class="{{ 'pin'|icon }}"></i>
{% endif %}
{% if route_delete is not null %}
<a href="{{ path(route_delete, {'id': comment.id}) }}" class="confirmation-link btn btn-default btn-xs" data-question="confirm.delete"><i class="{{ 'delete'|icon }}"></i></a>

View File

@@ -81,35 +81,35 @@
{% endif %}
</td>
</tr>
{% if can_edit %}
<tr>
<th>{{ 'label.fixedRate'|trans }}</th>
<td>
{% if project.fixedRate is not empty %}
{{ project.fixedRate|money(project.customer.currency) }}
{% else %}
&ndash;
{% endif %}
</td>
</tr>
<tr>
<th>{{ 'label.hourlyRate'|trans }}</th>
<td>
{% if project.hourlyRate is not empty %}
{{ project.hourlyRate|money(project.customer.currency) }}
{% else %}
&ndash;
{% endif %}
</td>
</tr>
{% endif %}
{% for metaField in project.visibleMetaFields %}
<tr>
<th>{{ metaField.label }}</th>
<td>{{ widgets.form_type_value(metaField.type, metaField.value, project) }}</td>
</tr>
{% endfor %}
{% endif %}
{% if can_edit %}
<tr>
<th>{{ 'label.fixedRate'|trans }}</th>
<td>
{% if project.fixedRate is not empty %}
{{ project.fixedRate|money(project.customer.currency) }}
{% else %}
&ndash;
{% endif %}
</td>
</tr>
<tr>
<th>{{ 'label.hourlyRate'|trans }}</th>
<td>
{% if project.hourlyRate is not empty %}
{{ project.hourlyRate|money(project.customer.currency) }}
{% else %}
&ndash;
{% endif %}
</td>
</tr>
{% endif %}
{% for metaField in project.visibleMetaFields %}
<tr>
<th>{{ metaField.label }}</th>
<td>{{ widgets.form_type_value(metaField.type, metaField.value, project) }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
{% endembed %}

View File

@@ -45,7 +45,7 @@
{{ tables.datatable_header(tableName, columns, query, {'reload': 'kimai.projectUpdate kimai.projectTeamUpdate'}) }}
{% for entry in entries %}
<tr class="alternative-link open-edit" data-href="{{ path('project_details', {'id': entry.id}) }}">
<tr{% if is_granted('view', entry) %} class="alternative-link open-edit" data-href="{{ path('project_details', {'id': entry.id}) }}"{% endif %}>
<td>{{ widgets.label_color_dot('project', true, entry.name, null, entry.color) }}</td>
<td class="{{ tables.data_table_column_class(tableName, columns, 'customer') }}">
{{ widgets.label_customer(entry.customer) }}

View File

@@ -29,7 +29,7 @@ class PermissionControllerTest extends ControllerBaseTest
$client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN);
$this->assertAccessIsGranted($client, '/admin/permissions');
$this->assertHasDataTable($client);
$this->assertDataTableRowCount($client, 'datatable_user_admin_permissions', 101);
$this->assertDataTableRowCount($client, 'datatable_user_admin_permissions', 107);
$this->assertPageActions($client, [
'back' => $this->createUrl('/admin/user/'),
'roles modal-ajax-form' => $this->createUrl('/admin/permissions/roles/create'),